码迷,mamicode.com
首页 > 其他好文 > 详细

基于Ogre的角色控制器

时间:2015-02-25 13:00:10      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:

基本框架

首先参照这里配置好工程。

添加一个类CharacterApplication,还有main.cpp.

直接贴代码了。

characterapplication.h

#pragma once
#include <OgreCamera.h>
#include <OgreEntity.h>
#include <OgreLogManager.h>
#include <OgreRoot.h>
#include <Ogre.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreRenderWindow.h>
#include <OgreConfigFile.h>
#include <OgreTextureManager.h>
#include <OgreMaterialManager.h>
#include <OgreWindowEventUtilities.h>
#include <conio.h>

class CharactorApplication
{
public:
	CharactorApplication();
	~CharactorApplication();
	void go();

private:
	bool startup();
	void loadResouces();
	void createScene();
	void createCamera();

	Ogre::SceneManager* mSceneManager;
	Ogre::Root* mRoot;
	Ogre::RenderWindow* mWindow;

};


characterapplication.cpp

#include "charactorapplication.h"


CharactorApplication::CharactorApplication()
{
	mSceneManager = NULL;
	mRoot = NULL;
}


CharactorApplication::~CharactorApplication()
{
	delete mRoot;
}

bool CharactorApplication::startup()
{
	mRoot = new Ogre::Root("plugins_d.cfg");
	if (!mRoot->showConfigDialog())
	{
		return false;
	}

	mWindow = mRoot->initialise(true, "Character Control");
	mSceneManager = mRoot->createSceneManager(Ogre::ST_GENERIC);

	return true;
}

void CharactorApplication::createCamera()
{
	Ogre::Camera* camera = mSceneManager->createCamera("Camera");
	camera->setPosition(Ogre::Vector3(0, 0, 30));
	camera->lookAt(Ogre::Vector3(0, 0, 0));
	camera->setNearClipDistance(5);

	Ogre::Viewport* viewport = mWindow->addViewport(camera);
	viewport->setBackgroundColour(Ogre::ColourValue(1.0f, 1.0f, 0.0f));

	camera->setAspectRatio(Ogre::Real(viewport->getActualWidth()) / Ogre::Real(viewport->getActualHeight()));
}

void CharactorApplication::loadResouces()
{
	//Load resources
	Ogre::ConfigFile cf;
	cf.load("resources_d.cfg");

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
				archName, typeName, secName);
		}
	}
	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
}

void CharactorApplication::createScene()
{
	mSceneManager->setAmbientLight(Ogre::ColourValue(1, 1, 1));
	Ogre::Entity* sinbadEnt = mSceneManager->createEntity("Sinbad.mesh");
	mSceneManager->getRootSceneNode()->attachObject(sinbadEnt);
	
}

void CharactorApplication::go()
{
	if (startup())
	{
		loadResouces();
		createCamera();
		createScene();
		mRoot->startRendering();
		_cprintf("Done");
	}
}


简单说一下下面的几个函数
bool startup() - 成员的初始化工作。
void loadResouces() - 初始化资源。
void createScene() - 创建场景。
void createCamera() - 创建摄像机及视口。

工程目录下面别忘了把resources_d.cfg和plugins_d.cfg拷贝过来。


运行一下,结果如下:

技术分享


丰富场景

最终场景如下

技术分享


地面和天空盒

Ogre::Plane plane(Ogre::Vector3::UNIT_Y, -25);
	Ogre::MeshManager::getSingleton().createPlane("plane", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 1500, 1500, 20, 20, true, 1, 5, 5, Ogre::Vector3::UNIT_Z);
	Ogre::Entity* plantEnt = mSceneManager->createEntity("LightPlaneEntity", "plane");
	plantEnt->setMaterialName("Examples/BeachStones");
	mSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(plantEnt);
	mSceneManager->setSkyBox(true, "Examples/SpaceSkyBox", 5000, true);

一片草地

