1
\$\begingroup\$

as the title of the question says, I was wondering if there is common method to make gameObjects e.g. enemies or bullets follow curvilinear trajectories before reaching their target. For instance, assuming to be talking about a top-down 2D game, there are multiple ways to make an gameobject, say an enemy follow a straight line like this to go hit the player:

enter image description here

But how to make it so that before reaching the player it would do something like this?

enter image description here

Does somebody have an idea?

I know that the question may sound not too specific, therefore for sake of argument, how could I make so that a bullet shot from an enemy follows an arch "à la Wanted" before hitting the player instead of just flying straight?

\$\endgroup\$
  • 2
    \$\begingroup\$ There are as many ways to do this as there are curves you might want the object to follow. Can you boil this down to something more specific? Presumably you've already looked at things like sinusoids and splines? \$\endgroup\$ – DMGregory Jul 24 at 21:03
  • \$\begingroup\$ Yes i did, and I was wondering exactly about this: is the most widely used way to code the trajectories using mathematical formulae, or there are other methodologies that are used? I am using Unity, therefore the most straightforward thing would be to see if there was some component that would do the trick, but at this point I am just curious to see all the alternatives now. I will add an example to see try and make some clarity. \$\endgroup\$ – FSic Jul 25 at 7:10
  • 2
    \$\begingroup\$ I don't know anything about unity, but you could use bezier curves or quadradic curves to achieve this very easily. math.stackexchange.com/questions/2382566/… \$\endgroup\$ – NeomerArcana Jul 25 at 8:13
  • \$\begingroup\$ The thing about bezier curves is that you have to determine the control points. In case of an animation which repeats itself in the same place and in the same way it would be ok, I just set the points and write the mathematical formula. I think that the problem however would be when the object shooting changes its position and orientation, because at that point you should be update every time the position of the control points, right? \$\endgroup\$ – FSic Jul 25 at 8:21
  • 1
    \$\begingroup\$ Effective? Yes. Efficient? Probably. Rotation is a couple of multiplications. \$\endgroup\$ – NeomerArcana Jul 25 at 9:30
1
\$\begingroup\$

To add on to the discussion I think Bezier curves are good approach, and in terms of recalculating them you can pre-bake some curves and modify their points based on requirements, so the impact should not be heavy (less so in 2D)

Since you are working in 2D getting started is a bit easier, and ignore the z-axis (or y in unity, depending on your dominant hand :P )

Anyway. I just wanted to add these resources for you or anyone else who happens on this thread.

Have a look at this post. It is very in depth, but very useful I think.

There is also this Youtube series that I think might help:

Part 1 Bezier Curves in Unity: Linear Curve

Part 2 Bezier Curves in Unity: Quadratic Curve

Part 3 Bezier Curves in Unity: Cubic Curve

Good luck.

\$\endgroup\$
  • \$\begingroup\$ Thanks for adding this material, it is pretty neat! Perhaps they go a bit beyond the scope of the question, but as you said they can be quite useful for somebody looking for additional info. \$\endgroup\$ – FSic Aug 7 at 7:42
0
\$\begingroup\$

After some delay, here is my solution:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BezierShoot : MonoBehaviour
{
[SerializeField] GameObject target;
[SerializeField] Transform controlPoint0;
[SerializeField] Transform controlPoint1;
[SerializeField] Transform controlPoint2;
[SerializeField] Transform controlPoint3;
[SerializeField] GameObject pointerPrefab;//used during debugging, not necessary
[SerializeField] GameObject shotPrefab;
[SerializeField] float speed = 5f;
[SerializeField] float t = 0;//the parameter for the bezier curve
/**
     I want to try and make 2 points, one third and two thirds distance from player to object.
    1) I find the 1/4 and 3/4 distance on the connecting line
    2) I get the normalized distance from the new points from the target
    3) I get the perpendicular vector with respect to each point and the target and multiply by the distance parameter
    3.1) obtaining vector coordinates: I have direction tempDir
        normDir.x = tempDir.y
        normDir.y = -tempDir.x
     */

private void Update()
{
    if (Input.GetKeyDown(KeyCode.B))
    {
        CreateControlPoint1();
        CreateControlPoint2();
        StartCoroutine(BezierShooting());
    }
}

private void CreateControlPoint1()
{
    controlPoint0 = transform;
    controlPoint3 = target.transform;
    //the position of the control point will be taken at 1/4 the distance between the initial and the target point, which will act as first and last control points for the bezier curve        
    controlPoint1.position = new Vector3(controlPoint0.position.x + (controlPoint3.position.x - controlPoint0.position.x)/4, controlPoint0.position.y + (controlPoint3.position.y - controlPoint0.position.y)/4, 0);
    //in order to determine lateral displacement i derive the vector perpendicular to the one connecting first and last control points
    Vector2 tempDir = new Vector2((controlPoint3.position.x - controlPoint1.position.x),(controlPoint3.position.y - controlPoint1.position.y));
    tempDir.Normalize();
    Vector2 normDir;
    normDir.x = tempDir.y;
    normDir.y = -tempDir.x;
    //i translate the control point by the desired amount sideways
    controlPoint1.Translate(-normDir.x * 2f, -normDir.y * 2f, 0);
}

private void CreateControlPoint2()
{
    controlPoint0 = transform;
    controlPoint3 = target.transform;

    controlPoint2.position = new Vector3(controlPoint0.position.x + (controlPoint3.position.x - controlPoint0.position.x)*3 / 4, controlPoint0.position.y + (controlPoint3.position.y - controlPoint0.position.y)*3 / 4, 0);
    Vector2 tempDir = new Vector2((controlPoint3.position.x - controlPoint2.position.x), (controlPoint3.position.y - controlPoint2.position.y));
    tempDir.Normalize();
    Vector2 normDir;
    normDir.x = tempDir.y;
    normDir.y = -tempDir.x;

    controlPoint2.Translate(-normDir.x * 2f, -normDir.y * 2f, 0);
}


private IEnumerator BezierShooting()
{
    var shotInstance = Instantiate(shotPrefab, transform.position, Quaternion.identity);//instantiate the bullet
    //the parameter for the bezier curve goes from 0 to 1, therefore it has been initialised to 0 and 
    //the loop for the trajectory will go on until t=1 i.e. the bullet reached the target or hit something along the road
    while (t < 1 && shotInstance != null)
    {
        float invT = 1f - t;
        //the bezier curve equation. 4 points define a cubic bezier curve
        var currentPosition = invT * invT * invT * controlPoint0.position
                            + 3 * invT * invT * t * controlPoint1.position
                            + 3 * invT * t * t * controlPoint2.position
                            + t * t * t * controlPoint3.position;
        shotInstance.transform.position = currentPosition;
        t += Time.deltaTime / 1f;
        yield return null;
    }

    t = 0;
}

}

What it simply does is 1) creating 2 points that will be used as intermediate control points by temporarily creating two "axes", one in the direction from the first control point to the target, acting as my yHat let's say, and the other going perpendicularly to the previous. These will be used in the coroutine BezierShooting() to define the curve that the bullet will follow.

It is far from optimal, starting from the fact that I use two identical functions to create a single control point everytime (i started by doing it in the same function, literally just adding '2' to all that was referred to the second control point, but it always ended up spawining the control points in the same position) or from the fact that the bullet is moved by directly changing its transform position, whereas i would have preferred to work with the rigidbody, but in the end it works and the bullets travel very nicely ;) hope it can be helpful to somebody!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.