I want an Object lerping in the y-axis to move alo

2019-08-31 09:46发布

问题:

I'm currently making a runner type game that is not randomly generated in Unity. The player, camera and background stay in the same place (the player movement is clamped) and the hazards come towards the player along the negative Z-Axis with this simple lines of code:

public float speed;

private Rigidbody rb;

void Start () {
    rb = GetComponent<Rigidbody> ();
    rb.velocity = transform.forward * -speed;
}

And it works fine. Now I want to add asteroids that not only come towards the player, but they move up and down (and repeat) and I tried doing this with Lerp(). I'm not a pro about Lerp so I used a code that I found online that works:

public Transform startPos, endPos;
public bool repeatable = true;
public float speed = 1.0f;
public float duration = 3.0f;

float startTime, totalDistance;

IEnumerator Start () {
    startTime = Time.time;

    while(repeatable) {
        yield return RepeatLerp(startPos.position, endPos.position, duration);
        yield return RepeatLerp(endPos.position, startPos.position, duration);
    }
}

void Update () {
    totalDistance = Vector3.Distance(startPos.position, endPos.position);
    if(!repeatable) {
        float currentDuration = (Time.time - startTime) * speed;
        float journeyFraction = currentDuration / totalDistance;
        this.transform.position = Vector3.Lerp(startPos.position, endPos.position, journeyFraction);
    }
}

public IEnumerator RepeatLerp(Vector3 a, Vector3 b, float time) {
    float i = 0.0f;
    float rate = (1.0f / time) * speed;
    while (i < 1.0f) {
        i += Time.deltaTime * rate;
        this.transform.position = Vector3.Lerp(a, b, i);
        yield return null;
    }
}

What I did is create 2 Empty Objects for the start and end positions and then I put the hazard and two lerping points under another Empty Object, let's call it Parent (So Parent > -Hazard -Start - End). Then I added the moving script along the Z-Axis to the parent empty and it kinda works but is like jumping. So the lerping works but it does not move along the Z-Axis until the lerping function is done, the the object jumps to the new Position in the Z-Axis. So it looks very jumpy and glitchy.

How can I do this so is a smooth movement along the Z-Axis and the lerp still works along the Y?

Thanks!!

PS: I know I could just move the character and camera etc, but for now I would like to keep it this way.

回答1:

The coroutine RepeatLerp acts across several frames, but receives input of type Vector3. The actual position of a reference point will change over time, but the argument values a and b do not change until the coroutine terminates.

So the immediate solution is simple: instead of passing Vector3, pass reference to Transform, and grab its new position each frame. Change your function to this:

public IEnumerator RepeatLerp(Transform a, Transform b, float time)
{
    float i = 0.0f;
    float rate = (1.0f / time) * speed;
    while (i < 1.0f)
    {
        i += Time.deltaTime * rate;
        this.transform.position = Vector3.Lerp(a.position, b.position, i);
        yield return null;
    }
}

And in Start funtion the invocation will now be:

yield return RepeatLerp(startPos, endPos, duration);
yield return RepeatLerp(endPos, startPos, duration);

This will solve your problem, however, having said that, I strongly suggest you reconsider the way you move your object. You have a mix of Rigidbody semantics with moving objects using transform, which is a really bad practice. The engine is not designed to do that and it may cause great performance issues in the future.

In general, if you have colliders on your objects (and it looks like you have) you should move your objects around using only Rigidbody and applying velocity / forces to it. Maybe have a look at Rigidbody.MovePosition if you want to use Lerp, but even better use Rigidbody.velocity, like for example (the code below is just schematic):

if (transform.position.x > highLimit) rigidbody.velocity -= 2*pulsingSpeed;
if (transform.position.x < lowLimit) rigidbody.velocity += 2*pulsingSpeed;