为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

Orge选中物体

2018-04-28 19页 doc 46KB 18阅读

用户头像

is_321575

暂无简介

举报
Orge选中物体Orge选中物体 选中物体 这次对于所有的鼠标事件,我创建了封闭函数来处理它们。当用户按下鼠标左键, "onLeftPressed"函数被调用,当按下右键时"onRightReleased"函数被调用,等 等。 一如既往,首先给出框架代码: #include #include #include #include "ExampleApplication.h" class MouseQueryListener : public ExampleFrameListener, public OIS::MouseL...
Orge选中物体
Orge选中物体 选中物体 这次对于所有的鼠标事件,我创建了封闭函数来处理它们。当用户按下鼠标左键, "onLeftPressed"函数被调用,当按下右键时"onRightReleased"函数被调用,等 等。 一如既往,首先给出框架代码: #include #include #include #include "ExampleApplication.h" class MouseQueryListener : public ExampleFrameListener, public OIS::MouseListener { public: MouseQueryListener(RenderWindow* win, Camera* cam, SceneManager *sceneManager, CEGUI::Renderer *renderer) : ExampleFrameListener(win, cam, false, true), mGUIRenderer(renderer) { // Setup default variables mCount = 0; mCurrentObject = NULL; mLMouseDown = false; mRMouseDown = false; mSceneMgr = sceneManager; // Reduce move speed mMoveSpeed = 50; mRotateSpeed /= 500; // Register this so that we get mouse events. mMouse->setEventCallback(this); // Create RaySceneQuery mRaySceneQuery = mSceneMgr->createRayQuery(Ray()); } // MouseQueryListener ~MouseQueryListener() { mSceneMgr->destroyQuery(mRaySceneQuery); } bool frameStarted(const FrameEvent &evt) { // Process the base frame listener code. Since we are going to be // manipulating the translate vector, we need this to happen first. if (!ExampleFrameListener::frameStarted(evt)) return false; // Setup the scene query Vector3 camPos = mCamera->getPosition(); Ray cameraRay(Vector3(camPos.x, 5000.0f, camPos.z), Vector3::NEGATIVE_UNIT_Y); mRaySceneQuery->setRay(cameraRay); // Perform the scene query RaySceneQueryResult &result = mRaySceneQuery->execute(); RaySceneQueryResult::iterator itr = result.begin(); // Get the results, set the camera height if (itr != result.end() && itr->worldFragment) { Real terrainHeight = itr->worldFragment->singleIntersection.y; if ((terrainHeight + 10.0f) > camPos.y) mCamera->setPosition( camPos.x, terrainHeight + 10.0f, camPos.z ); } return true; } bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { // Left mouse button up if (id == OIS::MB_Left) { onLeftReleased(arg); mLMouseDown = false; } // if // Right mouse button up else if (id == OIS::MB_Right) { onRightReleased(arg); mRMouseDown = false; } // else if return true; } bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) { // Left mouse button down if (id == OIS::MB_Left) { onLeftPressed(arg); mLMouseDown = true; } // if // Right mouse button down else if (id == OIS::MB_Right) { onRightPressed(arg); mRMouseDown = true; } // else if return true; } bool mouseMoved(const OIS::MouseEvent &arg) { // Update CEGUI with the mouse motion CEGUI::System::getSingleton().injectMouseMove(arg.state.X. rel, arg.state.Y.rel); // If we are dragging the left mouse button. if (mLMouseDown) { CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition(); Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(arg.state.width),m ousePos.d_y/float(arg.state.height)); mRaySceneQuery->setRay(mouseRay); RaySceneQueryResult &result = mRaySceneQuery->execute(); RaySceneQueryResult::iterator itr = result.begin(); if (itr != result.end() && itr->worldFragment) mCurrentObject->setPosition(itr->worldFragment->singleIntersection); } // if // If we are dragging the right mouse button. else if (mRMouseDown) { mCamera->yaw(Degree(-arg.state.X.rel * mRotateSpeed)); mCamera->pitch(Degree(-arg.state.Y.rel * mRotateSpeed)); } // else if return true; } // Specific handlers void onLeftPressed(const OIS::MouseEvent &arg) { // Setup the ray scene query, use CEGUI's mouse position CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition(); Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(arg.state.width), mousePos.d_y/float(arg.state.height)); mRaySceneQuery->setRay(mouseRay); // Execute query RaySceneQueryResult &result = mRaySceneQuery->execute(); RaySceneQueryResult::iterator itr = result.begin( ); // Get results, create a node/entity on the position if (itr != result.end() && itr->worldFragment) { char name[16]; sprintf(name, "Robot%d", mCount++); Entity *ent = mSceneMgr->createEntity(name, "robot.mesh"); mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(String(name) + "Node", itr->worldFragment->singleIntersection); mCurrentObject->attachObject(ent); mCurrentObject->setScale(0.1f, 0.1f, 0.1f); } // if } void onLeftReleased(const OIS::MouseEvent &arg) { } void onRightPressed(const OIS::MouseEvent &arg) { CEGUI::MouseCursor::getSingleton().hide(); } virtual void onRightReleased(const OIS::MouseEvent &arg) { CEGUI::MouseCursor::getSingleton().show(); } protected: RaySceneQuery *mRaySceneQuery; // The ray scene query pointer bool mLMouseDown, mRMouseDown; // True if the mouse buttons are down int mCount; // The number of robots on the screen SceneManager *mSceneMgr; // A pointer to the scene manager SceneNode *mCurrentObject; // The newly created object CEGUI::Renderer *mGUIRenderer; // CEGUI renderer }; class MouseQueryApplication : public ExampleApplication { protected: CEGUI::OgreCEGUIRenderer *mGUIRenderer; CEGUI::System *mGUISystem; // CEGUI system public: MouseQueryApplication() { } ~MouseQueryApplication() { } protected: void chooseSceneManager(void) { // Use the terrain scene manager. mSceneMgr = mRoot->createSceneManager(ST_EXTERIOR_CLOSE); } void createScene(void) { // Set ambient light mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5)); mSceneMgr->setSkyDome(true, "Examples/CloudySky", 5, 8); // World geometry mSceneMgr->setWorldGeometry("terrain.cfg"); // Set camera look point mCamera->setPosition(40, 100, 580); mCamera->pitch(Degree(-30)); mCamera->yaw(Degree(-45)); // CEGUI setup mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mSceneMgr); mGUISystem = new CEGUI::System(mGUIRenderer); // Mouse CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme"); CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow"); } void createFrameListener(void) { mFrameListener = new MouseQueryListener(mWindow, mCamera, mSceneMgr, mGUIRenderer); mFrameListener->showDebugOverlay(true); mRoot->addFrameListener(mFrameListener); } }; #if OGRE_PLATFORM == PLATFORM_WIN32 || 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 MouseQueryApplication app; try { app.go(); } catch(Exception& e) { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_OK | MB_ICONERROR | MB_TASKMODAL); #else fprintf(stderr, "An exception has occurred: %s\n", e.getFullDescription().c_str()); #endif } return 0; } 运行程序会发现程序运行的结果和手札19给出的代码,即手札18的程序的 最终代码运行结果是一样的,只不过正如前面说的将相应实践放到了封闭的函数 中了,你应该花一些时间来消化这些不同之处~ 一、实现选中物体 最终能够做到当你放置物体后,能“拾取”并移动它。我们希望用户知道他 目前正在操纵哪一个物体。在游戏里,我们可能以某种特殊的方式来高亮这个物 体。而在这里我们用showBoundingBox方法来创建一个围绕该物体的方盒。当鼠 标首次按下时,取消旧的选择物体上的包围盒,然后当选择了一新物体时,给新 物体加上包围盒。为此,我们 在onLeftPressed函数的开头添加如下代码: // 打开包围盒 if (mCurrentObject) mCurrentObject->showBoundingBox(false); 并在onLeftPressed末尾添加代码: // Show the bounding box to highlight the selected object if (mCurrentObject) mCurrentObject->showBoundingBox(true); 运行你的程序发现单击创建的机器人会有一圈的白框 ———————————————————————————————————————————— 二、实现添加不同种类的物体 实现代码不仅能够添加机器人还能够放置和移动忍者。 我们需要一个“机器人模式”和一个“忍者模式”,来决定在屏幕上放置的物体。 我们把空格键设置成切换按钮,并且显示信息提示用户目前处于哪一种模式。 首先,我们把MouseQueryListener设置成机器人模式。我们添加一个变量来保存物体状态 在MouseQueryListener类的protected变量区域添加这个变量: bool mRobotMode; //变量用于标明当前状态 在MouseQueryListener类的构造函数进行初始化: // 设置文本、缺省状态 mRobotMode = true; mDebugText = "Robot Mode Enabled - Press Space to Toggle"; 下面有修改单击响应代码,单击时根据mRobotMode的状态来断定应当添加什么模型: 在onLeftPressed里修改代码: 将这三句 char name[16]; sprintf(name, "Robot%d", mCount++); Entity *ent = mSceneMgr->createEntity(name, "robot.mesh"); 修改为: Entity *ent; char name[16]; if (mRobotMode) { sprintf(name, "Robot%d", mCount++); ent = mSceneMgr->createEntity(name, "robot.mesh"); } // if else { sprintf(name, "Ninja%d", mCount++); ent = mSceneMgr->createEntity(name, "ninja.mesh"); } // else这些代码大家一定能够看懂我就不解释了 下面绑定空格键,来改变状态。 在frameStarted里(第一个if语句之后)添加: // 切换模式 if(mKeyboard->isKeyDown(OIS::KC_SPACE) && mTimeUntilNextToggle <= 0) { mRobotMode = !mRobotMode; mTimeUntilNextToggle = 1; mDebugText = (mRobotMode ? String("Robot") : String("Ninja")) + " Mode Enabled - Press Space to Toggle"; } 看看效果吧~ —————————————————————————————————— ———————— 三、选中物体 首先介绍一下下面这个结构体,你可以通过连接查看的类结构 RaySceneQueryResultEntry RaySceneQueryResult返回一个RaySceneQueryResultEntry结构体的iterator。 这个结构体包含三个变量。 distance变量告诉你这个物体沿着射线有多远。另外两个变量的其中一个将是null(movable或者worldFramegment)。 movable变量包含一个MovableObject对象(MovableObject基本上可以是任何你能绑在SceneNode上的对象(像实体、光源,等))你可以看一下后面那个继承关系图 如果与射线相交的话。如果射线接触到一个地形片段,worldFragment将保存这个worldFragment对象(比如地形)。 大多数RaySceneQueries的应用包括选取和操纵MovableObject对象,以及它们所绑定到的SceneNodes 。调用getName方法获取MovableObject的名称。调用getParentSceneNode(或getParentNode)获取它们所绑定到的SceneNode。如果RaySceneQueryResultEntry的结果不是一个MovableObject,movable变量则为null。 WorldFragment是完全另一种怪物。当RaySceneQueryResult中的worldFragment成员被设置时,就意味着返回结果是SceneManager创建的世界几何(world geometry)的一部分。返回的world fragment的类型是基于SceneManager的。它是这样实现的,WorldFragment结构体包含一个fragmentType变量,以指明world fragment的类型。基于这个fragmentType变量,设置其它成员变量(singleIntersection, planes, geometry, 或者renderOp)。一般来说,RaySceneQueries只返回WFT_SINGLE_INTERSECTION类型的WorldFragments。singleIntersection变量只是一个Vector3,用来报告交点的坐标。 介绍到这里,归正传 我们要做的另一件事情是“拾起”并拖拽已经被放置的物体。当前你若点击一个已经放置的物体,程序会忽略它,并在它后面放置另一个机器人。我们现在来修正它。 首先要保证当我们点击鼠标,我们能得到沿射线上的第一个东西。为此,我们需要设置RaySceneQuery按深度排序。找到onLeftPressed函数里的如下代码: // Setup the ray scene query, use CEGUI's mouse position CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition(); Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(arg.state.width), mousePos.d_y/float(arg.state.height)); mRaySceneQuery->setRay(mouseRay); // Execute query RaySceneQueryResult &result = mRaySceneQuery->execute(); RaySceneQueryResult::iterator itr = result.begin( ); 修改成这样(两处变化): // Setup the ray scene query CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition(); Ray mouseRay = mCamera->getCameraToViewportRay(mousePos.d_x/float(arg.state.width), mousePos.d_y/float(arg.state.height)); mRaySceneQuery->setRay(mouseRay); mRaySceneQuery->setSortByDistance(true);//按顺序返回结果 // Execute query RaySceneQueryResult &result = mRaySceneQuery->execute(); RaySceneQueryResult::iterator itr; 以下这段代码是我们要重写的,因为我们不能在单击时在创建实体 // Get results, create a node/entity on the position if (itr != result.end() && itr->worldFragment) { Entity *ent; char name[16]; if (mRobotMode) { sprintf(name, "Robot%d", mCount++); ent = mSceneMgr->createEntity(name, "robot.mesh"); } // if else { sprintf(name, "Ninja%d", mCount++); ent = mSceneMgr->createEntity(name, "ninja.mesh"); } // else这些代码大家一定能够看懂我就不解释了 mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(String(name) + "Node", itr->worldFragment->singleIntersection); mCurrentObject->attachObject(ent); mCurrentObject->setScale(0.1f, 0.1f, 0.1f); } // if } 实现能够选取已经放置在屏幕上的物体分为两步。 首先,如果用户点击一个物体,则使mCurrentObject等于它的父节点。 如果用户没有点击在物体上(而是点在地型上)时,就像以前一样放置一个新的 机器人。 第一个要做的修改就是,使用一个for循环来代替if语句: for ( itr = result.begin(); itr != result.end(); itr++ ) { if (itr->movable && itr->movable->getName().substr(0, 5) != "tile[") { mCurrentObject = itr->movable->getParentSceneNode(); break; // 首先我们要检查第一个交点的是不是一个MovableObject //如果是,我们把它的父节点赋给mCurrentObject。还要做另一个判断 //TerrainSceneManager会为地型本身创建MovableObject //所以我们可能实际上会与他们相交。为了修正这个问题,我通过检查对 象的名称来保证 //它们的名称不类似于地型名称。一个典型的地形名称比如 "tile[0][0,2]"。 //最后,注意这个break语句。我们只需要在第一个物体上做操作,一旦 我们找到一个合法的, //我们就应该跳出循环。 } // if else if (itr->worldFragment) { Entity *ent; char name[16]; if (mRobotMode) { sprintf(name, "Robot%d", mCount++); ent = mSceneMgr->createEntity(name, "robot.mesh"); } // if else { sprintf(name, "Ninja%d", mCount++); ent = mSceneMgr->createEntity(name, "ninja.mesh"); } // else mCurrentObject = mSceneMgr->getRootSceneNode()->createChildSceneNode(String(name) + "Node", itr->worldFragment->singleIntersection); mCurrentObject->attachObject(ent); mCurrentObject->setScale(0.1f, 0.1f, 0.1f); break; } // else if } // for 运行你的程序可以实现选中了
/
本文档为【Orge选中物体】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索