void CharactorApplication::createGrass()
{
	//Create grass
	Ogre::ManualObject* manual = mSceneManager->createManualObject("grass");
	manual->begin("Examples/GrassBlades", Ogre::RenderOperation::OT_TRIANGLE_LIST);
	manual->position(5.0, 0.0, 0.0);
	manual->textureCoord(1, 1);
	manual->position(-5.0, 10.0, 0.0);
	manual->textureCoord(0, 0);
	manual->position(-5.0, 0.0, 0.0);
	manual->textureCoord(0, 1);
	manual->position(5.0, 10.0, 0.0);
	manual->textureCoord(1, 0);
	manual->position(2.5, 0.0, 4.3);
	manual->textureCoord(1, 1);
	manual->position(-2.5, 10.0, -4.3);
	manual->textureCoord(0, 0);
	manual->position(-2.0, 0.0, -4.3);
	manual->textureCoord(0, 1);
	manual->position(2.5, 10.0, 4.3);
	manual->textureCoord(1, 0);
	manual->position(2.5, 0.0, -4.3);
	manual->textureCoord(1, 1);
	manual->position(-2.5, 10.0, 4.3);
	manual->textureCoord(0, 0);
	manual->position(-2.0, 0.0, 4.3);
	manual->textureCoord(0, 1);
	manual->position(2.5, 10.0, -4.3);
	manual->textureCoord(1, 0);

	manual->index(0);
	manual->index(1);
	manual->index(2);
	manual->index(0);
	manual->index(3);
	manual->index(1);


	manual->index(4);
	manual->index(5);
	manual->index(6);
	manual->index(4);
	manual->index(7);
	manual->index(5);
	manual->index(8);
	manual->index(9);
	manual->index(10);
	manual->index(8);
	manual->index(11);
	manual->index(9);

	manual->end();

	manual->convertToMesh("BladesOfGrass");

	Ogre::StaticGeometry* field = mSceneManager->createStaticGeometry("FieldOfGrass");
	for (int i = -25; i < 25; i++)
	{
		for (int j = -25; j < 25; j++)
		{
			Ogre::Entity * ent = mSceneManager->createEntity("BladesOfGrass");
			field->addEntity(ent, Ogre::Vector3(i * 3, -25, j * 3));
		}
	}
	field->build();
}

一个粒子

	Ogre::ParticleSystem::setDefaultNonVisibleUpdateTimeout(5);  // set nonvisible timeout
	Ogre::ParticleSystem* ps;

	ps = mSceneManager->createParticleSystem("Nimbus", "Examples/GreenyNimbus");
	mSceneManager->getRootSceneNode()->attachObject(ps);

灯光和阴影

	mSceneManager->setAmbientLight(Ogre::ColourValue(0, 0, 0));
	mSceneManager->setShadowTechnique(Ogre::SHADOWTYPE_STENCIL_ADDITIVE);

	Ogre::Light* directionalLight = mSceneManager->createLight("directionalLight");
	directionalLight->setType(Ogre::Light::LT_DIRECTIONAL);
	directionalLight->setDiffuseColour(Ogre::ColourValue(0.8f, 0.8f, 0.8f));
	directionalLight->setSpecularColour(Ogre::ColourValue(.25, .25, 0));
	directionalLight->setDirection(Ogre::Vector3(-1, -1, -1));


角色控制器

这个类主要处理角色的运动,动画的播放,摄像机的控制。

charactorcontroller.h

#pragma once

#include "Ogre.h"
#include "OIS.h"
#include <algorithm>
#define NUM_ANIMS 13           // number of animations the character has
#define CHAR_HEIGHT 0         // height of character‘s center of mass above ground
#define CAM_HEIGHT 2           // height of camera above character‘s center of mass
#define RUN_SPEED 85           // character running speed in units per second
#define TURN_SPEED 500.0f      // character turning in degrees per second
#define ANIM_FADE_SPEED 7.5f   // animation crossfade speed in % of full weight per second
#define JUMP_ACCEL 60.0f       // character jump acceleration in upward units per squared second
#define GRAVITY 180.0f          // gravity in downward units per squared second

class CharactorController
{
public:
	CharactorController(Ogre::Camera* cam);
	~CharactorController();

	void addTime(Ogre::Real deltaTime);
	void injectKeyDown(const OIS::KeyEvent& evt);
	void injectKeyUp(const OIS::KeyEvent& evt);
	void injectPointerMove(const OIS::MouseEvent& evt);
	void injectPointerDown(const OIS::MouseEvent& evt, OIS::MouseButtonID id);

private:
	enum AnimID
	{
		ANIM_IDLE_BASE,
		ANIM_IDLE_TOP,
		ANIM_RUN_BASE,
		ANIM_RUN_TOP,
		ANIM_HANDS_CLOSED,
		ANIM_HANDS_RELAXED,
		ANIM_DRAW_SWORDS,
		ANIM_SLICE_VERTICAL,
		ANIM_SLICE_HORIZONTAL,
		ANIM_DANCE,
		ANIM_JUMP_START,
		ANIM_JUMP_LOOP,
		ANIM_JUMP_END,
		ANIM_NONE
	};

