Trampoline

This shader is very straightforward : It deforms the background using a bezier curve. It can be used alone, but with at least this script to set the uniforms screen_pos and screen_size (UV computed from the viewport). Apply this shader on a node such as ColorRect.

extends ColorRect

func _ready():
	var viewport_size : Vector2 = get_viewport_rect().size
	material.set_shader_param("screen_size", rect_size / viewport_size)
	material.set_shader_param("screen_pos", rect_position / viewport_size)

Now, if you want to add a spring effect (so that the effect look like something is landing on the screen like on a trampoline, add a Tween node as a child (name it … well … Tween), and use the following script for your main ColorRect node:

class_name TrampolineEffect
extends ColorRect

signal finished()

export(float, -0.5, 1.0, 0.001) var height : float = 0.4
export(float) var stiffness = 5.0
export(float) var dampening = 3.0
export(float) var amplitude = 1.0
export(float) var start_delay = 1.4

const ACTIVITY_MARGIN : float = 0.01

onready var tween : Tween = $Tween
onready var velocity : float = 0
onready var release : bool = false

var current_height : float

func _ready():
	set_process(false)
	reset_uv()
	material.set_shader_param("force", 0)
	tween.connect("tween_all_completed", self, "_on_start_completed")

func reset_uv() -> void:
	var viewport_size : Vector2 = get_viewport_rect().size
	material.set_shader_param("screen_size", rect_size / viewport_size)
	material.set_shader_param("screen_pos", rect_position / viewport_size)

func activate() -> void:
	current_height = height
	reset_uv()
	set_process(false)
	release = false
	tween.remove_all()
	tween.interpolate_property(
		self,
		"material:shader_param/force",
		0,
		height,
		start_delay,
		Tween.TRANS_QUART,
		Tween.EASE_IN)
	tween.seek(0.0)
	tween.start()

func _on_start_completed() -> void:
	release = true
	set_process(true)

func _process(delta):
	if release:
		velocity -= ((current_height * stiffness) + (dampening * velocity)) * delta
		current_height = clamp(velocity + current_height, -amplitude, amplitude)
		material.set_shader_param("force", current_height)
		if abs(current_height) < ACTIVITY_MARGIN and abs(velocity) < ACTIVITY_MARGIN:
			current_height = 0
			velocity = 0
			material.set_shader_param("force", 0)
			emit_signal("finished")
			release = false

The exported variables are:

  • height : The height/force to apply. Range between -0.5 (push) and 1.0 (pull).
  • stiffness and dampening : Typical spring-mass system constants.
  • amplitude : Height clamping value. Should remain to 1.0
  • start_delay : Before doing the trampoline effect, the script will bring the deformation from 0 to the height value in start_delay seconds.

To activate the effect, just call the activate function. The effect can be reused, so the activate function can be re-called.

The signal finished is emitted when the spring-mass system reached a stable state (height is 0 and no movement).

Shader code
shader_type canvas_item;

uniform float force : hint_range(-0.5, 1.0, 0.001) = 0.4;
uniform vec2 screen_pos;
uniform vec2 screen_size;

void fragment() {
	vec2 v = vec2(.5) - UV;
	float d = min(1., length(v) * 2.);
	vec2 target_id = screen_pos + ((UV + ((2.*v/d)
		* clamp(
			force * (d + 2.*sqrt(1. - d) - 1.),
			(d - 1.) / 2., 
			d / 2.) )) * screen_size);
	target_id.y = 1. - target_id.y;
	vec4 color = texture(SCREEN_TEXTURE, target_id);
	COLOR = color;
}
Tags
2d, deformation, Spring-Mass, Trampoline
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from CasualGarageCoder

(Almost) Invisible Character

2D Fountain

Swirl/Sink

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments