Movement with gradually increasing and decreasing velocitiy

Godot Version4.6

Question

I searched this question and got “no results found” return, so I guess I should ask:

What’s the best way to make gradually increasing and/or decreasing velocity movement?

A specific example:

Human running speed. A football player might run a 40 yard dash, but he doesn’t start at top speed. He starts at zero, and his speed spikes in the first 10-20 yards.

Then the speed increases at much lower rate over the next 10 yards until around the 30 yard point which is usually around the area where the increase ends because he’s hit his top speed.

Now, over 60 or 70 yards, his speed might start to wane, depending on fatigue, weather, soreness from injury, etc.

Most games have players running top speed immediately and staying static at that speed. Is is possible to code a more human type of running, and where would I even begin?

func _ready() -> void:
    print("hello world")

You use move_toward()

For example speed = move_toward(speed, max_speed, delta), or speed = move_toward(speed, minimum_speed, delta) if you want to decrease.

First argument is starting point. Because you call it every frame you can just use the current speed. You move it towards the second argument by the increment delta each frame. You can use any float as third argument, you don’t need to use the actual delta.

Thank you for that answer.

So move_toward isn’t necessarily only a movement function, but command for a value increase?

Yes it will move a value towards another value, that value could represent anything, and it doesn’t have to increase.

The CharacterBody basic movement template uses move_toward (incorrectly) when no direction in held. It would be better if the third parameter was multiplied by delta.

Yes you take something and moves it towards something else by a small and even value each frame. You could also mess around with the delta-value if you want initial change to be faster or slower than later but i think mostly people just use delta.

Given this snippet the equation is accelerating in pixels per second for 2D and meters per second for 3D

velocity = velocity.move_toward(direction * SPEED, delta * ACCELERATION)

If we took out the * ACCELERATION it would be the same as accelerating by 1 m/s in 3D or 1 px/s in 2D. For 3D this is okay, maybe not snappy but it’ll get you around, for 2D this is abysmal for anything but the tiniest pixel art games, a 2D 1080p game would benefit from an ACCELERATION in the thousands.

What if my scale is 16 px/ yard and my over all game speed is 600 pixels per second, with math applied to character speed to bring it to 8.7 - 9.7 yards per second? Is that possible?

If your SPEED is 600 I would use an ACCELERATION of at least 2,400. ≈4x the SPEED value makes for a fairly snappy acceleration, I usually go up to 8x if I don’t intend to feel weighty, like if movement isn’t a core game mechanic.

Ok, in that case I might want to go 8k. Movement in football is a pretty core mechanic. lol

I want it to feel like movement isn’t as simple as “stop/start” but I also want to properly represent the explosive athleticism that the players possess. I also don’t want to resort to “sprint” buttons and that type of thing because it’s not accurate to human speed and movement. I cannot accurately represent everything about football. Even multi billion companies can’t do that. But I would like to have at least an approximation of some football movement.

You could use get_strength() on the joystick input, where 1 is max, 0.5 is halfway tilt etc. Then use that as a modifier. Then you could multiply with modifier where you calculate speed now. Walking if slight tilt, jogging if a bit more, running if full or nearly full. You would still need to use move_toward for sudden tilts from one end to the other

I was just messing around with ball creation, and I used a PhysicsBody2D to create it. Interestingly, there are mass and inertia settings in there. When I messed with them, I found that the ball had some “drag” behind the mouse cursor.

Could I child a PhysicsBody2D to a player object and create the feeling of inertia/velocity that way? @gertkeno curious about what you think about this, too. I like both of your suggestions.

Thank you for your help, since I haven’t thanked you guys yet.

RigidBodies introduce a whole new level of physics interactions, we wouldn’t be talking in px/s but in forces. To make best use of RigidBodies you must submit to the physics engine, there will be some jank especially with fast moving and small objects. To say “I want this to move at 600 px/s” you must ask how much force per second is require to move accelerate it’s mass, then lower the force to match the object’s friction and drag; much more complicated.

It’s totally different, CharacterBodies are a great bridge to make use of physics while not being totally bound to the engine’s whims.

Ok, thank you. Maybe better to go the CharacterBody route, then.

What I usually do is give my objects a maximum speed and an acceleration. Just add the acceleration to the speed as long as they are accelerating until they reach max speed. This way you also have an easy way to control the acceleration. Same thing with slowing down, give the object a deceleration if it has breaks or something or just let friction slow it down naturally.

That seems simple enough, but being a complete beginner, I’m not sure how to implement a lot of this. I’ll have to watch some more videos and tutorials.

It’s rough because I know what I want to do, I just cant put it into code yet.

Thank you again for your help! I watched a video on YouTube that let me code 8 directional movement with surprising ease, and using your acceleration code advice, I came up with some decent-feeling movement.

Here’s what I ended up with:

```extends CharacterBody2D

@export var speed = 750
@export var acceleration = 1350
func get_input():
		var input_direction = Input.get_vector("left", "right", "up", "down")
		velocity = velocity.move_toward(input_direction * speed, Engine.time_scale/Engine.physics_ticks_per_second * acceleration)
		
func _physics_process(delta: float) -> void:
	get_input()
	move_and_slide()```

The velocity math in there happened because it was telling me delta wasn’t defined in scope, but when I looked up what delta was, that’s the equation that was in the definition so I tried that in place of delta and it worked!

You should pass delta to the function that requires it, or move your function into _physics_process

# pass in delta
func get_input(delta_time: float) -> void:
	var input_direction = Input.get_vector("left", "right", "up", "down")
	velocity = velocity.move_toward(input_direction * speed, delta_time * acceleration)
		
func _physics_process(delta: float) -> void:
	get_input(delta) # given here
	move_and_slide()

###### OR ######

# remove func get_input
func _physics_process(delta: float) -> void:
	var input_direction = Input.get_vector("left", "right", "up", "down")
	velocity = velocity.move_toward(input_direction * speed, delta * acceleration)
	move_and_slide()

Even though it’s been solved I’ll add another option. Some of the courses I’ve seen have handled acceleration and deceleration by applying a sine wave to the movement.

That’s an interesting option, especially if the curve could be modified like an ADSR envelope on a synth. Sharpen the attack based on a “quickness” value, flatten or sharpen the decay based on “agility” and extend sustain based on a “stamina” value and extend release based on “velocity.”

I’d have no idea how to code that, though.

How did you apply a sine wave? I don’t see where that would fit in without a lerp which normally produces frame-dependent movement I’d advise against.