2
votes

I currently have a little issue with a script I made. Basically, I want to create a script that makes its GameObject (let's name it A) and follows another GameObject's (named B) position. I know a simple way to do that would be to parent A to B, but I'm not doing it for two reasons : 1) I want to be able to apply a smoothing (whose value I can change) on A's movement; 2) I want to be able to make A follow B's position and/or rotation at will.

Here is the script I wrote :

using UnityEngine;
using System.Collections;

public class FollowGameObject : MonoBehaviour {

public GameObject m_GameObjectToFollow;
public bool m_FollowPosition;
public bool m_FollowRotation;
public float m_PositionSmoothing;
public float m_RotationSmoothing;
// Should not be changed once set
public bool m_UseOffsetPosition;
public bool m_UseOffsetRotation;
private Vector3 m_PositionOffset;
private Quaternion m_RotationOffset;

void Start () {

    m_PositionSmoothing = Mathf.Clamp(m_PositionSmoothing, 0.0f, 1.0f);
    m_RotationSmoothing = Mathf.Clamp(m_RotationSmoothing, 0.0f, 1.0f);

    if (m_UseOffsetPosition)
    {
        m_PositionOffset = transform.position - m_GameObjectToFollow.transform.position;
    } else {
        m_PositionOffset = Vector3.zero;
    }

    if (m_UseOffsetRotation)
    {
        m_RotationOffset = transform.rotation * Quaternion.Inverse(m_GameObjectToFollow.transform.rotation);
    } else {
        m_RotationOffset = Quaternion.identity;
    }

}

void FixedUpdate () {

    if (m_FollowPosition) {
        Vector3 goalPosition = m_GameObjectToFollow.transform.position + m_PositionOffset;
        transform.position = Vector3.Lerp(transform.position, goalPosition, m_PositionSmoothing);
        //transform.Translate(newPosition - transform.position, Space.World);
    }

    if (m_FollowRotation) {
        Quaternion goalRotation = m_GameObjectToFollow.transform.rotation * m_RotationOffset;
        transform.rotation = Quaternion.Lerp(transform.rotation, goalRotation, m_RotationSmoothing);
    }

}

I hope the code is easily understandable, if not feel free to ask. In any case, once I attach this script to A and assign its m_GameObjectToFollow attribute to B (B is parented to a character controller, and I parented a sphere renderer to A so I can see if it follows B correctly), I notice that A is indeed following B, but I see that its position (through the sphere renderer) is "fluctuating" between the "right" position (B's) and another one. Visually, the sphere is flickering. I tried putting the smoothing values to 1 (i.e. A should always be at B's position/rotation). I still see a flickering.

Could someone explain to me what I did wrong?

EDIT : Seems like I'm using Lerp the wrong way with its last value. I modified the script to use speed values instead of smoothing values, but still the same problem when I try to create some smooth movements (with lower speed values). I have troubles explaining the problem properly. The best way to see what the problem look like would be to experience it yourself : 1) Create a scene with a terrain and a character controller in it; 2) Parent the main camera to the controller (so that it always follows it); 3) Create a new GameObject with a renderer (for example, a sphere), not parented to any other GameObject, but attach the following script to it :

using UnityEngine;

using System.Collections;

public class FollowGameObject : MonoBehaviour {

public GameObject m_GameObjectToFollow;
public bool m_FollowPosition;
public bool m_FollowRotation;
// Betzeen 0 and 1. 1 means that a complete unsmoothed follow
public float m_PositionFollowSpeed;
public float m_RotationFollowSpeed;
// Should not be changed once set
public bool m_UseOffsetPosition;
public bool m_UseOffsetRotation;
private Vector3 m_PositionOffset;
private Quaternion m_RotationOffset;

void Start () {

    if (m_UseOffsetPosition)
    {
        m_PositionOffset = transform.position - m_GameObjectToFollow.transform.position;
    } else {
        m_PositionOffset = Vector3.zero;
    }

    if (m_UseOffsetRotation)
    {
        m_RotationOffset = transform.rotation * Quaternion.Inverse(m_GameObjectToFollow.transform.rotation);
    } else {
        m_RotationOffset = Quaternion.identity;
    }

}

void Update () {

    if (m_FollowPosition) {
        Vector3 goalPosition = m_GameObjectToFollow.transform.position + m_PositionOffset;
        transform.position = Vector3.Slerp(transform.position, goalPosition, Time.deltaTime * m_PositionFollowSpeed);
    }

    if (m_FollowRotation) {
        Quaternion goalRotation = m_GameObjectToFollow.transform.rotation * m_RotationOffset;
        transform.rotation = Quaternion.Slerp(transform.rotation, goalRotation, Time.deltaTime * m_RotationFollowSpeed);
    }

}

}

With : m_GameObjectToFollow = the character controller GameObject;

m_FollowPosition = true;

m_PositionFollowSpeed = 10;

(The other parameters values don't matter for this test)

Now start the scene and move the character controller, I will see the sphere flickering during motion, but if you stop moving it will smoothly go to the controller.

1
I completely understand why to not use parent and child objects too much. :)ʇolɐǝz ǝɥʇ qoq
In your start method you use two times m_UseOffsetPosition. I think you may want to use m_UseOffsetRotation in the second if, the one for the rotation. Also, m_RotationSmoothing = Mathf.Clamp(m_PositionSmoothing, 0.0f, 1.0f); shouldn't be with m_RotationSmoothing inside instead of m_PositionSmoothing?Gounemond
Maaannn you're right, sorry (that's what happens when you just copy/paste without focus lol). Fixed it, but the problem still remains. I also posted the same question in the Unity forums and seems like I'm not using Lerp correctly (I shouldn't use a fixed value as last parameter but a something like "Time.deltaTime * speed" instead. I tried it and get better results with high speed values (which give pretty much the same result as a parenting), but with lower speed values (with should give some smoothing) I still get the flickering...PurpleMatter
I edited my original thread, look after "EDIT" to see the new script I'm testing and the way to experience the problem yourself.PurpleMatter

1 Answers

0
votes

You are using FixedUpdate. Is there any special reason to do so?

Anyway, try to use Update or LateUpdate instead of FixedUpdate or check Fixed Timestep in Project Settings => Time.

Also read the answer to this question for more information about difference between Update and FixedUpdate.