终于迎来了自己的最后一个游戏,RPG冒险游戏,这个应该也是当前在单机领域最火的游戏类型了吧,丰富的剧情配上动听的音乐,在加上华丽的画面和带劲的打斗,实在是一个让人心旷神怡的游戏啊,本文旨在塑造一个简单的rpg游戏,希望和大家一起分享这美妙的游戏编程世界。
当前的大部分rpg游戏都是以第三人称视角作为基础的,这个和第一人称略有不同,在Camera的构建上也不尽相同,所以我带大家走进第三人称视角的世界。
class CDXThirdCamera
{
public:
void Create(D3DXVECTOR3 vEye,D3DXVECTOR3 vAt);
void RorateY(float fAngle);
void RorateAxis(float fAngle);
void Scale(float fParam);
void GetTransform(D3DXMATRIX *Matrix);
void Walk(float fWalk);
void Left(float fLeft);
D3DXVECTOR3 GetEye();
D3DXVECTOR3 GetAt();
void SetEyeHeight(float iY);
void SetAtHeight(float iY);
void SetEye(D3DXVECTOR3 Eye);
void SetAt(D3DXVECTOR3 At);
private:
D3DXVECTOR3 m_vEye;
D3DXVECTOR3 m_vAt;
};
第三人称视角需要满足哪些需求,视角的水平旋转,视角的垂直旋转和视角的缩放,于是便有了RotateY,RotateAxis和Scale三个函数,还要注意这里有两个成员变量:
D3DXVECTOR3 m_vEye;
D3DXVECTOR3 m_vAt;
m_vEye代表玩家视角,就是当前Camera所处的位置,而m_vAt便是需要观察的点,说白了就是游戏里玩家操控的人物所处的位置,这样,有了Eye和At便可以形成一个视图矩阵了。
那么我们首先来看下RotateY是怎么实现的:
void CDXThirdCamera::RotateY( float fAngle )
{
D3DXMATRIX mat,matY,matTrans;
D3DXMatrixTranslation(&mat,-m_vAt.x,-m_vAt.y,-m_vAt.z);
D3DXMatrixRotationY(&matY,fAngle*D3DX_PI/180);
D3DXMatrixTranslation(&matTrans,m_vAt.x,m_vAt.y,m_vAt.z);
mat=mat*matY*matTrans;
D3DXVec3TransformCoord(&m_vEye,&m_vEye,&mat);
}
大家可以看到,我这里没有自己计算,而是全部用了D3DX的函数来做的,首先将当前用户平移玩家视角所在的位置平移,以使玩家的观察点位于原点,然后让Y轴旋转一定角度,最后在平移回来,这样我们就可以产生玩家视角围绕当前人物(观察点)旋转的效果。好,我们再看一下 RotateAxis函数是怎么实现的:
void CDXThirdCamera::RotateAxis( float fAngle )
{
D3DXVECTOR3 u=m_vEye-m_vAt;
D3DXVECTOR3 v=D3DXVECTOR3(m_vAt.x,0,m_vAt.z)-m_vAt;
D3DXVECTOR3 out;
D3DXVec3Cross(&out,&u,&v);
D3DXVec3Normalize(&out,&out);
D3DXMATRIX mat,matAxis,matTrans;
D3DXMatrixTranslation(&mat,-m_vAt.x,-m_vAt.y,-m_vAt.z);
D3DXMatrixRotationAxis(&matAxis,&out,fAngle*D3DX_PI/180);
D3DXMatrixTranslation(&matTrans,m_vAt.x,m_vAt.y,m_vAt.z);
mat=mat*matAxis*matTrans;
D3DXVec3TransformCoord(&m_vEye,&m_vEye,&mat);
}
垂直旋转的话相对来说比较复杂,但是我仔细分析下原理也很简单,首先我们根据观察点到用户视角的向量与婧观察点并且垂直于XZ平面的向量做叉乘,得到的便是垂直于这两条向量的一条向量,然后利用D3DXMatrixRotationAxis这样一个旋转轴函数便可以得出新的玩家视角位置。最后我们看一下Scale缩放视角是怎么实现的:
void CDXThirdCamera::Scale( float fParam )
{
D3DXVECTOR3 vScale=m_vAt-m_vEye;
m_vEye+=vScale*(1-fParam);
}
缩放的操作很简单,没有用到什么函数,就是一个简单的插值处理而已,效果还不错。好了,下面我们继续介绍Walk是如何实现的:
void CDXThirdCamera::Walk( float fWalk )
{
D3DXVECTOR2 Normal=D3DXVECTOR2(m_vAt.x,m_vAt.z)-D3DXVECTOR2(m_vEye.x,m_vEye.z);
D3DXVec2Normalize(&Normal,&Normal);
m_vAt+=D3DXVECTOR3(fWalk*Normal.x,0,fWalk*Normal.y);
m_vEye+=D3DXVECTOR3(fWalk*Normal.x,0,fWalk*Normal.y);
}
因为行走只是在x和z方向上的位移(y上也会有移动,但必须根据地图来算出当前x和z所处的位置y的大小),所以我们只要构建一个二维方向向量,单位化后它的长度便为1,然后和当前的Eye和At相加下便可得到新的位置大小了。于是Walk(1)便是向前走,那么 Walk(-1)便是向后走了,这样就可以少写一个函数了。最后我们再来看下Left是如何实现的:
void CDXThirdCamera::Left( float fLeft )
{
D3DXVECTOR3 u=m_vEye-m_vAt;
D3DXVECTOR3 v=D3DXVECTOR3(m_vAt.x,0,m_vAt.z)-m_vAt;
D3DXVECTOR3 out;
D3DXVec3Cross(&out,&u,&v);
D3DXVec3Normalize(&out,&out);
m_vAt+=D3DXVECTOR3(fLeft*out.x,0,fLeft*out.z);
m_vEye+=D3DXVECTOR3(fLeft*out.x,0,fLeft*out.z);
}
有了上面的基础,这段代码我相信大家应该很容易就可以看懂了吧。恩,下一节我将带给大家的是rpg游戏里战斗部分的重点:粒子系统。
本文有不足之处,还望大家多多指正。