You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PlayCanvas游戏开发:如何用Shift键实现角色加速并优化冗余代码

优化PlayCanvas第一人称移动脚本(Shift加速功能)

我是编程新手,正在使用PlayCanvas开发游戏,希望实现按下Shift键时提升角色移动速度。目前我已完成该功能,但代码较为冗余,现有实现代码如下,寻求更简洁的实现方法。

原始代码

var FirstPersonMovement = pc.createScript('firstPersonMovement');

FirstPersonMovement.attributes.add('camera', {
    type: 'entity',
    description: 'Optional, assign a camera entity, otherwise one is created'
});

FirstPersonMovement.attributes.add('power', {
    type: 'number',
    default: 2500,
    description: 'Adjusts the speed of player movement'
});

FirstPersonMovement.attributes.add('lookSpeed', {
    type: 'number',
    default: 0.25,
    description: 'Adjusts the sensitivity of looking'
});

// initialize code called once per entity
FirstPersonMovement.prototype.initialize = function() {
    this.force = new pc.Vec3();
    this.eulers = new pc.Vec3();

    var app = this.app;

    // Listen for mouse move events
    app.mouse.on("mousemove", this._onMouseMove, this);

    // when the mouse is clicked hide the cursor
    app.mouse.on("mousedown", function () {
        app.mouse.enablePointerLock();
    }, this);

    // Check for required components
    if (!this.entity.collision) {
        console.error("First Person Movement script needs to have a 'collision' component");
    }

    if (!this.entity.rigidbody || this.entity.rigidbody.type !== pc.BODYTYPE_DYNAMIC) {
        console.error("First Person Movement script needs to have a DYNAMIC 'rigidbody' component");
    }
};

// update code called every frame
FirstPersonMovement.prototype.update = function(dt) {
    // If a camera isn't assigned from the Editor, create one
    if (!this.camera) {
        this._createCamera();
    }

    var force = this.force;
    var app = this.app;

    // Get camera directions to determine movement directions
    var forward = this.camera.forward;
    var right = this.camera.right;


    // movement
    var x = 0;
    var z = 0;

    // Use W-A-S-D and SHIFT keys to move player
    // Check for key presses
    if (app.keyboard.isPressed(pc.KEY_A) || app.keyboard.isPressed(pc.KEY_Q)) {
        x -= right.x;
        z -= right.z;
    }

    if (app.keyboard.isPressed(pc.KEY_D)) {
        x += right.x;
        z += right.z;
    }

    if (app.keyboard.isPressed(pc.KEY_W)) {
        x += forward.x;
        z += forward.z;
    }
        
    if (app.keyboard.isPressed(pc.KEY_S))  {
        x -= forward.x;
        z -= forward.z;
    }
    if (app.keyboard.isPressed(pc.KEY_SHIFT)) {
        x += forward.x;
        z += forward.z;
    }

    // use direction from keypresses to apply a force to the character
    if (x !== 0 && z !== 0) {
        force.set(x, 0, z).normalize().scale(this.power);
        this.entity.rigidbody.applyForce(force);
    }

    // update camera angle from mouse events
    this.camera.setLocalEulerAngles(this.eulers.y, this.eulers.x, 0);
};

FirstPersonMovement.prototype._onMouseMove = function (e) {
    // If pointer is disabled
    // If the left mouse button is down update the camera from mouse movement
    if (pc.Mouse.isPointerLocked() || e.buttons[0]) {
        this.eulers.x -= this.lookSpeed * e.dx;
        this.eulers.y -= this.lookSpeed * e.dy;
    }
};

FirstPersonMovement.prototype._createCamera = function () {
    // If user hasn't assigned a camera, create a new one
    this.camera = new pc.Entity();
    this.camera.setName("First Person Camera");
    this.camera.addComponent("camera");
    this.entity.addChild(this.camera);
    this.camera.translateLocal(0, 0.5, 0);
};

优化后的代码

var FirstPersonMovement = pc.createScript('firstPersonMovement');

FirstPersonMovement.attributes.add('camera', {
    type: 'entity',
    description: '可选,指定相机实体,否则自动创建'
});

FirstPersonMovement.attributes.add('power', {
    type: 'number',
    default: 2500,
    description: '调整玩家移动基础速度'
});

FirstPersonMovement.attributes.add('lookSpeed', {
    type: 'number',
    default: 0.25,
    description: '调整视角灵敏度'
});

FirstPersonMovement.attributes.add('sprintMultiplier', {
    type: 'number',
    default: 2,
    description: 'Shift冲刺时的速度倍率'
});

// 初始化代码,每个实体调用一次
FirstPersonMovement.prototype.initialize = function() {
    this.force = new pc.Vec3();
    this.eulers = new pc.Vec3();
    const app = this.app;

    // 监听鼠标移动事件
    app.mouse.on("mousemove", this._onMouseMove, this);

    // 点击鼠标时隐藏光标并锁定指针
    app.mouse.on("mousedown", () => app.mouse.enablePointerLock(), this);

    // 检查必要组件是否存在
    if (!this.entity.collision) {
        console.error("第一人称移动脚本需要绑定碰撞组件");
    }

    if (!this.entity.rigidbody || this.entity.rigidbody.type !== pc.BODYTYPE_DYNAMIC) {
        console.error("第一人称移动脚本需要绑定动态刚体组件");
    }
};

// 每帧执行的更新代码
FirstPersonMovement.prototype.update = function(dt) {
    // 如果未指定相机,自动创建
    if (!this.camera) {
        this._createCamera();
    }

    const force = this.force;
    const app = this.app;
    const forward = this.camera.forward;
    const right = this.camera.right;

    // 计算基础移动方向
    let x = 0;
    let z = 0;

    // 统一处理方向输入
    x += (app.keyboard.isPressed(pc.KEY_D) - app.keyboard.isPressed(pc.KEY_A) - app.keyboard.isPressed(pc.KEY_Q)) * right.x;
    z += (app.keyboard.isPressed(pc.KEY_D) - app.keyboard.isPressed(pc.KEY_A) - app.keyboard.isPressed(pc.KEY_Q)) * right.z;
    
    x += (app.keyboard.isPressed(pc.KEY_W) - app.keyboard.isPressed(pc.KEY_S)) * forward.x;
    z += (app.keyboard.isPressed(pc.KEY_W) - app.keyboard.isPressed(pc.KEY_S)) * forward.z;

    // 应用冲刺倍率
    const speedMultiplier = app.keyboard.isPressed(pc.KEY_SHIFT) ? this.sprintMultiplier : 1;

    // 仅当有移动输入时施加力
    if (x !== 0 || z !== 0) {
        force.set(x, 0, z).normalize().scale(this.power * speedMultiplier);
        this.entity.rigidbody.applyForce(force);
    }

    // 更新相机视角
    this.camera.setLocalEulerAngles(this.eulers.y, this.eulers.x, 0);
};

FirstPersonMovement.prototype._onMouseMove = function (e) {
    // 指针锁定或按住左键时更新视角
    if (pc.Mouse.isPointerLocked() || e.buttons[0]) {
        this.eulers.x -= this.lookSpeed * e.dx;
        this.eulers.y -= this.lookSpeed * e.dy;
    }
};

FirstPersonMovement.prototype._createCamera = function () {
    // 自动创建第一人称相机
    this.camera = new pc.Entity();
    this.camera.setName("第一人称相机");
    this.camera.addComponent("camera");
    this.entity.addChild(this.camera);
    this.camera.translateLocal(0, 0.5, 0);
};

优化说明

  • 新增可配置冲刺倍率:添加sprintMultiplier属性,无需硬编码冲刺速度,在编辑器中即可调整,灵活性更高。
  • 简化按键判断逻辑:用按键按下状态(0或1)相减的方式合并方向输入代码,减少重复的if判断。
  • 修复Shift逻辑错误:原代码按下Shift会直接添加前进力(无论是否按W),优化后改为在当前移动方向基础上乘以倍率,符合正常冲刺逻辑。
  • 精简代码结构:合并重复的app.keyboard.isPressed调用,减少冗余代码;用箭头函数简化事件回调写法。
  • 中文注释优化:将注释改为中文,更贴合新手阅读习惯。

内容的提问来源于stack exchange,提问作者Kyle_3_1415

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 08:35:24