Почему при перемещении объекта к цели, если цель находится далеко, объект движется очень быстро, но если цель близка, она движется медленнее?

#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. Вероятно.