As Coco runs through it her speed is slowed and you get this little rustling of leaves.
First up, let's look at the sprite for the grass.
The grass sprite is made up for two layers.
The important thing is that it's split into two pieces so that when other sprites are moving through the it they get Y sorted to make it look like they are in the grass.
I also have a particle emitter for shooting leaves.
This makes animating the actual grass a bit easier. The actual "Rustle" animation is just two frames but the particle emitter makes it appear more detailed.
The emitter is off by default but each grass instance keeps track of any bodies that are overlapping so that when they have a non-zero velocity it can enable the emitter.
The script for this is pretty simple.
I just have some signal handlers for tracking any bodies as they enter or exit.
func _on_BodyDetector_body_entered(body: KinematicBody2D) -> void: bodies.append(body) func _on_BodyDetector_body_exited(body: KinematicBody2D) -> void: bodies.remove(bodies.find(body))
Then in the process handler I loop over those bodies and check if they are moving.
func _physics_process(delta: float) -> void: var any_overlap := false for body in bodies: # Only emit if the overlapping body is moving if "velocity" in body and body.velocity.length() > 0: any_overlap = true if "status" in body: body.status.add_slow(0.05) particles.emitting = any_overlap if any_overlap: animation_player.play("Rustle") else: animation_player.play("Idle")
The grass also applies a negative speed buff to anything that can accept status changes.
And that's it.
If you prefer to see this kind of stuff in video form then you should subscribe to my game dev YouTube channel where I talk about all kinds of stuff like this.