0 votes

I'm having a hard time wrapping my brain around how to code shooting an arrow with an arc. There have been plenty of tutorials for how to do this in 2d, but I haven't found one that explains for 3d and I can't figure out how to translate between the two in this case.

I have the attacker and the target's translations. My current version uses moveandcollide

The attacker instances a kinematic arrow (don't know which physics body to use) and should pass it the initial angle. The arrow has an initial force(?) or velocity vector.

I can't figure out how to calculate the initial angle in 3d. Including the possibility of differing heights.
I also know that there should be 2 possible angles as well. I'd also like the arrow to point in the direction of travel, which again is a 3d angle I can't figure out.

This is my first 3d project using physics so I'm pretty much in the dark on this one and frustrated that this shouldn't be terribly difficult math. It's just that I've forgotten it all.

Any assistance would be greatly appreciated.

Godot version 3.3.2
in Engine by (35 points)

1 Answer

0 votes

Alright, so I figured it out. First, terminology is important. I should have been searching for Projectile motion. Secondly, having an understanding of transforms was what I lacked.

I'm going to post the code I cobbled together to make it work for anyone else who runs into the same problem.

extends KinematicBody

# force is the forward movement of the projectile
export var force = 20.0
export var g = Vector3.DOWN * 9.8
# t was just to keep track of time
var t = 0
# speed is just to make things move faster
export var speed = 1

var velocity = Vector3()

# init_xy is the initial upward angle while init_xz is the angle pointing toward the target.
var init_xy = 0
var init_xz = 0

# I initialized the angles beforehand in a different scene so all I had to do was
# add the arrow to the tree for it to shoot.
func _ready():
    rotate_x(init_xy)
    rotate_y(init_xz)
    velocity += -transform.basis.z * force

# Just to keep time and free the arrow after a bit.
func _process(delta):
    if t > 10:
        queue_free()
    t += delta

func _physics_process(delta):
    # Add gravity
    velocity += g * delta * speed
    # This makes the arrow point in the direction of travel, like in real life.
    look_at(transform.origin + velocity.normalized(), Vector3.UP)
    # pretty much does the work for you. Although this might be different if you aren't
    # using a KinematicBody.
    move_and_collide(velocity*delta*speed)

You can find the math for the initial angles pretty easily. I hope this saves someone a lot of head ache.

by (35 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.