Hi guys. I've been working on something for a while and I'd appreciate some help if anyone is interested.

Example:
https://ibb.co/N1vHZ5P
Other Example:
https://ibb.co/QQJgV04

What I want to do is have a character 'jump' from a point, to another point, while moving through a point in between. I want this to be visualized as a parabola. I also want it to appear like a 'natural' jump.

I've done everything but making the jump look natural. What I'm doing so far is calculating two parabolas through code, one on the left side of the central point and one on the right, then adding both of their points to a Curve2D. I add the Curve2D as the curve property of a Path2D, slap a PathFollow2D on there and iterate over it using its unit_offset property. This causes the character to move along the parabola at a constant rate. So far so good.

But here's where I'm stuck. I want to move across this curve as if I'm jumping, meaning I want the character to slow down at the top of the curve and speed up again as he comes back down. I can't figure out a way to do this. Currently I'm just tweening from 0 to 1 and setting the PathFollow2D's `unit_offset` property to that. The problem is that if I interpolate using say, `TRANS_QUAD` and `EASE_IN_OUT`, the slowing takes place exactly at the x center of the curve. Which is a big problem for curves like the second one above, because the exact center is not the highest point.

What I've tried:

• Literally split the arc in two (treating it as 2 curves rather than combining each half-parabola into one). This allows me to calculate the proper speed and do `EASE_OUT` on one side and `EASE_IN` on the other. This doesn't work though because when I interpolate the character through them there's a 'catch' at the central point, and there seems to be no way to get rid of that (removing the central point from one of the curves so it isn't 'duplicated' does the opposite of help)

I also haven't included any code because there's a decent amount. If you think it would help you to see it outside the conceptual realm, just let me know. I have separate scripts for the standard arc and the split arc I tried so let me know which you'd like to see.

Please feel free to give me any questions along the lines of "Why are you doing it that way, my guy?" This is just me working and I tend to overcomplicate things. As far as I can tell this is the only way to accomplish this.

Thank you again.

Godot version 3.3
in Engine
edited

+1 vote

Hi,
check out this excellent tutorial:
https://www.forrestthewoods.com/blog/solving_ballistic_trajectories/

and look at his code on github:
https://github.com/forrestthewoods/lib_fts/blob/master/code/fts_ballistic_trajectory.cs

maybe one of his methods fits your needs

by (3,932 points)

I appreciate the resource!

i've found an implementation of it in one of my projects.
Haven't cleaned it from additional code but i think it gets the point

``````extends Spatial
var max_height:float = 6.0

var lateral_speed:float = 6.0
var divergence:Vector3 = Vector3(2,0,2)
var fire_velocity:Vector3 = Vector3()
var gravity:float = 0
var target:Vector3

var damage_group:String = ""
var damage:float = 5

set_physics_process( false )

func _physics_process(delta):
translate(fire_velocity * delta)
fire_velocity.y -= gravity * delta
if translation.y < target.y:
print("greande reached destination")
Main.__explosion.instance().detonate(global_transform.origin)
damage()
queue_free()

func target(group):
damage_group = group
return self

func damage():
var units = get_tree().get_nodes_in_group(damage_group)
for unit in units:
print("damage")
unit.injure(damage)

func throw( origin:Vector3, nTarget:Vector3 ):
target = nTarget + Vector3(rand_range(-divergence.x,divergence.x),rand_range(-divergence.y,divergence.y),rand_range(-divergence.z,divergence.z))
if not solve_ballistic_arc_lateral( origin, target):
queue_free()
return

translation = origin
set_physics_process( true )

func solve_ballistic_arc_lateral( proj_pos:Vector3, target_pos:Vector3):

# Handling these cases is up to your project's coding standards
if proj_pos != target_pos and lateral_speed > 0 and max_height > proj_pos.y:
print_debug( "fts.solve_ballistic_arc called with invalid data");

var diff:Vector3 = target_pos - proj_pos
var diffXZ:Vector3 = Vector3(diff.x, 0, diff.z)
var lateralDist:float = diffXZ.length()

if (lateralDist == 0):
return false

var time:float = lateralDist / lateral_speed

fire_velocity = diffXZ.normalized() * lateral_speed

# System of equations. Hit max_height at t=.5*time. Hit target at t=time.
#
# peak = y0 + vertical_speed*halfTime + .5*gravity*halfTime^2
# end = y0 + vertical_speed*time + .5*gravity*time^s
# Wolfram Alpha: solve b = a + .5*v*t + .5*g*(.5*t)^2, c = a + vt + .5*g*t^2 for g, v
var a:float = proj_pos.y;       # initial
var b:float = max_height;       # peak
var c:float = target_pos.y;     # final

gravity = -4*(a - 2*b + c) / (time* time)
fire_velocity.y = -(3*a - 4*b + c) / time

return true
``````

Thank you! I'll look this over.