0
\$\begingroup\$

Context: infinite runner, stationary player, obstacles move toward player. I have an asteroid that currently Vector3.MoveTowards a moving target e.g. a "rubble" object spawns hidden far away from player and moves toward player. At time of spawn, an asteroid spawns well above it and starts moving toward the rubble. When they collide, rubble appears, asteroid disappears, boom, particles, etc.

TL;DR

I want a kinematic object to track high for awhile and dive bomb at the last minute to crash into a moving target with variable speed (final location unknown.) I also want animation curves to tweak the speed and dive bomb effects.

The meat

The goal: I'd like the asteroid to track mostly high until some time close to impact and then sort of dive bomb down toward the rubble. I want to control the speed with an animation curve in the inspector. Bonus points if I can control the "dive bomb" intensity with another animation curve. I'd like to keep the motion smooth (I thought of maybe trying to calculate

The problem: The current path of motion is lame. The asteroid just gradually moves down and sort of asymptotically (to the ground) hits the rubble since I'm just using Vector3.MoveTowards with a moving target. Even if I try to control its speed over time, it's not what I'm looking for. The game speed also changes variably, so it would be tricky at best to figure out the actual final destination of the target.

How can I keep the asteroid high-ish until a point, then start dive bombing for a more dramatic crash? I'm thinking somehow the distance and/or time need to be normalized to use the animation curve, but I don't know how to do it when the target moves variably. I've attempted to normalize it, but maybe just can't get the math right. Can time spent traveling be normalized if you don't know how long it will travel?

The current lame code:

timeSinceStart += Time.deltaTime;

float baseSpeed = GameManager.gm.speed * gameSpeedMultiplier;

float adjustedSpeed = baseSpeed * speedCurve.Evaluate(timeSinceStart);

float step = adjustedSpeed * Time.deltaTime;

transform.position = Vector3.MoveTowards(transform.position, target.transform.position, step);

transform.Rotate(randomRotation, rotationSpeed * Time.deltaTime);

Update: sketched image

  • A == asteroid
  • R == rubble/target
  • P == player

enter image description here

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

This is how I would do it:

The first thing you would need to do is calculate a vector from the position of the asteroid to the end position.

Vector 3 direction = (transform.position - endPosition);

We can then use the equation \$Speed = Distance / Time\$ to calculate the speed needed.

For example if we want the asteroid to travel 10 units in a time of 5 seconds we can input the values into the equation to calculate how many units per second we need to move:

(U = Unity Units)

\$U/s = 10 / 5\$

or in other words, 2U/s.

Here's how we can implement this inside of Unity:

We can create an IEnemerator to do things over time:

private IEnumerator DropAsteroid(float duration, AnimationCurve speedCurve)
{
    float elapsed = 0f;
    Vector3 direction = (transform.position - endPosition);
    Vector3 speed = direction / duration;

    while (elapsed < duration)
    {
        Vector3 velo = speed * speedCurve.Evaluate(elapsed / duration);
        m_Rigidbody.velocity = velo;
        elapsed += Time.deltaTime;
    }
}

Hope that helps. (also this is untested code so any issues let me know and ill try to help.)

\$\endgroup\$
6
  • \$\begingroup\$ Please correct me if I'm wrong, but I don't think you accounted for (final location unknown.) The game speed increases variably, therefore the speed (and location) of the target changes variably since it is moving toward the stationary player. So, I don't think direction in your code can be calculated (or at least not that simply) \$\endgroup\$
    – David Fox
    Mar 24 at 21:44
  • \$\begingroup\$ the game speed changing would be accounted for in the physics of the rigidbody, and you must know the final location, you said it yourself, its the position of the player, so just use player.transform.position; \$\endgroup\$
    – Pow
    Mar 24 at 22:23
  • \$\begingroup\$ the target of the asteroid is not the player. the target moves in the negative-z direction from its point of spawn to some point in front of the player (when the asteroid "lands" and the rubble is revealed. the rubble then continues moving toward the player. this movement is not physics-based; it is kinematic. both time and distance are unknown in this problem. your solution offers both as knowns. \$\endgroup\$
    – David Fox
    Mar 25 at 2:35
  • \$\begingroup\$ distance is not a known, it is calculated from the asteroids position (transform.position) and the end position (endPosition), if you want the asteroid to fall infront of the rubble as its moving, you could just use Vector3 endPos = rubble.transform.position; endPos += endPos.normalized * lengthInfrontOfRubble \$\endgroup\$
    – Pow
    Mar 25 at 8:58
  • \$\begingroup\$ end position is not known--the target moves with variable speed. \$\endgroup\$
    – David Fox
    Mar 25 at 13:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .