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

Unity2D向左上移动时冲刺功能失效的Bug排查

问题:左上方向移动时冲刺功能无法触发

我正在参与GMTK 2022 Game Jam项目开发,角色移动时按空格键可触发冲刺——沿当前速度方向移动并短暂获得高速移动能力。所有方向的冲刺功能都正常,但按住左上方向移动时,冲刺的触发条件始终不满足,Debug.Log("Dash")完全没有输出。已排查一小时未找到原因,相关代码如下:

// Update is called once per frame
void Update()
{
    playerInputh = 0;
    playerInputv = 0;
    if (Input.GetKey("right"))
    {
        playerInputh = 1;
    }
    if (Input.GetKey("left"))
    {
        playerInputh = -1;
    }
    if (Input.GetKey("right") && Input.GetKey("left"))
    {
        playerInputh = 0;
    }
    if (Input.GetKey("up"))
    {
        playerInputv = 1;
    }
    if (Input.GetKey("down"))
    {
        playerInputv = -1;
    }
    if (Input.GetKey("up") && Input.GetKey("down"))
    {
        playerInputv = 0;
    }

    Vector2 screenPosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
    Vector2 mouseWorldPosition = Camera.main.ScreenToWorldPoint(screenPosition);


    //This is the dash that isn't working:
    if ((Input.GetKeyDown("space")) && (playerInputh != 0 || playerInputv != 0))
    {
        Debug.Log("Dash");
        //Vector2 transform2dposition = new Vector2(transform.position.x, transform.position.y);
        m_Rigidbody.AddForce((m_Rigidbody.velocity) * 500f);
        wJumpTimer = airControlAfterJump;
        speed = maxSpeed*3.5f;
        StartCoroutine(Roll());
    }
}

void FixedUpdate()
{
    //no moving while jumping!!!
    if (wJumpTimer > 0)
    {
        wJumpTimer -= 1;
    }
    else
    {
        wJumpTimer = 0;
    }

    //move
    if (playerInputh != 0 && playerInputv != 0) //make diagonals no super sayan
    {
        playerInputh *= moveLimiter;
        playerInputv *= moveLimiter;

        one_h = playerInputh;//futureproof
        one_v = playerInputv;
    }
    if ((playerInputh != 0 || playerInputv != 0) && speed < maxSpeed) //are we hitting the move buttons??
    {
        speed += acceleration;//accelerate
        one_h = playerInputh;//futureproof
        one_v = playerInputv;

    }
    else
    {     
        if (speed > 0f) //are we getting off the ride
        {
            speed -= deceleration; //decelerate
        }
        else
        {
            speed = 0f; //no funny buisness
        }
    }

    m_Rigidbody.velocity = new Vector2(one_h * speed, one_v * speed); //actually move
}

void SetFace(int diceNumb)
{
    rndr.sprite = sprites[diceNumb];
}
IEnumerator Roll()
{
    Random diceNumb = new Random();
    rndr.sprite = sprites[diceNumb.Next(0,5)];
    yield return new WaitForSeconds(0.125f);
    rndr.sprite = sprites[diceNumb.Next(0, 5)];
    yield return new WaitForSeconds(0.125f);
    rndr.sprite = sprites[diceNumb.Next(0, 5)];
    yield return new WaitForSeconds(0.125f);
    rndr.sprite = sprites[diceNumb.Next(0, 5)];
    yield return new WaitForSeconds(0.125f);
    var newValue = diceNumb.Next(0, 5);
    FaceValue = newValue + 1;
    rndr.sprite = sprites[newValue];
}

问题根源

核心问题是FixedUpdate中直接修改了playerInputh和playerInputv这两个输入变量:
当同时按住左和上时,Update中会将playerInputh设为-1、playerInputv设为1,但FixedUpdate里执行playerInputh *= moveLimiter和playerInputv *= moveLimiter(moveLimiter通常是≈0.707的浮点数)。如果playerInputh和playerInputv是int类型,乘以浮点数后会被截断为0;即使是float类型,后续逻辑也可能导致变量值异常,干扰Update中的冲刺条件判断。

此外,冲刺触发依赖playerInputh !=0 || playerInputv !=0,但输入变量被修改后,可能在某些帧内出现值为0的情况,导致条件不满足。


修复方案

1. 避免修改原始输入变量

在FixedUpdate中使用临时变量处理移动逻辑,不要直接修改playerInputh和playerInputv:

void FixedUpdate()
{
    //no moving while jumping!!!
    if (wJumpTimer > 0)
    {
        wJumpTimer -= 1;
    }
    else
    {
        wJumpTimer = 0;
    }

    // 使用临时变量处理移动,不修改原始输入
    float tempH = playerInputh;
    float tempV = playerInputv;

    //move
    if (tempH != 0 && tempV != 0) //make diagonals no super sayan
    {
        tempH *= moveLimiter;
        tempV *= moveLimiter;

        one_h = tempH;//futureproof
        one_v = tempV;
    }
    if ((tempH != 0 || tempV != 0) && speed < maxSpeed) //are we hitting the move buttons??
    {
        speed += acceleration;//accelerate
        one_h = tempH;//futureproof
        one_v = tempV;

    }
    else
    {     
        if (speed > 0f) //are we getting off the ride
        {
            speed -= deceleration; //decelerate
        }
        else
        {
            speed = 0f; //no funny buisness
        }
    }

    m_Rigidbody.velocity = new Vector2(one_h * speed, one_v * speed); //actually move
}

2. 优化冲刺触发条件

直接检测按键状态或角色速度,避免依赖可能被修改的输入变量:

// 修改冲刺判断条件
if (Input.GetKeyDown("space") && 
    (Input.GetKey("left") || Input.GetKey("right") || Input.GetKey("up") || Input.GetKey("down")))
{
    Debug.Log("Dash");
    m_Rigidbody.AddForce(m_Rigidbody.velocity * 500f);
    wJumpTimer = airControlAfterJump;
    speed = maxSpeed * 3.5f;
    StartCoroutine(Roll());
}

或者用角色速度判断(确保角色在移动时才能冲刺):

if (Input.GetKeyDown("space") && m_Rigidbody.velocity.magnitude > 0.1f)
{
    // 冲刺逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 21:54:18