	void setupBody(Ogre::SceneManager* sceneManager);
	void setupAnimations();
	void setupCamera(Ogre::Camera* cam);
	void updateBody(Ogre::Real deltaTime);
	void updateAnimations(Ogre::Real deltaTime);
	void fadeAnimations(Ogre::Real deltaTime);
	void updateCamera(Ogre::Real deltaTime);
	void updateCameraGoal(Ogre::Real deltaYaw, Ogre::Real deltaPitch, Ogre::Real deltaZoom);
	void setBaseAnimation(AnimID id, bool reset = false);
	void setTopAnimation(AnimID id, bool reset = false);

	Ogre::SceneNode* mBodyNode;
	Ogre::SceneNode* mCameraPivot;
	Ogre::SceneNode* mCameraGoal;
	Ogre::SceneNode* mCameraNode;
	Ogre::Real mPivotPitch;
	Ogre::Entity* mBodyEnt;
	Ogre::Entity* mSword1;
	Ogre::Entity* mSword2;
	Ogre::RibbonTrail* mSwordTrail;
	Ogre::AnimationState* mAnims[NUM_ANIMS];    // master animation list
	AnimID mBaseAnimID;                   // current base (full- or lower-body) animation
	AnimID mTopAnimID;                    // current top (upper-body) animation
	bool mFadingIn[NUM_ANIMS];            // which animations are fading in
	bool mFadingOut[NUM_ANIMS];           // which animations are fading out
	bool mSwordsDrawn;
	Ogre::Vector3 mKeyDirection;      // player‘s local intended direction based on WASD keys
	Ogre::Vector3 mGoalDirection;     // actual intended direction in world-space
	Ogre::Real mVerticalVelocity;     // for jumping
	Ogre::Real mTimer;                // general timer to see how long animations have been playing

};

charactorcontroller.cpp

#include "charactorcontroller.h"


CharactorController::CharactorController(Ogre::Camera* cam)
{
	setupBody(cam->getSceneManager());
	setupCamera(cam);
	setupAnimations();
}

CharactorController::~CharactorController()
{
}


void CharactorController::addTime(Ogre::Real deltaTime)
{
	updateBody(deltaTime);
	updateAnimations(deltaTime);
	updateCamera(deltaTime);
}

void CharactorController::injectKeyDown(const OIS::KeyEvent& evt)
{
	if (evt.key == OIS::KC_Q && (mTopAnimID == ANIM_IDLE_TOP || mTopAnimID == ANIM_RUN_TOP))
	{
		// take swords out (or put them back, since it‘s the same animation but reversed)
		setTopAnimation(ANIM_DRAW_SWORDS, true);
		mTimer = 0;
	}
	else if (evt.key == OIS::KC_E && !mSwordsDrawn)
	{
		if (mTopAnimID == ANIM_IDLE_TOP || mTopAnimID == ANIM_RUN_TOP)
		{
			// start dancing
			setBaseAnimation(ANIM_DANCE, true);
			setTopAnimation(ANIM_NONE);
			// disable hand animation because the dance controls hands
			mAnims[ANIM_HANDS_RELAXED]->setEnabled(false);
		}
		else if (mBaseAnimID == ANIM_DANCE)
		{
			// stop dancing
			setBaseAnimation(ANIM_IDLE_BASE);
			setTopAnimation(ANIM_IDLE_TOP);
			// re-enable hand animation
			mAnims[ANIM_HANDS_RELAXED]->setEnabled(true);
		}
	}

	// keep track of the player‘s intended direction
	else if (evt.key == OIS::KC_W) mKeyDirection.z = -1;
	else if (evt.key == OIS::KC_A) mKeyDirection.x = -1;
	else if (evt.key == OIS::KC_S) mKeyDirection.z = 1;
	else if (evt.key == OIS::KC_D) mKeyDirection.x = 1;

	else if (evt.key == OIS::KC_SPACE && (mTopAnimID == ANIM_IDLE_TOP || mTopAnimID == ANIM_RUN_TOP))
	{
		// jump if on ground
		setBaseAnimation(ANIM_JUMP_START, true);
		setTopAnimation(ANIM_NONE);
		mTimer = 0;
	}

	if (!mKeyDirection.isZeroLength() && mBaseAnimID == ANIM_IDLE_BASE)
	{
		// start running if not already moving and the player wants to move
		setBaseAnimation(ANIM_RUN_BASE, true);
		if (mTopAnimID == ANIM_IDLE_TOP) setTopAnimation(ANIM_RUN_TOP, true);
	}
}

