关闭

使用Irrlicht构建游戏主角

标签: 游戏Irrlicht
613人阅读 评论(0) 收藏 举报
分类:

所谓游戏主角就是第三视角看到的在屏幕中间附近跑来跑去,然后周围景物随之变换的节点。

最终效果

实现的思路很简单,分为以下三步
1. 获取键盘输入
2. 移动主角,并且在需要的时候更改动画
3. 移动摄像机
这里的前提是周围环境相对世界坐标系不变。

那么使用Irrlicht怎么实现呢?一步一步来。

1. 获取键盘输入
自然就是重载我们的 IEventReceiver 类了,这部分大体思路可以参考教程 04.Movement 里面的实现:维护一个键位表,每个键值有两个状态(按下和没有按下),在键盘有信号时修改本表对应键值的状态,以便主渲染程序读取。


class MyEventReceiver : public IEventReceiver
{
public:

    MyEventReceiver()
    {
        for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
            KeyIsDown[i] = false;

        runContrlCounter = 0;
        pressKeyCounter = 0;
    }

    virtual bool OnEvent(const SEvent& event)
    {

        // 改变键位状态
        if (event.EventType == irr::EET_KEY_INPUT_EVENT){
            KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;

        }

        return false;
    }

    virtual bool IsKeyDown(EKEY_CODE keyCode) const
    {
        return KeyIsDown[keyCode];
    }

private:
    bool KeyIsDown[KEY_KEY_CODES_COUNT];
};

接下来第二步
2.移动角色并更改动画
本身这几个动作是比较简单的,但坑就坑在节点类 IAnimatedMeshSceneNode 居然是个抽象类,并且我没有找到合适的去继承它成为实体类的方法(如果有请告知)。那只能对这个类的系列操作封装在一个代理类 MyRoleDelegate 里面了。这个类里面有个 render() 函数用于从事件接收器中读取当前键盘状态并操作主节点。

有WASD操作的人物一共有八个方向,此时对应八种模型旋转变换(二维),也比较简单。附上代码

class MyRoleDelegate
{

public:

    MyRoleDelegate(IAnimatedMeshSceneNode* node_p, MyEventReceiver* receiver_p,
    IrrlichtDevice* device_p)
    :role(node_p), receiver(receiver_p), device(device_p)
    {
        init();

    }

    void init()
    {
        MOVEMENT_SPEED = 25.f;
        available = true;
        currentPosition = role->getPosition();
        setAnimationType(EMAT_STAND);
        //初始为站立动画
    }


    void setAnimationType(EMD2_ANIMATION_TYPE atype)
    {
        //避免重复设置同一个动作而造成卡顿
        if(currentAnimationType!=atype)
        {
            role->setMD2Animation(atype);
            currentAnimationType=atype;
        }
    }

    void render()
    {
        if(false)
        {
          //  setAnimationType(EMAT_STAND);
        }
        else
        {
            setAnimationType(EMAT_RUN);
            f32 frameDeltaTime = 0.1;

            currentPosition = role->getPosition();
            float move_distance = MOVEMENT_SPEED * frameDeltaTime;

            vector3df dir(0.0,-90,0); //角色的方向
            if(receiver->IsKeyDown(KEY_KEY_W))
            {
                dir.Y = -90;
                currentPosition.Z += move_distance*0.7;
                if(receiver->IsKeyDown(KEY_KEY_A))
                {   //WA 方向
                    dir.Y = -135;
                    currentPosition.X -= move_distance*0.7;
                }
                else if(receiver->IsKeyDown(KEY_KEY_D))
                {   //WD 方向
                    dir.Y = -45;
                    currentPosition.X += move_distance*0.7;
                }
                else
                {//W方向,以下类似
                    currentPosition.Z += move_distance*0.3;
                }
            }

            else if(receiver->IsKeyDown(KEY_KEY_S))
            {
                dir.Y = 90;
                currentPosition.Z -= move_distance*0.7;
                if(receiver->IsKeyDown(KEY_KEY_A))
                {
                    dir.Y = 135;
                    currentPosition.X -= move_distance*0.7;
                }
                else if(receiver->IsKeyDown(KEY_KEY_D))
                {
                    dir.Y = 45;
                    currentPosition.X += move_distance*0.7;
                }
                else
                {
                    currentPosition.Z -= move_distance*0.3;
                }
            }

            else if(receiver->IsKeyDown(KEY_KEY_A))
            {
                dir.Y = 180;
                currentPosition.X -= move_distance;
            }
            else if(receiver->IsKeyDown(KEY_KEY_D)){
                dir.Y = 360;
                currentPosition.X += move_distance;
            }
            else{
                dir = currentRotation;
                setAnimationType(EMAT_STAND);
            }

            if(dir != currentRotation){
                role->setRotation(dir);
                currentRotation = dir;
            }
            role->setPosition(currentPosition);
        }
    }


    vector3df getCameraPosition(){
        //设置此时相机应该处于的位置
        vector3df pos = currentPosition;
        pos.Y += 50;
        pos.Z -= 50;
        return pos;
    }

private:

    IrrlichtDevice* device; //主设备指针
    MyEventReceiver* receiver;//主类事件接收器
    IAnimatedMeshSceneNode* role;//所代理的节点指针

    bool available;
    EMD2_ANIMATION_TYPE currentAnimationType;
    vector3df currentPosition, currentRotation;;
    f32 MOVEMENT_SPEED;

};

另外,setAnimationType涉及更改动画的API,仅仅适用于MD2格式模型,如有其它需要请重载

第三步就最简单了,只需要在主渲染函数里面更改相机位置即可。

while(device->run())
{
    rDele->render(); //rDele 为主节点代理
    camera->setPosition(rDele->getCameraPosition());

    //其他渲染操作

当然,你还需要一个主Game类来初始化所有变量,载入模型,建立三角碎片选择器,加入碰撞检测与重力等等,就不在这里解释了。

最终的效果就是开头的那张动画。

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:12748次
    • 积分:284
    • 等级:
    • 排名:千里之外
    • 原创:15篇
    • 转载:0篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论