У меня есть игровой объект, содержащий другой игровой объект, который должен иметь возможность вращаться к цели (представьте себе танковую башню). Итак, я создал следующий сценарий:
public class Rotator : MonoBehaviour {
public GameObject _enemy;
void Update () {
var actualTarget = _enemy.transform.position;
var targetDir = actualTarget - transform.position;
var step = 2 * Time.deltaTime;
var target = Quaternion.LookRotation(targetDir.normalized, Vector3.up);
var actual = target * Quaternion.Inverse(transform.parent.rotation);
var targetRotation = Quaternion.Slerp(transform.localRotation, actual, step);
targetRotation.eulerAngles = ClampRotation(targetRotation.eulerAngles);
transform.localRotation = targetRotation;
}
private static Vector3 ClampRotation(Vector3 eulerAngles) {
var x = Mathf.Clamp(eulerAngles.x > 180 ? eulerAngles.x - 360 : eulerAngles.x, -180, 180);
var y = Mathf.Clamp(eulerAngles.y > 180 ? eulerAngles.y - 360 : eulerAngles.y, -45, 45);
return new Vector3(x, y, 0);
}
}
Настройка объектов:
Вращение объекта с именем «родительский» составляет 90 градусов по оси Y, все остальное не поворачивается.
Зажим по оси Y работает хорошо - угол поворота составляет от -45 до 45 градусов. Однако вращение не работает по оси x (с зажимом или без него).
Итак, цель здесь состоит в том, чтобы, когда я перемещаю куб влево или вправо, красный кубик поворачивается на [-45,45] градусов вокруг оси Y, а когда я перемещаю его вверх или вниз, красный кубик вращается на [-180,180] градусов. вокруг оси X.
У меня был некоторый успех, используя метод LookAt класса Transform, но по какой-то причине, если я пытаюсь вручную изменить eulerAngles из localRotation, он внезапно теряет возможность вращаться назад по оси X, хотя я делаю что-то только с Y ценности...
Теперь стало понятнее?
Да не продвигается. Вы также хотите добавить ограничение вращения для обеих осей?
Если, двигаясь вверх, вы имеете в виду, что красный парень не указывает на движущийся куб, когда он движется вверх / вниз, тогда да - это проблема. И снова - да - я хочу добавить ограничение вращения для осей X и Y. Z one я просто устанавливаю на 0, так как я не хочу, чтобы на него вообще влияли.





После долгих часов проб и ошибок и безумного просмотра Интернета мне удалось найти ответ, который я мог бы приспособить к своим потребностям. Комментарий к первому оператору if метода Clamp - это полезно, если я хочу, чтобы объект также был зажат в его перевернутом положении (если цель находится за ним):
void Update() {
transform.LookAt(_target.transform);
var rotation = transform.localRotation;
var eulers = ClampRotation(rotation.eulerAngles);
transform.localEulerAngles = eulers;
}
private static Vector3 ClampRotation(Vector3 eulerAngles) {
var x = Clamp(eulerAngles.x, -60, 60);
var y = Clamp(eulerAngles.y, -45, 45);
return new Vector3(x, y, 0);
}
private static float Clamp(float angle, float min, float max) {
if ((angle <= 180 && angle >= 180 - Mathf.Abs(min)) || (angle >= 180 && angle <= 180 + max)) {
return Mathf.Clamp(angle, 180 - Mathf.Abs(min), 180 + max);
}
if (angle > 180f) {
angle -= 360f;
}
angle = Mathf.Clamp(angle, min, max);
if (angle < 0f) {
angle += 360f;
}
return angle;
}
Обновлено:
Оказывается, иногда лучше создать собственное мелкозернистое решение, которое можно легко модифицировать, поэтому для всех, кто заинтересован, вы также можете сделать то, что я хотел, с приведенным ниже кодом:
void Update() {
var actualTarget = _enemy.transform.position;
var targetDir = actualTarget - transform.position;
var target = Quaternion.LookRotation(targetDir.normalized, transform.up);
var actual = Quaternion.Inverse(transform.parent.rotation) * target;
actual.eulerAngles = ClampRotation(actual.eulerAngles);
var targetRotation = Quaternion.Slerp(transform.localRotation, actual, 8 * Time.deltaTime);
transform.localRotation = targetRotation;
}
private static Vector3 ClampRotation(Vector3 newRotation) {
var x = Clamp(newRotation.x, -179, 179);
var y = Clamp(newRotation.y, -45, 45);
return new Vector3(x, y, 0);
}
private static float Clamp(float angle, float min, float max) {
if ((angle <= 180 && angle >= 180 - Mathf.Abs(min)) || (angle >= 180 && angle <= 180 + max)) {
return Mathf.Clamp(angle, 180 - Mathf.Abs(min), 180 + max);
}
if (angle > 180f) {
angle -= 360f;
}
angle = Mathf.Clamp(angle, min, max);
if (angle < 0f) {
angle += 360f;
}
if (Mathf.Abs(angle) == 360) {
angle = 0;
}
return angle;
}
Думаю, ответа пока нет, потому что люди не понимают, в чем проблема. Вы говорите, что он вращается, но в чем проблема? Любой анимированный gif, чтобы показать, что происходит сейчас и чего вы ожидаете?