void CharactorController::injectKeyUp(const OIS::KeyEvent& evt)
{
	// keep track of the player‘s intended direction
	if (evt.key == OIS::KC_W && mKeyDirection.z == -1) mKeyDirection.z = 0;
	else if (evt.key == OIS::KC_A && mKeyDirection.x == -1) mKeyDirection.x = 0;
	else if (evt.key == OIS::KC_S && mKeyDirection.z == 1) mKeyDirection.z = 0;
	else if (evt.key == OIS::KC_D && mKeyDirection.x == 1) mKeyDirection.x = 0;

	if (mKeyDirection.isZeroLength() && mBaseAnimID == ANIM_RUN_BASE)
	{
		// stop running if already moving and the player doesn‘t want to move
		setBaseAnimation(ANIM_IDLE_BASE);
		if (mTopAnimID == ANIM_RUN_TOP) setTopAnimation(ANIM_IDLE_TOP);
	}
}

void CharactorController::injectPointerMove(const OIS::MouseEvent& evt)
{
	updateCameraGoal(-0.05f * evt.state.X.rel, -0.05f * evt.state.Y.rel, -0.0005f * evt.state.Z.rel);
}

void CharactorController::injectPointerDown(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
	if (mSwordsDrawn && (mTopAnimID == ANIM_IDLE_TOP || mTopAnimID == ANIM_RUN_TOP))
	{
		// if swords are out, and character‘s not doing something weird, then SLICE!
		if (id == OIS::MB_Left) setTopAnimation(ANIM_SLICE_VERTICAL, true);
		else if (id == OIS::MB_Right) setTopAnimation(ANIM_SLICE_HORIZONTAL, true);
		mTimer = 0;
	}
}




void CharactorController::setupBody(Ogre::SceneManager* sceneManager)
{
	// create main model
	mBodyNode = sceneManager->getRootSceneNode()->createChildSceneNode(Ogre::Vector3::UNIT_Y * CHAR_HEIGHT);
	mBodyEnt = sceneManager->createEntity("SinbadBody", "Sinbad.mesh");
	mBodyNode->attachObject(mBodyEnt);

	// create swords and attach to sheath
	Ogre::LogManager::getSingleton().logMessage("Creating swords");
	mSword1 = sceneManager->createEntity("SinbadSword1", "Sword.mesh");
	mSword2 = sceneManager->createEntity("SinbadSword2", "Sword.mesh");
	mBodyEnt->attachObjectToBone("Sheath.L", mSword1);
	mBodyEnt->attachObjectToBone("Sheath.R", mSword2);

	Ogre::LogManager::getSingleton().logMessage("Creating the chains");
	// create a couple of ribbon trails for the swords, just for fun
	Ogre::NameValuePairList params;
	params["numberOfChains"] = "2";
	params["maxElements"] = "80";
	mSwordTrail = (Ogre::RibbonTrail*)sceneManager->createMovableObject("RibbonTrail", ?ms);
	mSwordTrail->setMaterialName("Examples/LightRibbonTrail");
	mSwordTrail->setTrailLength(50);
	mSwordTrail->setInitialWidth(0, 100);
	mSwordTrail->setVisible(false);
	sceneManager->getRootSceneNode()->attachObject(mSwordTrail);


	for (int i = 0; i < 2; i++)
	{
		mSwordTrail->setInitialColour(i, 1, 0.8, 0);
		mSwordTrail->setColourChange(i, 0.75, 1.25, 1.25, 1.25);
		mSwordTrail->setWidthChange(i, 1);
		mSwordTrail->setInitialWidth(i, 0.5);
	}

	mKeyDirection = Ogre::Vector3::ZERO;
	mVerticalVelocity = 0;

	mBodyNode->setScale(5.0f, 5.0f, 5.0f);
}

