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

Unity2D中如何让实例化预制体按自身旋转与速度移动

问题描述

我正在开发一款射击游戏,遇到了实例化子弹的问题:在Instantiate()代码中,枪的角度与子弹角度同步,我甚至将Rigidbody2D的角度设置为枪的旋转值,但执行rb.velocity = new Vector2(10f, 0);时,子弹仅向右直线飞行,完全不考虑transform.rotation或rigidbody.rotation的旋转值。通过Inspector可以看到子弹的旋转值正确,但速度方向未随旋转改变。

计算枪角度的代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PointAtMouse : MonoBehaviour
{
    Vector3 mouse_pos;
    Transform target; //Assign to the object you want to rotate
    Vector3 object_pos;
    float angle;
    // Start is called before the first frame update
    void Start()
    {
        target = gameObject.transform;
    }

    void Update()
    {
        mouse_pos = Input.mousePosition;
        mouse_pos.z = 5.23f; //The distance between the camera and object
        object_pos = Camera.main.WorldToScreenPoint(target.position);
        mouse_pos.x = mouse_pos.x - object_pos.x;
        mouse_pos.y = mouse_pos.y - object_pos.y;
        angle = Mathf.Atan2(mouse_pos.y, mouse_pos.x) * Mathf.Rad2Deg;
        transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle - 90));
    }
}

实例化子弹的代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShootBullet : MonoBehaviour
{
    public GameObject bulletPrefab;
    float reload;
    // Start is called before the first frame update
    void Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        if(reload <= 0 && Input.GetMouseButtonDown(0))
        {
            GameObject bullet = Instantiate(bulletPrefab, gameObject.transform.position, gameObject.transform.rotation);
            Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
            rb.velocity = new Vector2(10, 0);
            reload = .1f;
        }

        if(reload > 0)
        {
            reload -= Time.deltaTime;
        }
    }
}

注意:ShootBullet类挂载在枪上而非子弹上,预制体已挂载正常工作的SpriteRenderer。我曾考虑根据旋转值设置Vector2的sin和cos值,但认为Unity应有现成方法,尝试多种方式均无效。

编辑:我通过以下代码让子弹有一定旋转方向,但仅能覆盖-45到45度:

rb.velocity = new Vector2(Mathf.Sin(bullet.transform.rotation.z) * 10, Mathf.Cos(bullet.transform.rotation.z) * 10);

请问如何修改该代码,让子弹能覆盖360度方向飞行?


解决方案

问题出在你直接使用transform.rotation.z——这个值是四元数的Z分量,不是欧拉角的旋转度数,范围仅在-1到1之间,导致三角函数计算只能覆盖小角度范围。以下是三种可靠的修复方式:

方法1:利用Transform的前方向(推荐)

Unity的Transform组件自带方向向量,直接取枪的朝向即可,无需手动计算三角函数:

// 在ShootBullet的Instantiate逻辑中修改
GameObject bullet = Instantiate(bulletPrefab, gameObject.transform.position, gameObject.transform.rotation);
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
// 你的枪旋转时绕Z轴转了angle-90,所以枪的up方向就是子弹飞行方向
rb.velocity = transform.up * 10f;

方法2:用欧拉角计算正确方向向量

手动计算时,需要先把四元数转成欧拉角的Z轴角度,再转成弧度计算:

// 在ShootBullet的Instantiate逻辑中修改
GameObject bullet = Instantiate(bulletPrefab, gameObject.transform.position, gameObject.transform.rotation);
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
float bulletAngle = bullet.transform.eulerAngles.z * Mathf.Deg2Rad;
rb.velocity = new Vector2(Mathf.Cos(bulletAngle), Mathf.Sin(bulletAngle)) * 10f;

eulerAngles.z是0-360的度数,转成弧度后,Mathf.Cos对应X方向、Mathf.Sin对应Y方向,配合枪的旋转逻辑可覆盖全360度。

方法3:复用瞄准逻辑中的角度

在PointAtMouse中把计算好的角度存为公共变量,直接在ShootBullet中调用:

// 1. 修改PointAtMouse脚本,添加公共变量
public float currentAngle;

// 在PointAtMouse的Update方法末尾赋值
currentAngle = angle;

// 2. 修改ShootBullet的Instantiate逻辑
GameObject bullet = Instantiate(bulletPrefab, gameObject.transform.position, gameObject.transform.rotation);
Rigidbody2D rb = bullet.GetComponent<Rigidbody2D>();
PointAtMouse aimScript = GetComponent<PointAtMouse>();
float radian = (aimScript.currentAngle - 90) * Mathf.Deg2Rad;
rb.velocity = new Vector2(Mathf.Cos(radian), Mathf.Sin(radian)) * 10f;

以上三种方法都能让子弹沿枪的朝向正确飞行,覆盖360度方向。


内容的提问来源于stack exchange,提问作者The Dog on the Log

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 12:16:08