Godot Version
godot-4
Question
Hey friendly people! I want to spawn a weapon in my player position and then throw it in the air with a rotation and then I want it to land exactly in the middle of the weapon rack. I’ve tried tween approach, but this look very unnatural. So I guess there is an approach with RigidBody2d, but from my level it seems impossible to calculate correct initial impulse power and direction. So is there a way to do that? 
There are probably more elegant ways. But what about path2d? Then you add the weapon as Child and then the progress. Didnt use it for a while.. but could be an option, if it should take the same direction
1 Like
@hydraware 's method would work, or you could do a 2D ballistics solver (which sounds intimidating, but really isn’t that complicated). Personally, I’d probably fudge it with interpolation:
const FINAL_ANGLE: float = PI # 180 degrees
const ANGLE_TRAVEL: float = TAU * 2 # 720 degreees
const TRAVEL_TIME: float = 2.25 # seconds
const THROW_HEIGHT: float = 50.0 # pixels
var time: float
var src_pos: Vector2
var tgt_pos: Vector2
func fling_start(src: Vector2, tgt: Vector2) -> void:
time = 0.0
src_pos = src
tgt_pos = tgt
func fling_update(delta: float) -> bool:
bool done = false
time += delta
if time >= TRAVEL_TIME:
time = TRAVEL_TIME
done = true
var t: float = time / TRAVEL_TIME # Gives us between 0.0 and 1.0
var x: float = lerp(src_pos.x, tgt_pos.x, t) # Get the horizontal position.
var y: float = lerp(src_pos.y, tgt_pos.y, t) # Account for height difference.
# Add a height curve. t is (0..1), we subtract half and multiply by PI to
# make the range (-PI/2 .. PI/2), which gives us the "hill" part of cosine.
y += cos((t - 0.5) * PI) * THROW_HEIGHT
# Set the position to our interpolated value, and interpolate a value for
# rotation. Note that we're lerping backwards for the rotation so that we
# wind up at FINAL_ANGLE.
position = Vector2(x, y)
rotation = FINAL_ANGLE + lerp(ANGLE_TRAVEL, 0.0, t)
return done
2 Likes
You should stick with Tweens, they have tons of properties to tweak; can you post what you made with them so far?
At first blush it seems a bit complicated to use Tween to do a parabolic arc. The basic positions could be fed to Tween for lerping, as could the angle, but how does one get the “ballistic” altitude component with Tween?
Yeah, for tween it didn’t work smoothly enough, because the movement of the weapon was just with a consistent speed, but when we throw into the air items their speed changes.
So I explored a bit more and came in with this RigidBody2d and applying central force + torque. And on collision with bottom of that weapon rack I just freeze the object and reset it’s position.
Funny enough looks pretty smooth 
Here I made a short video how the code worked in the end: https://www.youtube.com/watch?v=Ho2eErJ2J2Y&ab_channel=IndieInk
func spawn_weapon() -> void:
_current_weapon = CREATED_WEAPON.instantiate()
add_child(_current_weapon)
_current_weapon.global_position = get_tree().get_first_node_in_group(Player.GROUP_NAME).global_position
animation_created_weapon(_current_weapon)
func animation_created_weapon(weapon: RigidBody2D) -> void:
weapon.add_constant_torque(50)
var middle: Vector2 = weapon_landing_marker.global_position - weapon.global_position
middle.y -= LAUNCH_IN_THE_AIR_FORCE
weapon.apply_central_force(middle/ 2)
func _on_weapon_landing_body_entered(body: Node2D) -> void:
if body is CreatedWeapon:
body.sleeping = true
body.global_position = weapon_landing_marker.global_position
body.rotation = 0
1 Like
If you are using lerp
over time then it’s usually easy to convert to a tween, here’s approximately what you wrote as a Tween
const travel_time: float = 2.0
const arc_height: float = -200.0
var tween_x = sword.create_tween().set_parallel()
tween_x.tween_property(sword, "position:x", target_pos.x, travel_time)
tween_x.tween_property(sword, "rotation", TAU*2, travel_time).from(0)
var tween_arc := sword.create_tween().set_trans(Tween.TRANS_SINE)
tween_arc.tween_property(sword, "position:y", target_pos.y + arc_height, travel_time/2.0).set_ease(Tween.EASE_OUT)
tween_arc.tween_property(sword, "position:y", target_pos.y, travel_time/2.0).set_ease(Tween.EASE_IN)
Here’s a little video of it too!
5 Likes
Ah, ok, that makes sense.
Whoa! That looks dope!
And thank you all for your replies! I actually also played with tweens and lerps, so it was very helpful in my learning! <3
1 Like