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

