2D游戏中角色模型移动实现方式

大部分游戏中都有移动模型的需求,要移动模型,首先要获取到模型要走的路线,路线就是一个个节点的坐标构成的数组,然后根据数组中的每一个元素,依次并将模型的位置更新,也就是设置模型的x,y值(相对于屏幕笛卡尔坐标系中的横纵坐标值)。

一般的,想要更加真实的表现出人物移动的效果,可以模拟加速,减速。就需要在设计上加上一个属性。

速度 – speed;

根据 S = V * T; 距离 = 速度 * 时间;可以计算出当前帧移动的距离,根据距离再求出相应x,y轴移动的分量,达到一个移动的目的。
这就是一个根据直角三角形斜边长,和斜边的斜率,求两条直角边的长度的问题。这又涉及到一个求角度的问题。

下面要介绍一个不需要求角度的实现方式。

相似三角形

在这里插入图片描述
将当前模型所在位置置为坐标系原点O,B为目标点位置,OB的模长就是当前位置到目标点的距离。
OD是当前帧移动的距离,那么根据上图的辅助线CD,AB易得,

(1)OC的距离是x分量移动的距离,CD的距离是y分量移动的距离;
(2)▲OCD与▲OAB相似;

那么,根据相似三角形的性质,得出

OC / OA = CD / AB = OD / OB;

令D(mx,my),则

mx / dx = my / dy = OD / OB;

OD可以根据时间 * 速度得出,OB可以根据勾股定理求出。
那么OC和CD的距离,也就是mx,my也可求出
令f = OD / OB;

mx = f * dx;
my = f * dy;

这边的代码是根据cocoscreator引擎来写的。这个没有限制,方法是通用的。
具体实现代码如下:

const {ccclass, property} = cc._decorator;
enum Direction{
    UP,
    UP_RIGHT,
    RIGHT,
    DOWN_RIGHT,
    DOWN,
    DOWN_LEFT,
    LEFT,
    UP_LEFT
}
@ccclass
export default class Avartar extends cc.Component {
    start () {
    }
    /**
     * 人物移动的速度
     */
    private _speed:number = 10;
    get speed(){
        return this._speed;
    }
    /**
     * 使用set方法设置speed,可以根据速度的不同值,播放动画不同的动作
     * 比如切换行走,跑动和站立的动作
     */
    set speed(value:number){
        if(value === this._speed)return;
        this._speed = value;
    }
    /**
     * 人物当前路径
     */
    private _path:cc.Vec2[] = [];
    /**
     * 当前目标点,是即将要走到的目标点
     * 并非最终目的地
     */
    private _curTargetPosition:cc.Vec2;
    /**
    * 模型方向
    */
    private _dir:Direction;
    get dir(){
        return this._dir;
    }
    /**
     * 可以在set方法里做更多关于方向更新的操作
     */
    set dir(value:number){
        if(value === this._dir)return;
        this._dir = value;
    }

    /**
     * cocos提供的回调函数,每帧都会执行
     * @param dt 当前帧执行的时间,是执行一帧所需要的时间,单位是秒
     * 一般60帧的刷新频率下,dt的值约为1 / 60;
     */
    update (dt:number) {
        this.loopMove(dt);
    }
    /**
     * 每帧更新移动
     * @param dt 
     */
    loopMove(dt:number){
        //当速度为0时,不需要执行下面代码。因为不会移动
        if(!this.speed) return;
        //速度*时间,求出当前帧移动的距离,就是图中OD的距离
        let frameDistance = dt * this.speed;
        //求出图中B点的坐标值(dx,dy)
        let dx = this._curTargetPosition.x - this.node.x;
        let dy = this._curTargetPosition.y - this.node.y;
        //求出当前位置与目标位置的距离,也就是图中OB的距离
        let distance = Math.sqrt(dx * dx + dy * dy);
        // OD / OB,就是相似三角形的比例
        let f = frameDistance / distance;
        // 根据比例增加坐标值,至此单帧移动完成
        this.node.x += f * dx;
        this.node.y += f * dy;
        //判断是否到达当前目的地,因为js里数字类型都是浮点型保存,所以在判断的时候需要进行取整。
        if(this.node.x >> 0 === this._curTargetPosition.x 
        && this.node.y === this._curTargetPosition.y){
            this.doMoveNextPosition();
        }
    }
    /**
     * 移动下一个目标点
     */
    doMoveNextPosition(){
        if(this._path && this._path.length){
            this._curTargetPosition = this._path.shift();
            this.speed = 20;
            //更换目标点的时候需要更新模型方向
            this.updateDir();
        }else{
            this.speed = 0;
        }
    }

    updateDir(){
        this.dir = this.getDirection(this.node.getPosition(),this._curTargetPosition);
    }

