Diagonal Shooting

Stupid Question here, i’m in the Garden Glitch part where we instantiate a projectile from the gun to shoot forward, but it what if i would like to shoot it in a specific angle or direction? how could i do ? i tried searching a bit but i’m a little confused about the topic
like what if i would like to do a 45° shoot, in the past i got in other projects my projectile follow some fixed paths made by other pivot points in the scene, but i would like to understand better how to easily do some “advanced” directions

  void Update()
    {
        transform.Translate(Vector3.right * ProjectileSpeed * Time.deltaTime, Space.World);

}

*little update , i got a 45 angle by doing this

transform.Translate((Vector3.right+ Vector3.up) * ProjectileSpeed * Time.deltaTime, Space.World);

but WHAT could i do control better the angle i choose the projectile to be shoot? like idk a 67° shoot

1 Like

There are several ways to achieve this but all comes down to vector math and rotations.

Consider that each object has two type of scales and rotations; global and local, this is very important because based on this you can give all sorts of directions to a missile or even calculate if the player is in front of an enemy.

Let’s say you have an object, then, you write this block of code to a script and attach it to that object:

    void Update()
    {
        transform.Translate(Vector2.right, Space.World);
    }

The object will move to its right regardless of rotation, but what if you change the line to this: transform.Translate(Vector2.right, Space.Self);, the object will move completely different based on its rotation, the difference is that the first uses a global vector, while the second uses the local vector. You can even see the difference in the Editor window if you press the Global buttton at the right of the selection tools!

Editor

In the image below, the triangles on the left are using a global direction while the ones on the right are using a local direction, it changes quite a lot.

This way you can pass down the rotation of something to a moving object. That’s usually how Twin Stick games work (Enter The Gungeon, The Ascent), you have a character that rotates and when it shoots, it pases down his local direction to the missiles making them move to where the character is aiming.

There are many other ways to achieve that, like subtracting vectors to get the direction between the two.

It’s better if you test things out by yourself, so why not copy-paste the code below and have fun with it. Attach this to any 2D object and play with the exposed variables and the Z rotation.

    [SerializeField] float speed = 0.1f;
    [SerializeField] bool useGlobalDirection = true;

    void Update()
    {
        Space spaceType = useGlobalDirection ? Space.World : Space.Self;

        transform.Translate(Vector2.right * speed * Time.deltaTime, spaceType);
    }

Keep in mind that you won’t always have acces to the Space type, in those cases to get the local direction of an object you can use the transform type; transform.right, transform.forward, or transform.up will always return you the local direction of the transform.

1 Like

Hey there!

So do this you can use a little bit of trigonometry. Basically, you can create a vector based on the Cosine and Sin of an angle, the ‘direction’ will be the hypotenuse of that ‘triangle’. To do this in Unity, you first need to convert your angle to radians, and then create a new vector based on this. Here’s a quick example you can use in the Unity editor to see it visualised:

[SerializeField] float angle; //set this to anything you like

private void OnDrawGizmos()
{
   Handles.DrawLine(transform.position, GetVectorFromAngle());
}

private Vector3 GetVectorFromAngle()
{
   float angleInRadians = angle * Mathf.Deg2Rad;
    return new Vector2(Mathf.Cos(angleInRadians), Mathf.Sin(angleInRadians));
}

Here’s a more in depth example which explains some of the caveats when using this with Unity – mostly to do with how the degrees are different than the standard unit circle in Unity:

1 Like

Hi guys, you have been really helpful to me, i’m reading carefully both your replies
So from what i understood, you have shown to me some different path to follow, one a little more “manual” and another with trigonometry (which was the first thing i was trying to do)

So at first as suggested by Yee i put a simple round object and checked the “local” coordinates on top , i rotate this as i want it to be and i’ll render it as invisible later
so now i can use this as a sort of “sight” which i can aim at the direction i want the projectile to follow, all i’ll need to do is to rotate the object and give the local rotation of the gun as the direction of the projectile.
And doing so i can trick the system to think for example that “forward” is the angle i choose it to be
so basically i did this and changed the code by space.world to space.self

transform.Translate(Vector3.right * ProjectileSpeed * Time.deltaTime, Space.self);


This is working pretty good

only problem i’m trying to resolve is that at first i was shooting the knife rotating in the air
like this
image

this was the code

  transform.Translate(Vector3.right * ProjectileSpeed * Time.deltaTime, Space.World); 
   transform.Rotate( Vector3.forward* SpinSpeed * Time.deltaTime);

BUT now it goes like this:
image

