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

Unity中使用Input.GetKeyDown实现玩家两点间切换移动的技术问询

实现Unity玩家双位置切换移动功能

核心需求梳理

  • 两个固定目标位置:firstPosition = new Vector2(0, 0)、secondPosition = new Vector2(0, 5)
  • 按E键触发位置切换:在第一个位置时按E移动到第二个,反之亦然
  • 使用transform.Translate实现平滑移动

优化后的完整代码

using UnityEngine;

public class PlayerPositionSwitch : MonoBehaviour
{
    // 定义两个固定目标位置
    [SerializeField] private Vector2 firstPosition = new Vector2(0, 0);
    [SerializeField] private Vector2 secondPosition = new Vector2(0, 5);
    // 移动速度
    [SerializeField] private float moveSpeed = 2f;
    // 位置判定阈值(避免浮点精度问题)
    [SerializeField] private float positionThreshold = 0.01f;

    private Rigidbody2D rig2d;
    private Vector2 currentTargetPosition;
    private bool isMoving = false;

    private void Awake()
    {
        rig2d = GetComponent<Rigidbody2D>();
        // 初始化当前目标为初始位置
        currentTargetPosition = transform.position;
    }

    private void Update()
    {
        // 只有不在移动状态时,才响应E键输入
        if (!isMoving && Input.GetKeyDown(KeyCode.E))
        {
            SwitchTargetPosition();
            isMoving = true;
            // 移动时关闭刚体模拟,避免物理干扰
            if (rig2d != null)
            {
                rig2d.simulated = false;
            }
        }

        // 如果处于移动状态,执行移动逻辑
        if (isMoving)
        {
            MoveToTarget();
        }
    }

    // 切换目标位置
    private void SwitchTargetPosition()
    {
        // 判断当前位置接近哪个目标,切换到另一个
        if (Vector2.Distance(transform.position, firstPosition) < positionThreshold)
        {
            currentTargetPosition = secondPosition;
        }
        else if (Vector2.Distance(transform.position, secondPosition) < positionThreshold)
        {
            currentTargetPosition = firstPosition;
        }
    }

    // 向目标位置移动
    private void MoveToTarget()
    {
        // 计算朝向目标的方向向量(归一化)
        Vector2 direction = (currentTargetPosition - (Vector2)transform.position).normalized;
        // 使用Translate移动,基于世界空间(避免自身旋转影响)
        transform.Translate(direction * moveSpeed * Time.deltaTime, Space.World);

        // 检查是否到达目标位置
        if (Vector2.Distance(transform.position, currentTargetPosition) < positionThreshold)
        {
            // 强制设置到目标位置,消除误差
            transform.position = currentTargetPosition;
            isMoving = false;
            // 移动结束后恢复刚体模拟
            if (rig2d != null)
            {
                rig2d.simulated = true;
            }
        }
    }
}

关键优化点说明

  • 位置判定阈值:使用positionThreshold避免浮点精度问题,直接用==判断位置会因为浮点误差导致逻辑失效
  • 状态管理:用isMoving变量控制输入响应,避免移动过程中重复触发切换
  • 刚体控制:移动时关闭刚体模拟,防止物理系统干扰移动路径,到达后恢复
  • 方向计算:基于世界空间移动,避免玩家自身旋转影响移动方向(如果不需要可以改成Space.Self)
  • 模块化拆分:将切换逻辑和移动逻辑拆分为单独方法,代码更易维护

对原有代码的适配说明

如果需要保留原有代码中的stairsOn、inHelecopter等变量逻辑,可以将移动触发条件修改为:

if (!isMoving && stairsOn && Input.GetKeyDown(KeyCode.E))
{
    SwitchTargetPosition();
    isMoving = true;
    inHelecopter.inHelecopter = true;
    if (rig2d != null)
    {
        rig2d.simulated = false;
    }
}

同时在移动结束时添加stairsOn = false;和inHelecopter.inHelecopter = false;(根据需求调整)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:46:04