游戏开发论坛

 找回密码
 立即注册
搜索
查看: 3328|回复: 3

改写例子Demo_Crowd原定踏步的机器人成向前走出现的问题。

[复制链接]

18

主题

78

帖子

165

积分

注册会员

Rank: 2

积分
165
发表于 2007-12-18 15:21:00 | 显示全部楼层 |阅读模式
我改了一个例子,就是Demo_Crowd.exe我让那一堆在山坡上原定踏步的机器人,改成向前走。
但是发现用例子里面的所使用的保持在地面上的方法,在上坡的地方就走不动了。变成原地走了。为什么?

源码如下,要放在OGRE的目录里面,这样就不用设置了。比如:E:\OgreSDK\MyOGREPrj\ExampleOGRE\ExampleOGRE.sln



#include "ExampleApplication.h"

// Event handler to add ability to alter curvature
class MyOGREFrameListener : public ExampleFrameListener
{

protected:
        size_t numMesh;//机器人网格数量
        size_t objectCount;//机器人物体数量
        size_t numRender;//渲染的实体序列标号
       
        //可移动的3D物体,AnimationState可动画状态
        std::vector <Entity *>                        renderEntity;//实体队列集合区别于批处理机器人
        std::vector <AnimationState*> animations;
        //c场景节点
        std::vector <SceneNode *>                        nodes; //实体队列集合方法所使用的
public:
        MyOGREFrameListener(RenderWindow* win, Camera* cam)
                : ExampleFrameListener(win, cam)
        {
                numMesh =70;//机器人网格数量
                createEntityGeom();
        }
        //-----------------------------------------------------------------------
        MyOGREFrameListener::~MyOGREFrameListener()
        {
                destroyEntityGeom();
        }
        //-----------------------------------------------------------------------
        //-----------------------------------------------------------------------
        bool frameStarted(const FrameEvent& evt)
        {
                std::vector <AnimationState*>::iterator it;
                for(it=animations.begin();it!=animations.end();it++)
                {
                        (*it)->addTime(evt.timeSinceLastFrame);
                }

                //create a RayQuery to get the terrain height
                //创建一个RayQuery对象去获得地形的高度,RaySceneQuery射线访问方法 //NEGATIVE_UNIT_Y表示标准的2D向量,之间的区别不是很理解
                RaySceneQuery* raySceneQuery=mCamera->getSceneManager()->createRayQuery(Ray(Vector3(0,0,0), Vector3::NEGATIVE_UNIT_Y));
                //RaySceneQueryResult查询结果迭代器
                RaySceneQueryResult::iterator itmove;
                RaySceneQueryResult& qryResult=raySceneQuery->execute();//execute()返回查询结果

                for (size_t i = 0; i < numMesh; i++)
                {
                        Vector3 position;
                        position=nodes->getPosition();

                        position.x+=0.2;

                        // clamp to terrain
                        static Ray updateRay;
                        updateRay.setOrigin(position);
                        updateRay.setDirection(Vector3::NEGATIVE_UNIT_Y);
                        raySceneQuery->setRay(updateRay);
                        RaySceneQueryResult& qryResult = raySceneQuery->execute();
                        RaySceneQueryResult::iterator k = qryResult.begin();
                        if (k != qryResult.end() && k->worldFragment)
                        {                               
                                        position.y=k->worldFragment->singleIntersection.y+1;//必须最少抬高一个单位的,免得走不了,但是机器人就不在地面上了。
                                        nodes->setPosition(position);                                       
                        }                       
                }
                if( ExampleFrameListener::frameStarted(evt) == false )
                        return false;

                return true;

        }
        //-----------------------------------------------------------------------
        void createEntityGeom();
        //-----------------------------------------------------------------------
        void destroyEntityGeom();
        //-----------------------------------------------------------------------

};

//-----------------------------------------------------------------------
void MyOGREFrameListener::createEntityGeom()
{
        size_t k = 0;
        size_t y = 0;

        //强制容器把它的容量改为至少numRender,提供的numRender不小于当前大小。这一般强迫进行一次重新分配,因为容量需要增加。
        //(如果n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。
        //在我的经验中,使用reserve来从一个string中修整多余容量一般不如使用“交换技巧”,那是条款17的主题。)
        renderEntity.reserve (numMesh);
        renderEntity.resize (numMesh);
        nodes.reserve (numMesh);
        nodes.resize (numMesh);
        //create a RayQuery to get the terrain height
        //创建一个RayQuery对象去获得地形的高度,RaySceneQuery射线访问方法 //NEGATIVE_UNIT_Y表示标准的2D向量,之间的区别不是很理解
        RaySceneQuery* raySceneQuery=mCamera->getSceneManager()->createRayQuery(Ray(Vector3(0,0,0), Vector3::NEGATIVE_UNIT_Y));
        //RaySceneQueryResult查询结果迭代器
        RaySceneQueryResult::iterator it;
        RaySceneQueryResult& qryResult=raySceneQuery->execute();//execute()返回查询结果
        for (size_t i = 0; i < numMesh; i++)
        {

                Vector3 position;

                position.x=10*y+500;
                position.y=0;
                position.z=10*k+500;       

                //设置一条射线,这条射线就是一个机器人的XZ轴上的位置,Y轴位置用射线获得。
                raySceneQuery->setRay (Ray(position, Vector3::UNIT_Y));
                raySceneQuery->execute();
                it = qryResult.begin();

                if (it != qryResult.end() && it->worldFragment)
                        position.y =  it->worldFragment->singleIntersection.y;

                //得到相机所在的场景,得到场景根节点,创建一个新的场景节点,靠这个好理解多了,上一个方法,虽然节省点内存,但帧数下降点点
                nodes=mCamera->getSceneManager()->getRootSceneNode()->createChildSceneNode("node"+StringConverter::toString(i));
                //注册日志消息,用来干马,注册在哪里?又有什么用,体现在哪里?
                LogManager::getSingleton().logMessage(":"+nodes->getName());
                //创建一股机器人
                renderEntity=mCamera->getSceneManager()->createEntity("robot"+StringConverter::toString(i), "robot.mesh");       
                nodes->attachObject(renderEntity);
                nodes->setPosition(position);
                nodes->setScale(Vector3(0.1,0.1,0.1));
                AnimationState*anim=renderEntity->getAnimationState("Walk");//
                animations.push_back(anim);//压入队列是为了方便帧监听进行更新动画帧
                anim->setTimePosition(y+k);
                anim->setEnabled(true);
                y++;
                if (y>14)
                {
                        y=0;
                        k++;
                }
        }
        //设置好以后,就开始删除,零时的对象。
        mCamera->getSceneManager()->destroyQuery(raySceneQuery);


}
//-----------------------------------------------------------------------
void MyOGREFrameListener::destroyEntityGeom()
{
        size_t i;
        size_t j=0;
        for (i=0;i<numMesh;i++)
        {
                LogManager::getSingleton().logMessage(" " +nodes->getName());
                LogManager::getSingleton().logMessage(StringConverter::toString(j)+":"+StringConverter::toString(j<numMesh));
                String name=nodes->getName();
                mCamera->getSceneManager()->destroySceneNode(name);
                mCamera->getSceneManager()->destroyEntity(renderEntity);
                j++;
        }
        animations.clear();
}
//-----------------------------------------------------------------------