spinning around the object, and not going forward, i mean maybe that is logical for the local coordinates but how can i fix this ?

after this i’ll proceed to try the trigonometric way showed me by [heckadactyl] thank you guys!

1 Like

You can fix it in many ways, you can child the sprite to an empty game object to move the parent and rotate the child, or use the parent’s local vectors instead.

If you simply want to shoot something at a certain angle use @heckadactyl method, if you want to aim at something then use vectors otherwise you’ll need to get the vectors to get the angle to get a vector.

[Edit]
I forgot to mention, don’t try to code everything, sometimes is better to simply animate things instead, like the spin of your knife, that won’t fix anything, but the less code the better.

1 Like

Thank you Yee, yeah your advice about animating is good, but about now i need to solve this little problems to better understand how things here works, so i can understand how to use these tools in the future.

I’ll try to do the parent child thing you mentioned, even if i didn’t really understood it at 100% ahahaha

1 Like

I tried doing this, but it didn’t gave me the results i hoped
image

 void Update()
    {
        
        transform.Translate(Vector3.right * ProjectileSpeed * Time.deltaTime, Space.Self); 
        transform.parent.Rotate(Vector3.forward * SpinSpeed * Time.deltaTime, Space.World);
  
    }

what am i doing wrong?

1 Like

That’s almost right, instead, try rotating the child and move the parent.

transform.parent.Translate(Vector3.right * projectileSpeed * Time.deltaTime, Space.Self);
transform.Rotate(Vector3.forward * spinSpeed * Time.deltaTime);
1 Like

Hi , sorry for the late reply but it got busy in these days, i wen ahead with the course and changed a lot of things, also in the hierarchy , but i wanted to still try this and i still didn’t get it to work by code when i am in local, the rotation keep beeing based on the father position .
i changed the hierarchy and gave all the scripts and rigidbody to the father, the child now has only a sprite renderer
(if i have to be honest i abandoned also the Transform.translate for moving things and adopted the rigidbody.moveposition cause it works a lot better with high speeds, but as for now the only method i got to work for shoot at a direction i want and also rotate is by doing the rotation an animation, but it would be cool to also solve this by code)
as mentioned the

transform.parent.Translate(Vector3.right * projectileSpeed * Time.deltaTime, Space.Self);
transform.Rotate(Vector3.forward * spinSpeed * Time.deltaTime);

keeps getting me the spinning around a Circle rather than on self

how i changed it as for now is

  Transform tr;
    void Start()
    {
        tr = GetComponentInChildren<Transform>();
    }

    void Update()
    {       
        transform.Translate(Vector3.right * ProjectileSpeed * Time.deltaTime, Space.Self);
        tr.Rotate(Vector3.forward * SpinSpeed * Time.deltaTime);
    }
1 Like

also when i go to the properties it is always the rotation of the parent to change
image

never the child one
image

it’s like he doesn’t care i wrote all that stuff above hahha i want the exact opposite
the child with the sprite should just rotate
while the father get moving along it’s path

it bothers me that i manage to get this behavior only by animating

1 Like

That happens because when you use the GetComponentInChildren method, the object that has the script attached will count itself as a child, so it will get the transform from itself, which is hilarious, I have no clue why they decided to make that work that way.

To avoid that you can get another component that the father doesn’t have, like the sprite renderer.

tr = GetComponentInChildren<SpriteRenderer>().transform;

Or to make it more flexible, just expose the variable and set it in the editor.

[SerializeField] Transform objectToRotate = null;
1 Like

Yeah dude thank you that worked hahahaha can’t believe it was that the issue.

Now i would like try to get this behavior also with the rigidbody.moveposition and rotation

  [SerializeField] float ProjectileSpeed = 1f;
  [SerializeField] float SpinSpeed = 1f;
    Rigidbody2D rb;
    Vector2 DeltaDirection;
  
    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
     
    }
    // Update is called once per frame

    private void FixedUpdate()
    {
        rb.MovePosition(rb.position + DeltaDirection); 

       rb.MoveRotation(rb.rotation+ SpinSpeed * Time.deltaTime);
        
       
    }

    void Update()
    {
        DeltaDirection = (Vector2.right*ProjectileSpeed*Time.deltaTime ); 

       DeltaDirection = transform.TransformDirection(DeltaDirection); //this is like the equal of self.local


    }

this gets the exact same problem as before, exact same behavior, what am i doing wrong here? i read that doing the child-parent thing with rigid bodies could be dangerous, what do you think (?)