void CharactorController::setupAnimations()
{
	// this is very important due to the nature of the exported animations
	mBodyEnt->getSkeleton()->setBlendMode(Ogre::ANIMBLEND_CUMULATIVE);
	Ogre::String animNames[] =
	{ "IdleBase", "IdleTop", "RunBase", "RunTop", "HandsClosed", "HandsRelaxed", "DrawSwords",
	"SliceVertical", "SliceHorizontal", "Dance", "JumpStart", "JumpLoop", "JumpEnd" };

	for (int i = 0; i < NUM_ANIMS; i++)
	{
		mAnims[i] = mBodyEnt->getAnimationState(animNames[i]);
		mAnims[i]->setLoop(true);
		mFadingIn[i] = false;
		mFadingOut[i] = false;
	}

	setBaseAnimation(ANIM_IDLE_BASE);
	setTopAnimation(ANIM_IDLE_TOP);

	mAnims[ANIM_HANDS_RELAXED]->setEnabled(true);

	mSwordsDrawn = false;
}

void CharactorController::setupCamera(Ogre::Camera* cam)
{
	mCameraPivot = cam->getSceneManager()->getRootSceneNode()->createChildSceneNode();
	mCameraGoal = mCameraPivot->createChildSceneNode(Ogre::Vector3(0, 0, 15));

	mCameraNode = cam->getSceneManager()->getRootSceneNode()->createChildSceneNode();
	mCameraNode->setPosition(mCameraPivot->getPosition() + mCameraGoal->getPosition());

	mCameraPivot->setFixedYawAxis(true);
	mCameraGoal->setFixedYawAxis(true);
	mCameraNode->setFixedYawAxis(true);

	cam->setNearClipDistance(0.1);
	cam->setFarClipDistance(100);
	mCameraNode->attachObject(cam);

	mPivotPitch = 0;

}

