Cannon barrel recoil?

godotbotgodotbot Posts: 6Member

Hello, I have programmed a turret cannon node that will rotate and has rotation limits. I am trying to add a recoil function so it will the barrel will recoil along its axis and then return. It is simply two nodes the barrel and the base that are siblings in a cannon container node(area2d's with a sprite).
I have a function that will recoil and return the barrel but when the barrel is rotated it just moves the barrel up and down.

func recoil(delta_time):
if is_recoiling == false:
$cannon_barrel.translate(Vector2(0,RECOIL_SPEED * delta_time))
if $cannon_barrel.get_position().y > MAX_RECOIL:
is_recoiling = true
elif is_recoiling == true:
$cannon_barrel.translate(Vector2(0,-RECOIL_SPEED * delta_time))
if $cannon_barrel.get_position().y < RETURN_POSITION:
is_recoiling = false

I call this in the process function. I can see the problem is just moving the y coordinate relative to the parent down and up. What function will move the y back along its own axis?


Tags :


  • godotbotgodotbot Posts: 6Member

    also I tried adding gdscript tags with but it didn't work

  • TwistedTwiglegTwistedTwigleg Posts: 982Admin

    You need to use Vector2(cos(rotation), sin(rotation)) to convert your rotation into a position around a unit circle, and then use that position to move your cannon.

    The code would look something like this:

    var unit_circle_pos = Vector2(cos($cannon_barrel.rotation), sin($cannon_barrel.rotation))
    $cannon_barrel.translate(unit_circle_pos * RECOIL_SPEED * delta_time)

    Keep in mind you are going to need to use something other than checking the y position to move the cannon back and forth. I would suggest using a timer (whether it be the node or just a variable) to track when to move the cannon to and from the desired positions.

    Regardless, using you need to use sin and cos to convert the rotation into a vector, and then use that vector to move the cannon. You may need to swap cos and sin to get the proper results, as I can never remember which goes where and so they’ll likely need to be swapped.

    (Ironically I’ve bee working so much with 3D rotation and relative vectors, that I’ve had to rewrite this like four times because I keep writing it like it’s for 3D :lol: )

  • godotbotgodotbot Posts: 6Member

    I must admit this got deep fast. The x and y coordinates of the cannon barrel are presumably in the center of the area2d which is a box. We get the rotation and then find the unit vector on the unit circle and move it back(theoretically). I have tried using the code with both the cosine and sine swapped and it never moves it back along the axis. I don't exactly understand what translate does, it seemed to make sense when I was using it.

  • godotbotgodotbot Posts: 6Member

    thanks for the help.

  • TwistedTwiglegTwistedTwigleg Posts: 982Admin
    Answer ✓

    Your welcome! I'll try to answer the new questions:
    (Let me know if something doesn't make sense, and I'll try to explain in more detail and/or better :smiley: )

    To move backwards you just need to multiply the above vector by negative one, then it should move backwards. So to move backwards using the above code, you need something like this: $cannon_barrel.translate(unit_circle_pos * RECOIL_SPEED * delta_time * -1)

    (That's assuming I remember correctly. It's been awhile since I've worked in 2D.)

    Translate moves a node by the inputted amount (relative to the node's position). If you are at position X:4 Y:4 and call translate(Vector2(-1, 2)) then you'll get a position of X:3 Y:6. Translate is primiarlly used to move nodes around without having to do a more messy bit of code to get the same result (otherwise you'd have to do node.position = node.position + translate_vector instead of node.translate(translate_vector)).

    Maybe this page from the docs will help? It's a little long and can be overwhelming, but it explains how the coordinate system works in Godot (you can skip the 3D stuff if you want)

    Also, I was just looking at this topic on the forums where I helped someone with a similar problem. There he is using velocity and then adding the velocity to his position instead of using translate. You may want to try using $cannon_barrel.position += (unit_circle_pos * RECOIL_SPEED * delta_time) or $cannon_barrel.global_translate(unit_circle_pos * RECOIL_SPEED * delta_time * -1) instead and see if one of those work better, because then it will be moving in global space as opposed to local space.

  • MegalomaniakMegalomaniak Posts: 1,048Admin

    Don't forget to select TwistedTwigleg's reply as an answer. ;)

  • godotbotgodotbot Posts: 6Member
    Answer ✓

    Hello, TwistedTwigleg, I am sure there is more to do but it is a lot closer. I used input keys (instead of a recoil function)
    to test it and what I had to do is rotate the "unit_circle_vector" by 90 degrees (A trick I learned from a youtube tutorial) and now
    when I press the up key and down key it will indeed slide up and down it axis.

    if Input.is_action_pressed("ui_up"):
        var unit_circle_position = Vector2(cos($cannon_barrel.get_rotation()),sin($cannon_barrel.get_rotation()))
        var new_vector = unit_circle_position * -RECOIL_SPEED * delta
    elif Input.is_action_pressed("ui_down"):
        var unit_circle_position = Vector2(cos($cannon_barrel.get_rotation()),sin($cannon_barrel.get_rotation()))
        var new_vector = unit_circle_position * RECOIL_SPEED * delta

    The only problem I have now is I can fly it off its base even though it is doing it from the local coordinates of the parent node.

  • TwistedTwiglegTwistedTwigleg Posts: 982Admin
    Answer ✓

    I'm glad you got it at least somewhat working! (I totally forgot about rotating the unit circle by 90 degrees so that it starts with a position pointing upwards :sweat_smile: )

    The reason it's moving beyond the base is because you do not have an if check (at least in the code above). There are many ways to go about this, and honestly I'm not sure what the 'best' solution is. Here's what I would do if I needed to solve this problem:
    (NOTE: The reason there is "-|" before every line is that I'm trying to format the post a little so it's easier to read)

    -| I would store the initial position of the Cannon in a variable called something like initial_pos. That way you can find out
    -| how far the cannon barrel is from it's starting position. We'll use this position as the farthest position we can pull the cannon
    -| back to. You'll need to declare the variable outside of _ready, and put something like
    -| initial_pos = $cannon_barrel.position in your _ready function
    -| Next I would then make a constant for how far you want to be able to move the cannon barrel away from that initial
    -| position. Something like const MAX_FORWARD_DISTANCE = 2 for example
    -| Then before you move the barrel, you just need to do a check like this:

    if Input.is_action_pressed("ui_up"):
      if $cannon_barrel.position.distance_squared_to(intial_position) < MAX_FORWARD_DISTANCE:
        # Move the cannon barrel forwards here!
    if Input.is_action_pressed("ui_down"):
      # You can tweak the 0.5 value to get a value that does not jitter around when it's close to the starting point
      if $cannon_barrel.position.distance_squared_to(intial_position) > 0.5: 
        # Move the cannon barrel backwards here!

    This should (in theory) stop the cannon barrel from moving farther than MAX_FORWARD_DISTANCE distance away from the starting position. I have not tested the code though, so it may not work. Let me know if it doesn't and I'll make an example project so I can test my solutions before posting them.

  • godotbotgodotbot Posts: 6Member

    Hello, yes that worked with the distance_to() function. distance_squared_to() seemed to give a small distance.
    Phew :dizzy: more programming than I expected. I think the ultimate solution is to move the children nodes(sprite and collision shape) of the barrel area2d
    so they will be comparing to a stable point on the whole structure and moving in a straight line.

  • TwistedTwiglegTwistedTwigleg Posts: 982Admin

    @godotbot said:
    Hello, yes that worked with the distance_to() function. distance_squared_to() seemed to give a small distance.

    Whoops! Sorry about that. I couldn't remember which of the two would give the desired result. Looking on it now it makes sense that distance_to is the correct choice :sweat_smile:

    Phew :dizzy: more programming than I expected. I think the ultimate solution is to move the children nodes(sprite and collision shape) of the barrel area2d
    so they will be comparing to a stable point on the whole structure and moving in a straight line.

    Even the most simple things generally have a fair amount of code behind them. Thankfully it gets programming gets easier the more you do it (at least for the simpler stuff).

    Moving the children nodes should work. I'm glad you have found a solution :smile:

Sign In or Register to comment.