The idea is that you want to move in a world direction. In your Update method, you are converting your global vector to local, that’s why you are getting the same behavior as before. Comment it out and see how it changes.

Another thing you could do is to initialize the direction and don’t change it afterward.

    [SerializeField] float projectileSpeed = 1f;
    [SerializeField] float spinSpeed = 1f;

    Rigidbody2D rb;
    Vector2 throwDirection;

    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        throwDirection = transform.right;
    }

    private void FixedUpdate()
    {
        rb.MovePosition(rb.position + throwDirection * projectileSpeed);
        rb.MoveRotation(rb.rotation + spinSpeed);
    }

Finally, yes, you don’t want to have a parent and a child with a rigidbody, that’s gonna cause a lot of weird movement, I suggest you try it out and see for yourself how crazy it gets.

Oh, almost forgot, when moving objects in FixedUpdate you don’t have to multiply by deltaTime, FixedUpdate is frame independent.

It just occurred to me that you can do something a little silly, but it works, you can transform an angle into a vector without using trigonometry.

[SerializeField] float angle = 0;

Vector2 throwDirection;

private void Start()
{
    throwDirection = Quaternion.Euler(0, 0, angle) * transform.right;
}

That will give you a vector that you could use to throw something in a 2D space in the angle you wrote in the exposed variable.

To be able to change it in real time you have to make a small modification:

    private void FixedUpdate()
    {
        throwDirection = Quaternion.Euler(0, 0, angle) * Vector2.right;
        rb.MovePosition(rb.position + throwDirection * projectileSpeed);
        rb.MoveRotation(rb.rotation + spinSpeed);
    }

Something like that works perfectly fine, you can change the angle in real-time and it will move in the desired angle.

yeah i convert it because i want it to be local, i’m trying to have like before a gun which shoots at the direction i gave by manually rotating it in the editor , so that’s the only part that has always worked hahaha it has to be active
If i am in World coordinates it works, also the Transform ones i used before worked in world, i’m trying to fix all to keep it working with local

for deltatime i read on the Docs that it is suggested to use Delta time also on fixed update, so for security reason i’ll keep it haha

Blockquote
For reading the delta time it is recommended to use Time.deltaTime instead because it automatically returns the right delta time if you are inside a FixedUpdate function or Update function.

and also i read that Unity automatically converts time.deltatime to Time.FixedDeltatime when it is used here so no problem, i also did some tests

Your solution also would work cause we are basically adjusting the angle by code, but i liked the “local” approach, and i need it also to understand other things. i need to solve this to make my mind clear haah

with the transform we solved the issue by making the parent-child relationship and by moving the transform.translate in local and the child with the renderer rotating in world

how can i get a behavior like this here? i am in the exact same situation but i can’t use the parent-child as we said before

i could try to to initialize the direction as you said but it could be useful to have it dinamically change

You’ll have to rotate the transform of the child directly, if you attach a rigidbody to the child it won’t work, I tried it out and the object wouldn’t move at all, it was increasing the position in the inspector but it stayed exactly where it was, really weird and fun to watch.

1 Like

Yep same, if there is a thing i understood today is that child at 60% of the time should only be used to render sprites or to have references with their position or rotation, better not attach many other component in there .-.
even in the glitch garden course Rick made us change all the hierarchy for this exact purpose

i think that maybe by using the rigid body for moving and transform the rotation of the child could work, but i read that using the two together (transform. and rigidbody.) could get into trouble, so i was trying to solve everything by remaining in their “families”

i think we are very close to the solution, because it is really close also to what i got before with the transform

Ok so i got it working by making it in the start as you said, do you think there is a way to also give it working in Update like we did with transform or i should just quit with the topic and with bothering you? ahahahah also because all of this is quite pointless because in a real situation i think all of us would just go with a rotate animation

 private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        DeltaDirection = (Vector2.right * ProjectileSpeed * Time.deltaTime);//la direzione e velocita
        DeltaDirection = transform.TransformDirection(DeltaDirection);   
    }
    // Update is called once per frame

    private void FixedUpdate()
    {
        rb.MovePosition(rb.position + DeltaDirection);
        rb.MoveRotation(rb.rotation+ SpinSpeed * Time.deltaTime);
        
       

Well, since you are multiplying by delta time it should work in Update too, there shouldn’t be much of a difference, but it is better to handle movement and things that have colliders in FixedUpdate.

What I do have to suggest is to name your variables with a lowercase letter, like deltaDirection instead of DeltaDirection, this might look trivial, but when having a bigger project with several clases and methods it will come to haunt.

1 Like

Privacy & Terms