#c# #unity3d
#c# #unity3d
Вопрос:
Я хочу, чтобы он двигался медленнее, как у объектов с близкого расстояния.
Маленький кубик перемещается из руки игрока в правый большой куб. Правильный большой куб является целью.
Это корневой объект игрока с прикрепленным к нему скриптом, скорость броска установлена на 0,5 f
Это сценарий в обновлении, который я вызываю методом ThrowObject :
using UnityEngine;
using System;
using System.Collections;
using UnityEngine.UI;
using System.Collections.Generic;
[RequireComponent(typeof(Animator))]
public class IKControl : MonoBehaviour
{
public InteractableItem[] lookObj = null;
public GameObject objToThrow;
public Text text;
public Text textMultiLine;
public float weightDamping = 1.5f;
public float maxDistance = 10f;
public bool RightHandToTarget = true;
public float throwSpeed;
private List<InteractableItem> allDetectedItems;
private Animator animator;
private InteractableItem lastPrimaryTarget;
private Quaternion savedRotation;
private float lerpEndDistance = 0.1f;
private float finalLookWeight = 0;
private bool transitionToNextTarget = false;
private InteractableItem target;
private bool throwObj = false;
void Start()
{
animator = GetComponent<Animator>();
allDetectedItems = new List<InteractableItem>();
}
// Callback for calculating IK
void OnAnimatorIK()
{
if (lookObj != null)
{
InteractableItem primaryTarget = null;
float closestLookWeight = 0;
// Here we find the target which is closest (by angle) to the players view line
allDetectedItems.Clear();
foreach (InteractableItem target in lookObj)
{
Vector3 lookAt = target.transform.position - transform.position;
lookAt.y = 0f;
// Filter out all objects that are too far away
//if (lookAt.magnitude > maxDistance) continue;
if (lookAt.magnitude > target.distance) continue;
float dotProduct = Vector3.Dot(new Vector3(transform.forward.x, 0f, transform.forward.z).normalized, lookAt.normalized);
float lookWeight = Mathf.Clamp(dotProduct, 0f, 1f);
if (lookWeight > 0.1f amp;amp; lookWeight > closestLookWeight)
{
closestLookWeight = lookWeight;
primaryTarget = target;
allDetectedItems.Add(target);
}
}
if (primaryTarget != null)
{
if ((lastPrimaryTarget != null) amp;amp; (lastPrimaryTarget != primaryTarget) amp;amp; (finalLookWeight > 0f))
{
// Here we start a new transition because the player looks already to a target but
// we have found another target the player should look at
transitionToNextTarget = true;
}
}
// The player is in a neutral look position but has found a new target
if ((primaryTarget != null) amp;amp; !transitionToNextTarget)
{
lastPrimaryTarget = primaryTarget;
//finalLookWeight = Mathf.Lerp(finalLookWeight, closestLookWeight, Time.deltaTime * weightDamping);
finalLookWeight = Mathf.Lerp(finalLookWeight, 1f, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .75f;
animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(primaryTarget.transform.position);
if (RightHandToTarget)
{
Vector3 relativePos = primaryTarget.transform.position - transform.position;
Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight * 1f * closestLookWeight);
animator.SetIKPosition(AvatarIKGoal.RightHand, primaryTarget.transform.position);
// -> new code block
if (finalLookWeight > 0.95f) // here you can play with a value between 0.95f -> 1.0f
{
// call your funtion to shoot something here
throwObj = true;
target = primaryTarget;
}
}
}
// Let the player smoothly look away from the last target to the neutral look position
if ((primaryTarget == null amp;amp; lastPrimaryTarget != null) || transitionToNextTarget)
{
finalLookWeight = Mathf.Lerp(finalLookWeight, 0f, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .75f;
animator.SetLookAtWeight(finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(lastPrimaryTarget.transform.position);
if (RightHandToTarget)
{
Vector3 relativePos = lastPrimaryTarget.transform.position - transform.position;
Quaternion rotationtoTarget = Quaternion.LookRotation(relativePos, Vector3.up);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, finalLookWeight);
animator.SetIKRotation(AvatarIKGoal.RightHand, rotationtoTarget);
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, finalLookWeight * 0.5f * closestLookWeight);
animator.SetIKPosition(AvatarIKGoal.RightHand, lastPrimaryTarget.transform.position);
}
if (finalLookWeight < lerpEndDistance)
{
transitionToNextTarget = false;
finalLookWeight = 0f;
lastPrimaryTarget = null;
}
}
// Show primary object found by the player
if (primaryTarget != null) text.text = "Item found: " primaryTarget.description;
else text.text = "Item found: none";
// Show all objects found by the player
if (allDetectedItems.Count > 0)
{
string result = "";
foreach (InteractableItem item in allDetectedItems)
{
result = item.description "n";
}
textMultiLine.text = resu<
}
else
{
textMultiLine.text = "No items found.";
}
}
}
private void ThrowObject()
{
objToThrow.transform.position = Vector3.Lerp(objToThrow.transform.position, target.transform.position, throwSpeed * Time.deltaTime);
}
private void Update()
{
if (throwObj == true)
{
ThrowObject();
}
}
}
Проблема в том, что когда игрок сталкивается с большим дальним космическим кораблем, а куб движется к космическому кораблю, он движется очень быстро, я почти не вижу, как движется куб. Не уверен, почему он движется медленно, плавно к близким целям, но очень быстро к дальним целям?
Комментарии:
1. Как предложил @Максим Фисман, я бы использовал
Vector3.MoveTowards
вместоVector3.Lerp
Ответ №1:
Для перемещения вы используете функцию Vector3.Lerp(Vector3 a, Vector3 b, float t). Он находит значение interectabke между a
и b
с помощью formula: a (b - a) * t
.
давайте предположим, что z-позиция не имеет значения, а главное положение объекта [0,0] Давайте рассмотрим следующие ситуации:
- Целевой объект находится рядом с основным. Его положение [10, 10]. Наш основной объект перемещается из начальной позиции в целевую с помощью переменной
float t
. Давайте посчитаем положение основного объекта, еслиt
это, например:0.1
,0.2
,0.3
(очевидно, что если это так, то0
положение основного объекта является начальной позицией, а если это так, то1
положение основного объекта является целевой позицией: ФОРМУЛА: a (b — a) * t
1) [0,0] ([10,10] - [0,0]) * 0.1 = [0,0] [10,10]*0.1 = [0,0] [1,1] = [1,1]
2) [0,0] ([10,10] - [0,0]) * 0.2 = [0,0] [10,10]*0.2 = [0,0] [2,2] = [2,2]
3) [0,0] ([10,10] - [0,0]) * 0.3 = [0,0] [10,10]*0.3 = [0,0] [3,3] = [3,3]
Мы получаем, что изменение переменной t
на 0,1 приводит к изменению положения на [1,1] единиц.
- Целевой объект находится в 50 раз дальше, чем в первом случае. Его положение теперь [500,500]. И мы оставляем
t
как это было:0.1 and 0.2 and 0.3
. Количество: ФОРМУЛА: a (b — a) * t
1) [0,0] ([500,500] - [0,0]) * 0.1 = [0,0] [500,500]*0.1 = [0,0] [50,50] = [50,50]
2) [0,0] ([500,500] - [0,0]) * 0.2 = [0,0] [500,500]*0.2 = [0,0] [100,100] = [100,100]
3) [0,0] ([500,500] - [0,0]) * 0.3 = [0,0] [500,500]*0.3 = [0,0] [150,150] = [150,150]
Здесь уменьшение переменной t
на 0,1 приводит к изменению положения на [50,50] единиц.
ТАКИМ образом, чем больше расстояние между объектами, тем быстрее изменяется положение основного объекта.
Ну, это было объяснение того, что вы делаете неправильно. Теперь решение:
Вам следует использовать функцию transform.Translate (перевод Vector3).
Эта функция перемещает объект в направлении параметра Vector3 translate. Конечно, если перевод равен [1,0,0], объект перемещается в положительное значение x, если [-1,0,0] — в отрицательное значение x, если [0,1,0] — в положительное значение y, если [0,-1,0] — в отрицательное значение y и так далее.
Как получить этот Vector3 translation
? Вы должны вычесть положение вашего объекта из положения цели. И тогда вы должны нормализовать его (так, чтобы значения были не больше 1 и не меньше 0). Код выглядит так:
Vector3 dir; // direction of moving. This parameter will be given to the function Translate()
GameObject targetPosition; // Target position
float speed; // The speed of moving. Recommended to be set from inspector
private void ThrowObject () {
dir = targetPosition - transform.position;
transform.Traslate(dir.normalized*Time.deltaTime*speed);
}
private void Update () {
ThrowObject();
}
P.S. Мы умножаем dir
на Time.deltaTime
, чтобы скорость перемещения была одинаковой как на быстрых, так и на медленных компьютерах (планшеты, телефоны …)
Комментарии:
1. Или вы можете использовать Vector3.MoveTowards. Вероятно.