Creator2D横版游戏(3)完结篇:敌人追着主角打的AI

前两期做好了主角左右移动和背景的移动
请添加图片描述
本期目标(敌人追着主角打)
请添加图片描述
把敌人的spine拖动到canvas下
在这里插入图片描述
新建FoeAI脚本,挂在敌人的spine节点上
在这里插入图片描述
和主角的Player脚本一样,先撸一个枚举,和主角脚本相比多了一个attack(攻击)

// 状态
// 左走 右走 静止 攻击
export enum State{
    left, right, idle, attack,
};

所需属性

	@property({displayName: "敌人", tooltip: "敌人,其实就是自己", type: sp.Skeleton})
    foe: sp.Skeleton = null;


    @property({displayName: "玩家节点", tooltip: "玩家节点", type: Node})
    player: Node = null;


    @property({displayName: "静止动画名称", tooltip: "静止动画名称"})
    idle_anim_name: string = "stand";

    @property({displayName: "行走动画名称", tooltip: "行走动画名称"})
    walk_anim_name: string = "celebrate";

    @property({displayName: "攻击动画名称", tooltip: "攻击动画名称"})
    attack_anim_name: string = "attack";


    @property({displayName: "行走速度", tooltip: "行走速度", type: CCFloat})
    walk_speed: number = 80;

    @property({displayName: "怪物走到哪里时停下攻击人物", tooltip: "怪物走到距离人物哪里时停下攻击人物", type: CCFloat})
    dis: number = 80;

    // 开始时状态是静止
    state = State.idle;

update和Player脚本差不多
节点X缩放(就是更改朝向)单放出来了

	update (dt: number) {
        // 如果状态为静止
        if (this.state == State.idle) {
            // 如果动画不为静止
            if (this.foe.animation != this.idle_anim_name) {
                // 动画为静止
                this.foe.animation = this.idle_anim_name;
            }
        }
        // 如果状态为左走 
        else if (this.state == State.left) {
            // 如果动画不为走路
            if (this.foe.animation != this.walk_anim_name) {
                // 动画为走路
                this.foe.animation = this.walk_anim_name;
            }

            // 移动
            let pos = this.foe.node.position;
            this.foe.node.setPosition(pos.x - this.walk_speed * dt, pos.y);
        }
        // 如果状态为右走 
        else if (this.state == State.right) {
            // 如果动画不为走路
            if (this.foe.animation != this.walk_anim_name) {
                // 动画为走路
                this.foe.animation = this.walk_anim_name;
            }

            // 移动
            let pos = this.foe.node.position;
            this.foe.node.setPosition(pos.x + this.walk_speed * dt, pos.y);
        }
        // 如果状态为攻击
        else if (this.state == State.attack) {
            // 如果动画不为攻击
            if (this.foe.animation != this.attack_anim_name) {
                // 动画为攻击
                this.foe.animation = this.attack_anim_name;
            }
        }

        if (this.foe.node.position.x > this.player.position.x) {
            // 人物缩放
            this.foe.node.setScale(new Vec3(-0.6, 0.6, 1));
        } else if (this.foe.node.position.x < this.player.position.x) {
            // 人物缩放
            this.foe.node.setScale(new Vec3(0.6, 0.6, 1));
        }


    }

主角的Player脚本是通过给按钮绑定事件控制state的更改
不可能弄出两个按钮控制敌人,那就是自己和自己玩了,没有任何意思
所以,必须用代码控制state才可以

之前定义了一个名为dis的属性,这个属性就是实现代码控制敌人状态的关键,很重要,也非常方便,可以直接在编辑器修改理想的值
在这里插入图片描述
在这里插入图片描述
在update添加以下代码,就完成了用代码控制敌人的状态
仔细体会体会下面的代码,很巧妙

		// 怪物X减去主角X
        let dis = this.foe.node.position.x - this.player.position.x;
        // 如果在右侧
        if (dis > this.dis) {
            // 状态为左走
            this.state = State.left;
        }
        // 如果在左侧 
        else if (dis < -this.dis) {
            // 状态为右走
            this.state = State.right;
        } 
        // 如果上面两种都不是
        else {
            // 状态为攻击
            this.state = State.attack;
        }

其实这些在我之前开源的游戏精灵大陆里面都有,只是觉得背景移动和敌人追着打比较在2D横版游戏比较常用而且比较难写(大于小于加减乘除判定很多,并不是代码有多难),所以才单独拿出来写一写

《精灵大陆》论坛链接:https://forum.cocos.org/t/topic/113520/10
《精灵大陆》源码:https://gitee.com/propertygame/sprite_-land

完结

源码:https://gitee.com/propertygame/cocos-creator3.x-demos/tree/master/2Dhorizontal
技术交流Q群:1130122408
更多内容请关注微信公众号
请添加图片描述

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