首页 > 代码库 > 游戏框架其九:WASD方向控制 { MovementController }

游戏框架其九:WASD方向控制 { MovementController }

下面实现的方向控制是基于键盘上的W A S D,来控制运动物体的方向的。下面是实现~

#pragma once
//========================================================================
// File: MovementController.h 就是实现键盘按钮 WASD 的方向控制
//========================================================================

#include "../GameCode4/Interfaces.h"
#include "Geometry.h"


// Forward declarations
class SceneNode;

typedef unsigned int  DWORD;
typedef unsigned short WORD;
typedef unsigned char  BYTE;
typedef unsigned int  ActorId;
typedef unsigned int  GameViewId;
typedef D3DXCOLOR     Color;
typedef float         FLOAT;
typedef unsigned int  UINT;
#ifdef   UNICODE
typedef wchar_t       TCHAR;
#else
typedef unsigned char TCHAR;
#endif
typedef unsigned char CHAR;
typedef unsigned wchar_t WCHAR;
enum HRESULT
{
    E_INVALIDARG,
    E_FAIL,
    S_OK,
};

////////////////////////////////////////////////////
//
// MovementController Description
//
//    Implements a WASD style movement controller
//
//  class MovementController		
//
////////////////////////////////////////////////////

class IPointerHandler
{
public:
    virtual bool VOnPointerMove(const Point &pos, const int radius) = 0;
    virtual bool VOnPointerButtonDown(const Point &pos, const int radius, const std::string &buttonName) = 0;
    virtual bool VOnPointerButtonUp(const Point &pos, const int radius, const std::string &buttonName) = 0;
};

class IKeyboardHandler
{
public:
    virtual bool VOnKeyDown(const BYTE c)=0;
    virtual bool VOnKeyUp(const BYTE c)=0;
};

class MovementController : public IPointerHandler, public IKeyboardHandler
{
protected:
	Mat4x4  m_matFromWorld;
	Mat4x4	m_matToWorld;
    Mat4x4  m_matPosition;

	Point					m_lastMousePos;
	bool					m_bKey[256];			// Which keys are up and down

	// Orientation Controls
	float		m_fTargetYaw;
	float		m_fTargetPitch;
	float		m_fYaw;
	float		m_fPitch;
	float		m_fPitchOnDown;
	float		m_fYawOnDown;
	float		m_maxSpeed;
	float		m_currentSpeed;

	// Added for Ch19/20 refactor
	bool		m_mouseLButtonDown;
	bool		m_bRotateWhenLButtonDown;

	shared_ptr<SceneNode> m_object;

public:
	MovementController(shared_ptr<SceneNode> object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown);
	void SetObject(shared_ptr<SceneNode> newObject);

	void OnUpdate(DWORD const elapsedMs);

public:
	bool VOnPointerMove(const Point &mousePos, const int radius);
	bool VOnPointerButtonDown(const Point &mousePos, const int radius, const std::string &buttonName);
	bool VOnPointerButtonUp(const Point &mousePos, const int radius, const std::string &buttonName);

	bool VOnKeyDown(const BYTE c) { m_bKey[c] = true; return true; }
	bool VOnKeyUp(const BYTE c) { m_bKey[c] = false; return true; }

	const Mat4x4 *GetToWorld() { return &m_matToWorld; }
	const Mat4x4 *GetFromWorld() { return &m_matFromWorld; }	
};

//========================================================================
// File: MovementController.cpp
//========================================================================

#include "GameCodeStd.h"
#include "Geometry.h"
#include "MovementController.h"
#include "SceneNodes.h"


////////////////////////////////////////////////////
// MovementController Implementation
////////////////////////////////////////////////////

#define MAX(a, b) ((a) >= (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))

MovementController::MovementController(shared_ptr<SceneNode> object, float initialYaw, float initialPitch, bool rotateWhenLButtonDown)
: m_object(object)
{
	m_object->VGet()->Transform(&m_matToWorld, &m_matFromWorld);

	m_fTargetYaw = m_fYaw = RADIANS_TO_DEGREES(-initialYaw);
	m_fTargetPitch = m_fPitch = RADIANS_TO_DEGREES(initialPitch);

	m_maxSpeed = 30.0f;			// 30 meters per second
	m_currentSpeed = 0.0f;

	Vec3 pos = m_matToWorld.GetPosition();

	m_matPosition.BuildTranslation(pos);

    POINT ptCursor;
    GetCursorPos( &ptCursor );
	m_lastMousePos = ptCursor;

	memset(m_bKey, 0x00, sizeof(m_bKey));

	m_mouseLButtonDown = false;
	m_bRotateWhenLButtonDown = rotateWhenLButtonDown;
}

//
// MovementController::VOnPointerButtonDown
//
bool MovementController::VOnPointerButtonDown(const Point &mousePos, const int radius, const std::string &buttonName)
{
	if (buttonName == "PointerLeft")
	{
		m_mouseLButtonDown = true;

		// We want mouse movement to be relative to the position
		// the cursor was at when the user first presses down on
		// the left button
		m_lastMousePos = mousePos;
		return true;
	}
	return false;
}

bool MovementController::VOnPointerButtonUp(const Point &mousePos, const int radius, const std::string &buttonName)
{
	if (buttonName == "PointerLeft")
	{
		m_mouseLButtonDown = false;
		return true;
	}
	return false;
}


//  class MovementController::VOnMouseMove