class MyOGREApplication : public ExampleApplication
{
public:
        MyOGREApplication() {}

        ~MyOGREApplication()
        {
               
        }

protected:


        virtual void chooseSceneManager(void)
        {
                // Get the SceneManager, in this case a generic one
                //我们必须将场景管理器设为地面的场景管理器,而不是ExampleApplication里默认的那个//
                //mSceneMgr = mRoot->createSceneManager("TerrainSceneManager");
                mSceneMgr = mRoot->createSceneManager(ST_EXTERIOR_CLOSE);

        }

        virtual void createCamera(void)
        {
                // Create the camera
                mCamera = mSceneMgr->createCamera(&quotlayerCam");

                mCamera->setPosition(700,100, 500);
                mCamera->lookAt(600,80,600);

                mCamera->setNearClipDistance( 1 );
                //mCamera->setFarClipDistance( 1000 );

        }

        // Just override the mandatory create scene method
        void createScene(void)
        {
                // Set ambient light
                mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));

                //白天的雾--------------------------start
                ////场景管理器的基类定义了一个叫做setWorldGeometry的方法,使派生类便于创建场景。当使用地面场景管理器(TerrainSceneManager)时,它需要一个文件名来加载地面属性。在createScene函数中添加这行代码
                std::string terrain_cfg("terrain.cfg");
                mSceneMgr -> setWorldGeometry( terrain_cfg );

                //天空穹 看不见
                //mSceneMgr->setSkyDome( true, "Examples/CloudySky", 30, 8 );
                // Create a skydome
                mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8);

                mSceneMgr->setShadowTextureSize(1024);
        }

        //-----------------------------------------------------------------------
        void createFrameListener(void)
        {
                // This is where we instantiate our own frame listener
                mFrameListener= new MyOGREFrameListener(mWindow, mCamera);
                mRoot->addFrameListener(mFrameListener);
        }
        //-----------------------------------------------------------------------


};


#ifdef __cplusplus
extern "C" {
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"

        INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
        int main(int argc, char **argv)
#endif
        {
                // Create application object
                MyOGREApplication app;

                try {
                        app.go();
                } catch( Ogre::Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
                        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL );
#else
                        std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
                }


                return 0;
        }
#ifdef __cplusplus
}
#endif

sf_20071218152117.rar

310.62 KB, 下载次数:

18

主题

78

帖子

165

积分

注册会员

Rank: 2

积分
165
 楼主| 发表于 2007-12-18 15:26:00 | 显示全部楼层

Re:改写例子Demo_Crowd原定踏步的机器人成向前走出现的问

我使用的是OgreSDKSetup1.4.5_VC71这个版本,因为学习才几天,所以注释不要理会。

如果要让人物保持在地面上运动,需要怎样做呢?是不是有更好的方法?

先3Q了。

1

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
发表于 2007-12-20 00:15:00 | 显示全部楼层

Re:改写例子Demo_Crowd原定踏步的机器人成向前走出现的问

如果你的场景是一个地形的话,找找有没有类似getTerrainHeight()的方法,取得指定位置地形高度。如果不是地形的话,自己用射线碰撞的算法,去碰撞地面,找到交点,把机器人设置到这个高度就可以了。
你的代码没仔细看。不知道回复是否对你有用

18

主题

78

帖子

165

积分

注册会员

Rank: 2

积分
165
 楼主| 发表于 2007-12-21 13:24:00 | 显示全部楼层

Re: 改写例子Demo_Crowd原定踏步的机器人成向前走出现的问

3Q了。
其实原因是射线的起点设置的位置不对,当每次帧监听的时候,将y值设置100使他高于地面(射线的方向向下的),就可以检测到和地面的交点了,否则射线的起点在地面以下没有交点的。不过你的提到的函数可以再试试。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-24 01:24

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表