void CharactorController::updateBody(Ogre::Real deltaTime)
{
	mGoalDirection = Ogre::Vector3::ZERO;   // we will calculate this

	if (mKeyDirection != Ogre::Vector3::ZERO && mBaseAnimID != ANIM_DANCE)
	{
		// calculate actually goal direction in world based on player‘s key directions
		mGoalDirection += mKeyDirection.z * mCameraNode->getOrientation().zAxis();
		mGoalDirection += mKeyDirection.x * mCameraNode->getOrientation().xAxis();
		mGoalDirection.y = 0;
		mGoalDirection.normalise();

		Ogre::Quaternion toGoal = mBodyNode->getOrientation().zAxis().getRotationTo(mGoalDirection);

		// calculate how much the character has to turn to face goal direction
		Ogre::Real yawToGoal = toGoal.getYaw().valueDegrees();
		// this is how much the character CAN turn this frame
		Ogre::Real yawAtSpeed = yawToGoal / Ogre::Math::Abs(yawToGoal) * deltaTime * TURN_SPEED;
		// reduce "turnability" if we‘re in midair
		if (mBaseAnimID == ANIM_JUMP_LOOP) yawAtSpeed *= 0.2f;

		// turn as much as we can, but not more than we need to
		if (yawToGoal < 0) yawToGoal = std::min<Ogre::Real>(0, std::max<Ogre::Real>(yawToGoal, yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, yawAtSpeed, 0);
		else if (yawToGoal > 0) yawToGoal = std::max<Ogre::Real>(0, std::min<Ogre::Real>(yawToGoal, yawAtSpeed)); //yawToGoal = Math::Clamp<Real>(yawToGoal, 0, yawAtSpeed);

		mBodyNode->yaw(Ogre::Degree(yawToGoal));

		// move in current body direction (not the goal direction)
		mBodyNode->translate(0, 0, deltaTime * RUN_SPEED * mAnims[mBaseAnimID]->getWeight(),
			Ogre::Node::TS_LOCAL);
	}

	if (mBaseAnimID == ANIM_JUMP_LOOP)
	{
		// if we‘re jumping, add a vertical offset too, and apply gravity
		mBodyNode->translate(0, mVerticalVelocity * deltaTime, 0, Ogre::Node::TS_LOCAL);
		mVerticalVelocity -= GRAVITY * deltaTime;

		Ogre::Vector3 pos = mBodyNode->getPosition();
		if (pos.y <= CHAR_HEIGHT)
		{
			// if we‘ve hit the ground, change to landing state
			pos.y = CHAR_HEIGHT;
			mBodyNode->setPosition(pos);
			setBaseAnimation(ANIM_JUMP_END, true);
			mTimer = 0;
		}
	}
}

void CharactorController::updateAnimations(Ogre::Real deltaTime)
{
	Ogre::Real baseAnimSpeed = 1;
	Ogre::Real topAnimSpeed = 1;

	mTimer += deltaTime;

	if (mTopAnimID == ANIM_DRAW_SWORDS)
	{
		// flip the draw swords animation if we need to put it back
		topAnimSpeed = mSwordsDrawn ? -1 : 1;

		// half-way through the animation is when the hand grasps the handles...
		if (mTimer >= mAnims[mTopAnimID]->getLength() / 2 &&
			mTimer - deltaTime < mAnims[mTopAnimID]->getLength() / 2)
		{
			// so transfer the swords from the sheaths to the hands
			mBodyEnt->detachAllObjectsFromBone();
			mBodyEnt->attachObjectToBone(mSwordsDrawn ? "Sheath.L" : "Handle.L", mSword1);
			mBodyEnt->attachObjectToBone(mSwordsDrawn ? "Sheath.R" : "Handle.R", mSword2);
			// change the hand state to grab or let go
			mAnims[ANIM_HANDS_CLOSED]->setEnabled(!mSwordsDrawn);
			mAnims[ANIM_HANDS_RELAXED]->setEnabled(mSwordsDrawn);

			// toggle sword trails
			if (mSwordsDrawn)
			{
				mSwordTrail->setVisible(false);
				mSwordTrail->removeNode(mSword1->getParentNode());
				mSwordTrail->removeNode(mSword2->getParentNode());
			}
			else
			{
				mSwordTrail->setVisible(true);
				mSwordTrail->addNode(mSword1->getParentNode());
				mSwordTrail->addNode(mSword2->getParentNode());
			}
		}

		if (mTimer >= mAnims[mTopAnimID]->getLength())
		{
			// animation is finished, so return to what we were doing before
			if (mBaseAnimID == ANIM_IDLE_BASE) setTopAnimation(ANIM_IDLE_TOP);
			else
			{
				setTopAnimation(ANIM_RUN_TOP);
				mAnims[ANIM_RUN_TOP]->setTimePosition(mAnims[ANIM_RUN_BASE]->getTimePosition());
			}
			mSwordsDrawn = !mSwordsDrawn;
		}
	}
	else if (mTopAnimID == ANIM_SLICE_VERTICAL || mTopAnimID == ANIM_SLICE_HORIZONTAL)
	{
		if (mTimer >= mAnims[mTopAnimID]->getLength())
		{
			// animation is finished, so return to what we were doing before
			if (mBaseAnimID == ANIM_IDLE_BASE) setTopAnimation(ANIM_IDLE_TOP);
			else
			{
				setTopAnimation(ANIM_RUN_TOP);
				mAnims[ANIM_RUN_TOP]->setTimePosition(mAnims[ANIM_RUN_BASE]->getTimePosition());
			}
		}

		// don‘t sway hips from side to side when slicing. that‘s just embarrassing.
		if (mBaseAnimID == ANIM_IDLE_BASE) baseAnimSpeed = 0;
	}
	else if (mBaseAnimID == ANIM_JUMP_START)
	{
		if (mTimer >= mAnims[mBaseAnimID]->getLength())
		{
			// takeoff animation finished, so time to leave the ground!
			setBaseAnimation(ANIM_JUMP_LOOP, true);
			// apply a jump acceleration to the character
			mVerticalVelocity = JUMP_ACCEL;
		}
	}
	else if (mBaseAnimID == ANIM_JUMP_END)
	{
		if (mTimer >= mAnims[mBaseAnimID]->getLength())
		{
			// safely landed, so go back to running or idling
			if (mKeyDirection == Ogre::Vector3::ZERO)
			{
				setBaseAnimation(ANIM_IDLE_BASE);
				setTopAnimation(ANIM_IDLE_TOP);
			}
			else
			{
				setBaseAnimation(ANIM_RUN_BASE, true);
				setTopAnimation(ANIM_RUN_TOP, true);
			}
		}
	}

	// increment the current base and top animation times
	if (mBaseAnimID != ANIM_NONE) mAnims[mBaseAnimID]->addTime(deltaTime * baseAnimSpeed);
	if (mTopAnimID != ANIM_NONE) mAnims[mTopAnimID]->addTime(deltaTime * topAnimSpeed);

	// apply smooth transitioning between our animations
	fadeAnimations(deltaTime);
}

void CharactorController::fadeAnimations(Ogre::Real deltaTime)
{
	for (int i = 0; i < NUM_ANIMS; i++)
	{
		if (mFadingIn[i])
		{
			// slowly fade this animation in until it has full weight
			Ogre::Real newWeight = mAnims[i]->getWeight() + deltaTime * ANIM_FADE_SPEED;
			mAnims[i]->setWeight(Ogre::Math::Clamp<Ogre::Real>(newWeight, 0, 1));
			if (newWeight >= 1) mFadingIn[i] = false;
		}
		else if (mFadingOut[i])
		{
			// slowly fade this animation out until it has no weight, and then disable it
			Ogre::Real newWeight = mAnims[i]->getWeight() - deltaTime * ANIM_FADE_SPEED;
			mAnims[i]->setWeight(Ogre::Math::Clamp<Ogre::Real>(newWeight, 0, 1));
			if (newWeight <= 0)
			{
				mAnims[i]->setEnabled(false);
				mFadingOut[i] = false;
			}
		}
	}
}

void CharactorController::updateCamera(Ogre::Real deltaTime)
{
	// place the camera pivot roughly at the character‘s shoulder
	mCameraPivot->setPosition(mBodyNode->getPosition() + Ogre::Vector3::UNIT_Y * CAM_HEIGHT);
	// move the camera smoothly to the goal
	Ogre::Vector3 goalOffset = mCameraGoal->_getDerivedPosition() - mCameraNode->getPosition();
	mCameraNode->translate(goalOffset * deltaTime * 9.0f);
	// always look at the pivot
	mCameraNode->lookAt(mCameraPivot->_getDerivedPosition(), Ogre::Node::TS_WORLD);
}

void CharactorController::updateCameraGoal(Ogre::Real deltaYaw, Ogre::Real deltaPitch, Ogre::Real deltaZoom)
{
	mCameraPivot->yaw(Ogre::Degree(deltaYaw), Ogre::Node::TS_WORLD);

	// bound the pitch
	if (!(mPivotPitch + deltaPitch > 25 && deltaPitch > 0) &&
		!(mPivotPitch + deltaPitch < -60 && deltaPitch < 0))
	{
		mCameraPivot->pitch(Ogre::Degree(deltaPitch), Ogre::Node::TS_LOCAL);
		mPivotPitch += deltaPitch;
	}

	Ogre::Real dist = mCameraGoal->_getDerivedPosition().distance(mCameraPivot->_getDerivedPosition());
	Ogre::Real distChange = deltaZoom * dist;

	// bound the zoom
	if (!(dist + distChange < 8 && distChange < 0) &&
		!(dist + distChange > 25 && distChange > 0))
	{
		mCameraGoal->translate(0, 0, distChange, Ogre::Node::TS_LOCAL);
	}
}

void CharactorController::setBaseAnimation(AnimID id, bool reset)
{
	if (mBaseAnimID >= 0 && mBaseAnimID < NUM_ANIMS)
	{
		// if we have an old animation, fade it out
		mFadingIn[mBaseAnimID] = false;
		mFadingOut[mBaseAnimID] = true;
	}

	mBaseAnimID = id;

	if (id != ANIM_NONE)
	{
		// if we have a new animation, enable it and fade it in
		mAnims[id]->setEnabled(true);
		mAnims[id]->setWeight(0);
		mFadingOut[id] = false;
		mFadingIn[id] = true;
		if (reset) mAnims[id]->setTimePosition(0);
	}
}

void CharactorController::setTopAnimation(AnimID id, bool reset)
{
	if (mTopAnimID >= 0 && mTopAnimID < NUM_ANIMS)
	{
		// if we have an old animation, fade it out
		mFadingIn[mTopAnimID] = false;
		mFadingOut[mTopAnimID] = true;
	}

	mTopAnimID = id;

	if (id != ANIM_NONE)
	{
		// if we have a new animation, enable it and fade it in
		mAnims[id]->setEnabled(true);
		mAnims[id]->setWeight(0);
		mFadingOut[id] = false;
		mFadingIn[id] = true;
		if (reset) mAnims[id]->setTimePosition(0);
	}
}


基于Ogre的角色控制器

标签:

原文地址:http://blog.csdn.net/silangquan/article/details/43835395

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!