Animation by code

A position track and a color track written key by key at startup, with no .anim file. The timeline below shows the same keys the code inserted.

The editor above is running this project. Change a line and it reloads.

Godot classes used

AnimationPlayerAnimationAnimationLibrary

The code

scripts/main.gd
extends Node

const LENGTH: float = 2.4
const RADIUS: float = 36.0
const TRACK_LEFT: float = 150.0
const TRACK_WIDTH: float = 980.0
const TRACK_Y: float = 620.0

const KEYS: Array = [
	{time = 0.0, position = Vector2(430, 210), color = '#8da5f3'},
	{time = 0.6, position = Vector2(960, 250), color = '#8eef97'},
	{time = 1.2, position = Vector2(1010, 470), color = '#f3d48d'},
	{time = 1.8, position = Vector2(490, 440), color = '#fc7f7f'},
	{time = 2.4, position = Vector2(430, 210), color = '#8da5f3'},
]

var player: AnimationPlayer
var playhead: ColorRect


func _ready() -> void:
	_add_background()
	_add_label('Animation and AnimationLibrary built at runtime, no .anim file', Vector2(40, 40))

	for key in KEYS:
		var mark: Polygon2D = _make_circle(10.0, Color(key.color))
		mark.position = key.position
		add_child(mark)

	var blob: Polygon2D = _make_circle(RADIUS, Color(KEYS[0].color))
	blob.name = 'Blob'
	blob.position = KEYS[0].position
	add_child(blob)

	var animation: Animation = Animation.new()
	animation.length = LENGTH
	animation.loop_mode = Animation.LOOP_LINEAR

	var position_track: int = animation.add_track(Animation.TYPE_VALUE)
	animation.track_set_path(position_track, 'Blob:position')
	animation.track_set_interpolation_type(position_track, Animation.INTERPOLATION_CUBIC)

	var color_track: int = animation.add_track(Animation.TYPE_VALUE)
	animation.track_set_path(color_track, 'Blob:color')

	for key in KEYS:
		animation.track_insert_key(position_track, key.time, key.position)
		animation.track_insert_key(color_track, key.time, Color(key.color))

	var library: AnimationLibrary = AnimationLibrary.new()
	library.add_animation('orbit', animation)

	player = AnimationPlayer.new()
	add_child(player)
	player.add_animation_library('', library)
	player.play('orbit')

	_add_timeline()

	print('the dots are the keyframe positions, the ticks are their times')


func _process(_delta: float) -> void:
	var progress: float = player.current_animation_position / LENGTH
	playhead.position.x = TRACK_LEFT + TRACK_WIDTH * progress


func _add_timeline() -> void:
	var rail: ColorRect = ColorRect.new()
	rail.color = Color('#2a2f3d')
	rail.position = Vector2(TRACK_LEFT, TRACK_Y)
	rail.size = Vector2(TRACK_WIDTH, 10)
	add_child(rail)

	for key in KEYS:
		var tick: ColorRect = ColorRect.new()
		tick.color = Color(key.color)
		tick.size = Vector2(6, 34)
		tick.position = Vector2(TRACK_LEFT + TRACK_WIDTH * key.time / LENGTH - 3.0, TRACK_Y - 12)
		add_child(tick)

	playhead = ColorRect.new()
	playhead.color = Color('#ffffff')
	playhead.size = Vector2(3, 56)
	playhead.position = Vector2(TRACK_LEFT, TRACK_Y - 23)
	add_child(playhead)


func _make_circle(radius: float, color: Color) -> Polygon2D:
	var points: PackedVector2Array = PackedVector2Array()

	for i in 32:
		var angle: float = TAU * i / 32
		points.append(Vector2(cos(angle), sin(angle)) * radius)

	var circle: Polygon2D = Polygon2D.new()
	circle.polygon = points
	circle.color = color

	return circle


func _add_background() -> void:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)


func _add_label(text: String, at: Vector2) -> void:
	var label: Label = Label.new()
	label.text = text
	label.position = at
	label.add_theme_color_override('font_color', Color('#999999'))
	add_child(label)

More Animation examples