三种按键移动的方式

用Typescript在Cocos Creator里实现。

第一种实现方式

import { _decorator, Component, EventKeyboard, Input, input, KeyCode, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Controller')
export class Controller extends Component {
    //移动速度
    @property
    public moveSpeed: number = 100;

    //移动方向
    private _moveDirection: Vec3 = new Vec3(0, 0, 0);

    protected onLoad(): void {
        //注册键盘事件监听
        input.on(Input.EventType.KEY_DOWN, this._onKeyDown, this);
        input.on(Input.EventType.KEY_UP, this._onKeyUp, this);
    }

    protected onDestroy(): void {
        //注销键盘事件监听
        input.off(Input.EventType.KEY_DOWN, this._onKeyDown, this);
        input.off(Input.EventType.KEY_UP, this._onKeyUp, this);
    }

    private _onKeyDown(event: EventKeyboard) {
        //只要事件发生,就会给_moveDirection添加方向
        switch (event.keyCode) {
            case KeyCode.KEY_W:
                this._moveDirection.y = 1;
                break;
            case KeyCode.KEY_S:
                this._moveDirection.y = -1;
                break;
            case KeyCode.KEY_A:
                this._moveDirection.x = -1;
                break;
            case KeyCode.KEY_D:
                this._moveDirection.x = 1;
                break;
        }
    }

    private _onKeyUp(event: EventKeyboard) {
        //只要事件发生,_moveDirection就会清零
        switch (event.keyCode) {
            case KeyCode.KEY_W:
            case KeyCode.KEY_S:
                this._moveDirection.y = 0;
                break;
            case KeyCode.KEY_A:
            case KeyCode.KEY_D:
                this._moveDirection.x = 0;
                break;
        }
    }

    protected update(deltaTime: number) {
        let movements = new Vec3(this._moveDirection.x * this.moveSpeed * deltaTime, this._moveDirection.y * this.moveSpeed * deltaTime, 0);
        this.node.setPosition(this.node.position.add(movements));
    }
}

这是最简单的实现方式,然而这种方式在键盘上的操作手感却是比较诡异的。比如,当按住了A键时,玩家操控的对象向左移动,此时不要松开A键按下D键,玩家操控的对象向右移动,然而在松开A键或D键的时候,明明移动的按键还在按着,玩家操控的对象却定住不动了。其实仔细阅读代码可以发现,这是因为当玩家松开按键的时候触发了_onKeyUp,使得_moveDirection.x清零了,然而此时由于A键一直是按住的状态,并没有触发_onKeyDown,所以_moveDirection.x的值一直是0。
不过如果用的是手柄或者摇杆,由于左右键或上下键并不能同时按下,就不会产生这样的诡异现象。所以考虑键盘玩家,就需要对控制代码进行修改。

第二种实现方式

import { _decorator, Component, EventKeyboard, Input, input, KeyCode, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('Controller')
export class Controller extends Component {
    //移动速度
    @property
    public moveSpeed: number = 100;

    //移动方向
    private _moveDirection: Vec3 = new Vec3(0, 0, 0);

    //添加标志位,分开记录方向键的按下状态
    private _isUpPressed: boolean = false;
    private _isDownPressed: boolean = false;
    private _isLeftPressed: boolean = false;
    private _isRightPressed: boolean = false;

    protected onLoad(): void {
        //注册键盘事件监听
        input.on(Input.EventType.KEY_DOWN, this._onKeyDown, this);
        input.on(Input.EventType.KEY_UP, this._onKeyUp, this);
    }

    protected onDestroy(): void {
        //注销键盘事件监听
        input.off(Input.EventType.KEY_DOWN, this._onKeyDown, this);
        input.off(Input.EventType.KEY_UP, this._onKeyUp, this);
    }

    private _onKeyDown(event: EventKeyboard) {
        //只要事件发生,就改变标志位的状态为true
        switch (event.keyCode) {
            case KeyCode.KEY_W:
                this._isUpPressed = true;
                break;
            case KeyCode.KEY_S:
                this._isDownPressed = true;
                break;
            case KeyCode.KEY_A:
                this._isLeftPressed = true;
                break;
            case KeyCode.KEY_D:
                this._isRightPressed = true;
                break;
        }
        //在有按键按下的时候,更新_moveDirection
        this._updateMoveDirection();
    }

    private _onKeyUp(event: EventKeyboard) {
        //只要事件发生,就改变标志位的状态为false
        switch (event.keyCode) {
            case KeyCode.KEY_W:
                this._isUpPressed = false;
                break;
            case KeyCode.KEY_S:
                this._isDownPressed = false;
                break;
            case KeyCode.KEY_A:
                this._isLeftPressed = false;
                break;
            case KeyCode.KEY_D:
                this._isRightPressed = false;
                break;
        }
        //在有按键松开的时候,更新_moveDirection
        this._updateMoveDirection();
    }

    protected update(deltaTime: number) {
        let movements = new Vec3(this._moveDirection.x * this.moveSpeed * deltaTime, this._moveDirection.y * this.moveSpeed * deltaTime, 0);
        this.node.setPosition(this.node.position.add(movements));
    }

    private _updateMoveDirection() {
        //根据按键的状态,更新_moveDirection的值
        this._moveDirection.x  = (this._isLeftPressed? -1 : 0) + (this._isRightPressed? 1 : 0);
        this._moveDirection.y  = (this._isUpPressed? -1 : 0) + (this._isDownPressed? 1 : 0);
    }
}

这种方式就解决了松开按键时,还在按着的按键失灵的情况。但这种实现方式有个特点,就是当A键和D键同时按下,或者当W键和S键同时按下时,玩家操控的对象会静止不动,有一点不太灵活,如果想要添加灵活性,希望玩家在按下A键的时候按下D键,操控的对象向右移动,此时松开D键,操控的对象回归向左移动的状态,那怎么实现呢。

第三种实现方式

import { _decorator, Component, EventKeyboard, Input, input, KeyCode, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

//记录方向的枚举
enum Direction {
    UP,
    DOWN,
    LEFT,
    RIGHT
}

@ccclass('Controller')
export class Controller extends Component {
    //移动速度
    @property
    public moveSpeed: number = 100;

    //移动方向
    private _moveDirection: Vec3 = new Vec3(0, 0, 0);

    //添加标志位,分开记录方向键的按下状态
    private _isUpPressed: boolean = false;
    private _isDownPressed: boolean = false;
    private _isLeftPressed: boolean = false;
    private _isRightPressed: boolean = false;

    //添加标志位,记住最后按下的方向
    private _lastVerticalDirection: Direction.UP | Direction.DOWN = null;
    private _lastHorizontalDirection: Direction.LEFT | Direction.RIGHT = null;

    protected onLoad(): void {
        //注册键盘事件监听
        input.on(Input.EventType.KEY_DOWN, this._onKeyDown, this);
        input.on(Input.EventType.KEY_UP, this._onKeyUp, this);
    }

    protected onDestroy(): void {
        //注销键盘事件监听
        input.off(Input.EventType.KEY_DOWN, this._onKeyDown, this);
        input.off(Input.EventType.KEY_UP, this._onKeyUp, this);
    }

    private _onKeyDown(event: EventKeyboard) {
        //只要事件发生,就改变标志位的状态为true,以及改变_lastVerticalDirection和_lastHorizontalDirection以记录最后按下的方向
        switch (event.keyCode) {
            case KeyCode.KEY_W:
                this._isUpPressed = true;
                this._lastVerticalDirection = Direction.UP;
                break;
            case KeyCode.KEY_S:
                this._isDownPressed = true;
                this._lastVerticalDirection = Direction.DOWN;
                break;
            case KeyCode.KEY_A:
                this._isLeftPressed = true;
                this._lastHorizontalDirection = Direction.LEFT;
                break;
            case KeyCode.KEY_D:
                this._isRightPressed = true;
                this._lastHorizontalDirection = Direction.RIGHT;
                break;
        }
        //在有按键按下的时候,更新_moveDirection
        this._updateMoveDirection();
    }

    private _onKeyUp(event: EventKeyboard) {
        //只要事件发生,就改变标志位的状态为false
        switch (event.keyCode) {
            case KeyCode.KEY_W:
                this._isUpPressed = false;
                if(this._isDownPressed){
                    this._lastVerticalDirection = Direction.DOWN;
                }else{
                    this._lastVerticalDirection = null;
                }
                break;
            case KeyCode.KEY_S:
                this._isDownPressed = false;
                if(this._isUpPressed){
                    this._lastVerticalDirection = Direction.UP;
                }else{
                    this._lastVerticalDirection = null;
                }
                break;
            case KeyCode.KEY_A:
                this._isLeftPressed = false;
                if(this._isRightPressed){
                    this._lastHorizontalDirection = Direction.RIGHT;
                }else{
                    this._lastHorizontalDirection = null;
                }
                break;
            case KeyCode.KEY_D:
                this._isRightPressed = false;
                if(this._isLeftPressed){
                    this._lastHorizontalDirection = Direction.LEFT;
                }else{
                    this._lastHorizontalDirection = null;
                }
                break;
        }
        //在有按键松开的时候,更新_moveDirection
        this._updateMoveDirection();
    }

    protected update(deltaTime: number) {
        let movements = new Vec3(this._moveDirection.x * this.moveSpeed * deltaTime, this._moveDirection.y * this.moveSpeed * deltaTime, 0);
        this.node.setPosition(this.node.position.add(movements));
    }

    private _updateMoveDirection() {
        //根据_lastVerticalDirection和_lastHorizontalDirection的值,更新_moveDirection的值
        if(this._lastVerticalDirection === Direction.UP){
            this._moveDirection.y = 1;
        }else if(this._lastVerticalDirection === Direction.DOWN){
            this._moveDirection.y = -1;
        }else{
            this._moveDirection.y = 0;
        }

        if(this._lastHorizontalDirection === Direction.LEFT){
            this._moveDirection.x = -1;
        }else if(this._lastHorizontalDirection === Direction.RIGHT){
            this._moveDirection.x = 1;
        }else{
            this._moveDirection.x = 0;
        }        
    }
}

这种实现方式看似完美解决了第二种实现方式不够灵活的状态,但其实也有很多的具体问题,甚至在格斗游戏和射击游戏这两个品类上掀起过不小的风波。这也是我通过一个视频了解到的。

https://www.bilibili.com/video/BV1qdwsebEs3/?spm_id_from=333.1387.homepage.video_card.click&vd_source=34c128fb80d025cfec1075f58ddfd8d4

所以不同的游戏还是需要根据具体的实际情况去设计按键逻辑。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