    /**
     * 设置路径
     * @param path 路径点数组
     */
    setPath(path:cc.Vec2[]){
        this._path = path;
        this.doMoveNextPosition();
    }

    getDirection(curPoint:cc.Vec2,targetPoint:cc.Vec2){
        //先得到当前位置与目标位置形成的向量(dx,dy);
        let dx = targetPoint.x - curPoint.x;
        let dy = targetPoint.y - curPoint.y;
        //当向量的X分量为0时,y分量 > 0则为上方向,反之为下方向,
        //因为下方向是正对准屏幕的方向,所以Y分量等于0时也是下方向。让玩家可以直接看到正脸
        if(dx === 0){
            return dy > 0 ? Direction.UP : Direction.DOWN;
        }
        //当向量的Y分量为0时,X分量 >= 0则为右向(因为个人觉得右向看起来比较舒服,所以在为0时也是右向)
        //反之为左向
        if(dy === 0){
            return dx >= 0 ? Direction.RIGHT : Direction.LEFT;
        }

        let ddy = dy / dx;
        if(ddy >= 2.414){
            return Direction.UP;
        }else if(ddy >= 0.414 && ddy < 2.414){
            return dx > 0 ? Direction.UP_RIGHT : Direction.UP_LEFT;
        }else if(ddy >= -2.414 && ddy < 0.414){
            return dx > 0 ? Direction.DOWN_RIGHT : Direction.DOWN_LEFT;
        }
        return Direction.DOWN;
    }

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Unity3D/2D游戏开发从0到1》是一本由刘国柱著的完整版书籍,主要介绍了使用Unity3D/2D进行游戏开发的全过程。 本书首先从Unity3D/2D的基础知识入手,介绍了Unity的界面、组件、场景布置等概念和基本操作。接着,书详细讲解了游戏对象和组件的概念,以及如何使用Unity编辑器进行场景的设计和制作。 在游戏开发的过程,素材的使用是不可忽视的一部分。本书介绍了如何使用Unity自带的资源以及如何导入外部素材,包括模型、纹理、音效等。同时,还讲解了如何对素材进行编辑、处理和优化,以使游戏的性能和质量达到最佳效果。 本书还深入介绍了Unity的脚本编程,包括C#脚本的基础语法、面向对象编程、游戏逻辑的设计和实现等。通过学习脚本编程,读者可以掌握如何创建角色控制、敌人AI、游戏界面、游戏场景等游戏元素,并将它们组合成一个完整的游戏。 此外,本书还介绍了Unity的物理引擎和碰撞系统的使用方法,以及如何实现游戏的各种物理效果。同时,还讲解了基于时间和事件的游戏控制方法,包括计时器、动画控制等。 最后,本书还介绍了一些高级技术和工具,如光照和阴影效果、粒子效果、手机和VR游戏开发等。这些内容可以帮助读者更深入地理解Unity的功能和应用,提高游戏的质量和用户体验。 总之,《Unity3D/2D游戏开发从0到1》是一本适合初学者入门的教程书籍,通过学习本书,读者可以全面掌握Unity3D/2D开发流程和技术,从零到一独立完成一个游戏项目。 ### 回答2: 《Unity3D/2D游戏开发从0到1》是刘国柱编著的一本游戏开发入门书籍。本书以Unity3D/2D开发工具,全面介绍了从零开始进行游戏开发的过程和技巧。 书籍内容包括了基础知识、项目搭建、角色设计、场景构建、物体控制、游戏逻辑、音效与动画、UI界面、碰撞检测等方面。作者结合具体实例,详细讲解了如何用Unity3D/2D从头开始制作游戏。 在基础知识部分,作者介绍了Unity3D/2D的基本操作和界面布局,帮助读者快速上手。接着,作者通过一个个简单的小项目,引导读者逐步学习和掌握游戏开发的流程和技巧。通过实操的方式,读者可以逐步实现一个完整的游戏项目。 在角色设计和场景构建方面,作者介绍了如何使用Unity提供的各种工具和组件来创建游戏场景和角色。同时,作者还探讨了如何使用脚本语言来控制游戏对象的行为,包括移动、跳跃、攻击等动作。 在游戏逻辑部分,作者引导读者学习如何设计游戏规则和关卡,以及如何实现游戏的各种功能,如计分系统、任务系统等。作者还介绍了如何使用动画和音效来增加游戏的视听效果。 在UI界面和碰撞检测方面,作者详细讲解了如何创建游戏界面和按钮,以及如何处理游戏的碰撞事件和碰撞检测。这些内容对于游戏的交互和玩法设计非常重要。 总体来说,这本书具有循序渐进、案例丰富、操作实用的特点,非常适合初学者入门和了解Unity3D/2D游戏开发。无论是想自己制作小游戏,还是进一步深入学习游戏开发技术,这本书都是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值