• D3D游戏编程系列(六):自己动手编写第一人称射击游戏之第一人称视角的构建


            说起第一人称射击游戏,不得不提第一人称视角啊,没有这个,那么这个第一就无从谈起啊,我作为一个观察者究竟如何在这个地图上顺利的移动和观察呢,那么,我们一起来研究下。

           我们首先来看下CDXCamera类:

    class CDXCamera
    {
    public:
    	void Go(float fLen);      //前进
    	void Back(float fLen);       //后退
    	void Up(float fLen);        //上升
    	void Down(float fLen);          //下降
    	void Left(float fLen);        //左移
    	void Right(float fLen);     //右移
    	void TurnLeft(float fAngle);       //向左转
    	void TurnRight(float fAngle);      //向右转
    	void TurnUp(float fAngle);        //向上看
    	void TurnDown(float fAngle);        //向下看
    	void Reset(CDXWindow *pWin,D3DXVECTOR3 vEye,D3DXVECTOR3 vAt);  //初始化
    	void SetTransForm();        //设置取景变换
    	D3DXVECTOR3 GetEye();
    	D3DXVECTOR3 GetAt();
    	float GetX();
    	float GetY();
    	float GetZ();
    	float GetRightAngle();      //水平转向的角度
    	float GetUpAngle();              //垂直转向的角度
    protected:
    	LPDIRECT3DDEVICE9 m_pDevice;
    	D3DXVECTOR3 m_vEye; 
    	D3DXVECTOR3 m_vAt; 
    	D3DXVECTOR3 m_vUp;
    	float m_fRightAngle;
    	float m_fUpAngle;
    	float m_fRad;
    };

            上面的这个类我相信大家应该明白个大概了吧,其实在DX的龙书上就有关于Camera的叙述,不过我这里和他的实现有点不同。我们首先来看一下这个Camera是如何创建的:

    void CDXCamera::Reset(CDXWindow *pWin,D3DXVECTOR3 vEye,D3DXVECTOR3 vAt)
    {
    	m_pDevice=pWin->GetD3dDevice();
    	D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f);
    	m_vUp=vUp;
    	m_vEye=vEye;
    	m_vAt=vAt;
    	m_fRad=sqrtf(powf(m_vAt.x-m_vEye.x,2)+powf(m_vAt.z-m_vEye.z,2));
    	m_fRightAngle=acos((m_vAt.z-m_vEye.z)/m_fRad)*180/D3DX_PI;
    	if((m_vAt.x-m_vEye.x)/m_fRad<0)
    	{
    		m_fRightAngle=360-m_fRightAngle;
    	}
    	cout<<m_fRightAngle<<endl;
    	m_fUpAngle=atan((m_vAt.y-m_vEye.y)/m_fRad)*180/D3DX_PI;
    }


           大家可以看到,我在处理水平角度上做了一个判断,因为是360度都可以旋转,所以直接去计算cos会有问题,我这里先判断sin的值,再决定角度是在0到180度还是180度到360度。那么我们要往前走一步,这个又是如何实现的呢,假设行走的距离为fLen个长度,那么便有如下代码:

    float x,z;
    x=fLen*sin(m_fRightAngle*(D3DX_PI/180.0f));
    z=fLen*cos(m_fRightAngle*(D3DX_PI/180.0f));
    m_vEye.x+=x;
    m_vEye.z+=z;
           是不是很简单的就解决这个问题了呢,好,接下去,我们假设要向左旋转fAngle个角度,该怎么办呢:

    float x,z;
    float fTempAngle=m_fRightAngle;
    m_fRightAngle-=fAngle;
    if(m_fRightAngle<0)
    {
    m_fRightAngle=360+fTempAngle-fAngle;
    }


    x=m_fRad*sin(m_fRightAngle*(D3DX_PI/180.0f));
    z=m_fRad*cos(m_fRightAngle*(D3DX_PI/180.0f));
    m_vAt.x=m_vEye.x+x;
    m_vAt.z=z+m_vEye.z;

           首先我们判断旋转后的角度是否在0到360度之间,否则调整角度,然后计算出需要需要移动的x和z的大小,然后和当前的Eye相加,便是新的At位置。于是我们就完成了旋转。依次类推,其他方法也是这样实现的。

            在这个CDXCamera构建完成后,如何应用到我们的游戏中去呢,那么就是在游戏的逻辑帧里面做判断,如果当前没有和墙壁以及其他人物碰撞的话,便行走,同时把人物的骨骼动画移动到当前Camera的位置,否则原地不动。还有一点的就是如何用鼠标控制观察视角的上下左右呢,大家应该还记得DIMOUSESTATE这个对象吧:

    typedef struct _DIMOUSESTATE {
        LONG    lX;
        LONG    lY;
        LONG    lZ;
        BYTE    rgbButtons[4];
    } DIMOUSESTATE, *LPDIMOUSESTATE;

             lX,lY,lZ便是相对于上次移动的相对坐标,我们只要去判断这个相对坐标的大小,便可以去改变观察视角了。

    int iMouseX=DXMouseMickeyX();
    		int iMouseY=DXMouseMickeyY();
    		if(iMouseX>0)
    		{
    			m_Camera.TurnRight(iMouseX*0.1);
    			m_Player.SetMatrix(m_Camera.GetRightAngle(),m_Camera.GetEye(),m_fDeltaTime);
    			_SendPlayerPosMsg(&m_Player);
    		}else if(iMouseX<0)
    		{
    			m_Camera.TurnLeft(-iMouseX*0.1);
    			m_Player.SetMatrix(m_Camera.GetRightAngle(),m_Camera.GetEye(),m_fDeltaTime);
    			_SendPlayerPosMsg(&m_Player);
    		}
    		if(iMouseY>0)
    		{
    
    			m_Camera.TurnDown(iMouseY*0.1);
    			float fAngle=m_Camera.GetUpAngle();
    			if(fAngle<=270 && fAngle>=90)
    			{
    				m_Camera.TurnUp(270-fAngle+1);
    			}
    		}else if(iMouseY<0)
    		{
    
    			m_Camera.TurnUp(-iMouseY*0.1);
    			float fAngle=m_Camera.GetUpAngle();
    			if(fAngle<=270 && fAngle>=90)
    			{
    				m_Camera.TurnDown(fAngle-90+1);
    			}
    		}

           还是很简单的吧,最后我们clipwindow并且showcursor一下,便可以欺骗玩家眼睛,让玩家可以用鼠标随意控制上下左右视角的效果了。

           其实关于第一人称射击游戏还有很多的内容,我这里给大家留下一个小问题,就是如何去判断一个子弹是否击中对方了呢,我们怎么在子弹的运行轨迹中去识别墙壁这些障碍物呢,呵呵,其实是有一定数学小技巧的,大家想一想应该能想到的。

           本文有不足之处,还望大家多多指正。

  • 相关阅读:
    web服务之NginX介绍
    LVS介绍以及工作模式案例
    sersync 实现实时数据同步
    Java高并发20-并发包中锁原理解析(二)
    Java高并发19-并发包中锁原理解析(一)
    从零开始学VUE之VueRouter(导航守卫)
    从零开始学VUE之VueRouter(传递参数)
    从零开始学VUE之VueRouter(嵌套路由)
    从零开始学VUE之VueRouter(路由懒加载)
    从零开始学VUE之VueRouter(动态路由)
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3366046.html
Copyright © 2020-2023  润新知