bool MovementController::VOnPointerMove(const Point &mousePos, const int radius)
{
	// There are two modes supported by this controller.

	if (m_bRotateWhenLButtonDown)
	{
		// Mode 1 - rotate the view only when the left mouse button is down
		// Only look around if the left button is down
		if(m_lastMousePos!=mousePos && m_mouseLButtonDown)
		{
			m_fTargetYaw = m_fTargetYaw + (m_lastMousePos.x - mousePos.x);
			m_fTargetPitch = m_fTargetPitch + (mousePos.y - m_lastMousePos.y);
			m_lastMousePos = mousePos;
		}
	}
	else if(m_lastMousePos!=mousePos)
	{
		// Mode 2 - rotate the controller when the mouse buttons are up
		m_fTargetYaw = m_fTargetYaw + (m_lastMousePos.x - mousePos.x);
		m_fTargetPitch = m_fTargetPitch + (mousePos.y - m_lastMousePos.y);
		m_lastMousePos = mousePos;
	}

	return true;
}

//  class MovementController::OnUpdate

void MovementController::OnUpdate(DWORD const deltaMilliseconds)
{
	//if (m_bKey['Q'])
	//{
	//	// This code is a cheat to position the camera exactly in a given
	//	// spot so I can take screen shots!

	//	Mat4x4 camTranslate;
	//	D3DXMatrixTranslation(&m_matPosition, 8.847f, 7.055f, 11.618f);

	//	m_fTargetYaw = m_fYaw += -64.35f;
	//	m_fTargetPitch = m_fPitch = 28.57f;

	//	// Calculate the new rotation matrix from the camera
	//	// yaw and pitch.
	//	Mat4x4 matRot;
	//	D3DXMatrixRotationYawPitchRoll(&matRot, DEGREES_TO_RADIANS(m_fYaw), DEGREES_TO_RADIANS(m_fPitch), 0);

	//	// Create the new object-to-world matrix, and the
	//	// new world-to-object matrix. 
	//	D3DXMatrixMultiply(&m_matToWorld, &matRot, &m_matPosition);
	//	D3DXMatrixInverse(&m_matFromWorld, NULL, &m_matToWorld);

	//	m_object->VSetTransform(&m_matToWorld, &m_matFromWorld);
	//	return;
	//}

	bool bTranslating = false;
	Vec4 atWorld(0,0,0,0);
	Vec4 rightWorld(0,0,0,0);
	Vec4 upWorld(0,0,0,0);

	if (m_bKey['W'] || m_bKey['S'])
	{
		// In D3D, the "look at" default is always
		// the positive Z axis.
		Vec4 at = g_Forward4; 
		if (m_bKey['S'])
			at *= -1;

		// This will give us the "look at" vector 
		// in world space - we'll use that to move
		// the camera.
		atWorld = m_matToWorld.Xform(at);
		bTranslating = true;
	}

	if (m_bKey['A'] || m_bKey['D'])
	{
		// In D3D, the "right" default is always
		// the positive X axis.
		Vec4 right = g_Right4; 
		if (m_bKey['A'])
			right *= -1;

		// This will give us the "right" vector 
		// in world space - we'll use that to move
		// the camera
		rightWorld = m_matToWorld.Xform(right);
		bTranslating = true;
	}

	if (m_bKey[' '] || m_bKey['C'] || m_bKey['X'])
	{
		// In D3D, the "up" default is always
		// the positive Y axis.
		Vec4 up = g_Right4; 
		if (!m_bKey[' '])
			up *= -1;

		//Unlike strafing, Up is always up no matter
		//which way you are looking
		upWorld = up;
		bTranslating = true;
	}

	//Handling rotation as a result of mouse position
	{
		// The secret formula!!! Don't give it away!
		//If you are seeing this now, then you must be some kind of elite hacker!
		m_fYaw += (m_fTargetYaw - m_fYaw) * ( .35f );
		m_fTargetPitch = MAX(-90, MIN(90, m_fTargetPitch));
		m_fPitch += (m_fTargetPitch - m_fPitch) * ( .35f );

		// Calculate the new rotation matrix from the camera
		// yaw and pitch.
		Mat4x4 matRot;
		matRot.BuildYawPitchRoll(DEGREES_TO_RADIANS(-m_fYaw), DEGREES_TO_RADIANS(m_fPitch), 0);

		// Create the new object-to-world matrix, and the
		// new world-to-object matrix. 

		m_matToWorld = matRot * m_matPosition;
		m_matFromWorld = m_matToWorld.Inverse(); 
		m_object->VSetTransform(&m_matToWorld, &m_matFromWorld);
	}

	if (bTranslating)
	{
		float elapsedTime = (float)deltaMilliseconds / 1000.0f;

		Vec3 direction = atWorld + rightWorld + upWorld;
		direction.Normalize(); 

		// Ramp the acceleration by the elapsed time.
		float numberOfSeconds = 5.f;
		m_currentSpeed += m_maxSpeed * ( (elapsedTime*elapsedTime) / numberOfSeconds);
		if (m_currentSpeed > m_maxSpeed)
			m_currentSpeed = m_maxSpeed;

		direction *= m_currentSpeed;

		Vec3 pos = m_matPosition.GetPosition() + direction;
		m_matPosition.SetPosition(pos);
		m_matToWorld.SetPosition(pos);

		m_matFromWorld = m_matToWorld.Inverse();
		m_object->VSetTransform(&m_matToWorld, &m_matFromWorld);
	}
	else
	{
		m_currentSpeed = 0.0f;
	}
}
以上是方向实现,下一篇是关于场景和场景节点( Scene , SceneNode )~~

游戏框架其九:WASD方向控制 { MovementController }