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

Unity俯视角射击游戏子弹旋转后移动方向异常问题

俯视角射击子弹旋转后移动方向异常问题

开发类似《星露谷物语》中《草原之王之旅》的俯视角射击游戏时,遇到以下问题:

  • 上下瞄准射击时,将子弹旋转90度以匹配移动方向后,向上射击时子弹向左移动,向下射击时向右移动;
  • 不旋转子弹时,移动方向正常。

现有代码

public class BulletMovement : MonoBehaviour
{
    public Vector2 moveDirection;
    private GameObject player;
    public int speed;
    
    // Start is called before the first frame update
    void Start()
    {
        player = GameObject.Find("Player");
        Move();
    }

    // Update is called once per frame
    void Update()
    {
        transform.Translate(moveDirection * Time.deltaTime * speed);
        CheckIfOutOfBounds();
    }
    
    //Moves the bullet in the direction the player is facing when the bullet is fired
    private void Move()
    {
        if (player.GetComponent<PlayerMovement>().GetPlayerFacing().Equals("up"))
        {
            RotateBullet(90);
            moveDirection = new Vector2(0, 1);
        }
        if (player.GetComponent<PlayerMovement>().GetPlayerFacing().Equals("down"))
        {
            RotateBullet(90);
            moveDirection = new Vector2(0, -1);
        }
        if (player.GetComponent<PlayerMovement>().GetPlayerFacing().Equals("left"))
        {
            //Moves the bullet in front of the gun
            transform.Translate(-0.363f, 0, 0);
            moveDirection = new Vector2(-1, 0);
        }
        if (player.GetComponent<PlayerMovement>().GetPlayerFacing().Equals("right"))
        {
            //Moves the bullet in front of the gun
            transform.Translate(0.363f, 0, 0);
            
            moveDirection = new Vector2(1, 0);
        }
    }

    //Destroys the bullet if it goes off-screen
    private void CheckIfOutOfBounds()
    {
        if (transform.position.x is > 10 or < -10)
        {
            Destroy(gameObject);
        }

        if (transform.position.y is > 10 or < -10)
        {
            Destroy(gameObject);
        }
    }

    private void RotateBullet(int degrees)
    {
        transform.rotation = Quaternion.Euler(new Vector3(0, 0, degrees));
    }
}

已尝试的方法

  • transform.Rotate(Vector3(0, 0, 90))
  • transform.Rotate(Vector3.right)
  • transform.rotation = Quaternion.Euler(new Vector3(0, 0, degrees))(当前使用)

问题原因

transform.Translate 默认使用自身局部坐标系,当子弹旋转后,局部坐标系的X/Y轴方向和世界坐标系不再一致。比如子弹向上旋转90度后,其局部X轴对应世界的Y轴,局部Y轴对应世界的-X轴,此时用世界坐标系的Vector2(0,1)调用Translate,就会导致子弹向局部X轴方向移动,对应世界的左方。

修复方案

  1. 修改Translate的坐标系参数:将Translate改为使用世界坐标系,避免局部旋转影响移动方向。
  2. 调整上下方向的旋转角度:向下射击时需要旋转-90度(或270度),才能让子弹图形朝向正确方向。

修改后的代码如下:

修复后的BulletMovement代码

public class BulletMovement : MonoBehaviour
{
    public Vector2 moveDirection;
    private GameObject player;
    public int speed;
    private PlayerMovement playerMovement; // 缓存组件引用
    
    void Start()
    {
        player = GameObject.Find("Player");
        playerMovement = player.GetComponent<PlayerMovement>();
        Move();
    }

    void Update()
    {
        // 使用Space.World指定世界坐标系移动,不受自身旋转影响
        transform.Translate(moveDirection * Time.deltaTime * speed, Space.World);
        CheckIfOutOfBounds();
    }
    
    private void Move()
    {
        var playerFacing = playerMovement.GetPlayerFacing();
        
        if (playerFacing.Equals("up"))
        {
            RotateBullet(90);
            moveDirection = new Vector2(0, 1);
        }
        else if (playerFacing.Equals("down"))
        {
            // 向下时旋转-90度,让子弹图形朝下
            RotateBullet(-90);
            moveDirection = new Vector2(0, -1);
        }
        else if (playerFacing.Equals("left"))
        {
            transform.Translate(-0.363f, 0, 0, Space.World);
            moveDirection = new Vector2(-1, 0);
        }
        else if (playerFacing.Equals("right"))
        {
            transform.Translate(0.363f, 0, 0, Space.World);
            moveDirection = new Vector2(1, 0);
        }
    }

    private void CheckIfOutOfBounds()
    {
        if (transform.position.x > 10 || transform.position.x < -10)
        {
            Destroy(gameObject);
        }

        if (transform.position.y > 10 || transform.position.y < -10)
        {
            Destroy(gameObject);
        }
    }

    private void RotateBullet(int degrees)
    {
        transform.rotation = Quaternion.Euler(0, 0, degrees);
    }
}

额外优化建议

  • 缓存PlayerMovement组件引用,避免重复调用GetComponent提升性能;
  • 将硬编码的子弹偏移值0.363f改为公共变量,方便在Inspector面板中可视化调整。

内容的提问来源于stack exchange,提问作者A guy with questions

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 02:26:24