Unity枪械Transform旋转超出限定-40°~0°范围转360度问题如何解决?
问题描述
核心问题
我限定了枪械X轴旋转范围为-40°~0°,但运行游戏时枪械仍会360°旋转。
运行游戏前的默认状态下,枪械X轴旋转值为0,对应截图如下:
我手动将枪械X轴旋转值修改为-40后的截图如下:
我的需求是让枪械仅在X轴0°到-40°范围内上下旋转,但实际运行时会出现360°旋转的问题。
原有代码
最初版本MissleLauncherRotation脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MissleLauncherRotation : MonoBehaviour { public Transform body; public Transform guns; public Vector3 spinAxisBody; public Vector3 spinAxisGuns; public float timeToSpin = 5f; public float spinSpeed = 20f; public bool randomSpin = false; private void Start() { StartCoroutine("Spin"); } private void Update() { } IEnumerator Spin() { float spinTimer; while (true) { if (randomSpin == true) { spinAxisBody = new Vector3(0,Random.Range(-180, 180),0); spinAxisGuns = new Vector3(Random.Range(-40, 0), 0, 0); } spinTimer = timeToSpin; while (spinTimer > 0f) { body.transform.Rotate(spinAxisBody, Time.deltaTime * spinSpeed); guns.Rotate(spinAxisGuns, Time.deltaTime * spinSpeed); spinTimer -= Time.deltaTime; yield return null; } } } }
调整后的测试版本MissleLauncherRotation脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class MissleLauncherRotation : MonoBehaviour { public Transform body; public Transform guns; public Vector3 spinAxisBody; public Vector3 spinAxisGuns; public float timeToSpin = 5f; public float spinSpeed = 20f; public bool randomSpin = false; Quaternion rot; private void Start() { rot = guns.rotation; } private void Update() { guns.Rotate(guns.up, (spinSpeed * Time.deltaTime)); var rot = guns.rotation.eulerAngles; rot = new Vector3 ( guns.eulerAngles.x, Mathf.Clamp(rot.x, -40, 0), guns.eulerAngles.z ); guns.rotation = Quaternion.Euler(rot); } }
调整后仅角度限制功能生效,但并非仅限制X轴,且我希望使用协程实现每隔X秒旋转一次的效果,不知道如何将限制逻辑和最初的协程代码结合。
关联脚本
DronesManager脚本(挂载在空GameObject上)
using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; public class DronesManager : MonoBehaviour { public Transform dronesUnchild; private List<GameObject> drones = new List<GameObject>(); private static System.Random rnd = new System.Random(); // Start is called before the first frame update void Start() { StartCoroutine(MoveDrone()); } // Update is called once per frame void Update() { } private IEnumerator MoveDrone() { // same as you did: var drones = GameObject.FindGameObjectsWithTag("Drone").ToList(); while (drones.Count > 0) { // pick one at random, get it int index = Random.Range(0, drones.Count); var drone = drones[index]; // remove it from list drones.RemoveAt(index); // TODO: might want to check/guard if drone == null ... this guards against it // being Destroy()ed and yet still lying around in our list marked as "dead" // simplified your get-component-and-go-if-not-already-going code here var droneControl = drone.GetComponent<DroneControl>(); if (droneControl.go == false) { droneControl.movingSpeed = 5f; droneControl.go = true; drone.transform.parent = dronesUnchild; } // wait yield return new WaitForSeconds(0.3f); } } }
DroneControl脚本(挂载在每个无人机对象上)
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DroneControl : MonoBehaviour { public float movingSpeed; public bool go = false; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { if(go) { transform.position -= transform.forward * movingSpeed * Time.deltaTime; } } }
附加问题
现在我修改MissleLauncherRotation脚本的变量时会出现程序卡顿的问题,不知道是否和上述两个无人机相关脚本有关?
解决方案
1. 修复枪械X轴旋转限制+协程结合问题
你之前的代码存在两个核心错误:
- Unity的欧拉角读取时默认返回0~360°的正值,-40°会被自动转换成320°,直接使用
Mathf.Clamp(-40,0)完全失效 - 测试版本代码中把X轴和Y轴的限制逻辑写反,导致出现不只限制X轴的问题
修正后的完整MissleLauncherRotation代码如下:
using System.Collections; using UnityEngine; public class MissleLauncherRotation : MonoBehaviour { public Transform body; public Transform guns; public Vector3 spinAxisBody; public Vector3 spinAxisGuns; public float timeToSpin = 5f; public float spinSpeed = 20f; public bool randomSpin = false; private void Start() { StartCoroutine(Spin()); } // 欧拉角转换为-180~180范围的工具方法 private float NormalizeAngle(float angle) { if (angle > 180) angle -= 360; return angle; } IEnumerator Spin() { float spinTimer; while (true) { if (randomSpin) { spinAxisBody = new Vector3(0,Random.Range(-180, 180),0); spinAxisGuns = new Vector3(Random.Range(-40, 0), 0, 0); } spinTimer = timeToSpin; while (spinTimer > 0f) { body.Rotate(spinAxisBody, Time.deltaTime * spinSpeed); guns.Rotate(spinAxisGuns, Time.deltaTime * spinSpeed); // 限制枪械X轴角度 Vector3 currentEuler = guns.eulerAngles; float normalizedX = NormalizeAngle(currentEuler.x); currentEuler.x = Mathf.Clamp(normalizedX, -40f, 0f); guns.rotation = Quaternion.Euler(currentEuler); spinTimer -= Time.deltaTime; yield return null; } // 若需要两次旋转之间增加固定间隔,在此处添加 yield return new WaitForSeconds(间隔时间); 即可 } } }
2. 修改变量卡顿问题
卡顿和两个无人机脚本无关,问题出在测试版本代码的Update逻辑里,每帧都在修改旋转再强制赋值,Inspector面板修改变量时会反复触发属性刷新,导致卡顿。替换为上述协程版本代码后,卡顿问题会自动消失。
如果替换后仍有卡顿,可排查两个方向:
- 场景内无人机数量是否过多
- 是否存在其他脚本在Update中执行了高频查找、实例化等重负载操作
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

