summaryrefslogtreecommitdiff
path: root/sprite.gd
blob: 3bfc961d6c47e8056cc8c813d184a429d86fc56c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class_name Sprite
extends Node2D


var sprite_data: SpriteResource
var action_data: ActionFormat

var current_action_idx := 0
var current_frame := 0
var current_start_time := 0.0
var accumulator := 0.0

var cache: Dictionary


func _ready() -> void:
	if not sprite_data or not action_data:
		set_process(false)


func load_file(path: String):
	var basename = path.get_basename()
	
	sprite_data = load("%s.tres" % basename)
	
	var act = FileAccess.open("%s.act" % basename, FileAccess.READ)
	action_data = ActionFormat.from_bytes(ByteStream.from_bytes(
		act.get_buffer(act.get_length())
	))
	
	if not sprite_data.files_exist():
		sprite_data.save_to_file() # generate at "runtime"
	
	set_process(true)
	set_current_action(0)


func set_current_action(idx: int):
	current_action_idx = idx
	current_frame = 0
	current_start_time = 0
	accumulator = 0
	
	update(action_data.actions[current_action_idx].motions[current_frame].sprite_layers)


func _process(delta: float) -> void:
	var action = action_data.actions[current_action_idx]
	var frame_time = ((action_data.frame_times[current_action_idx] * 24) / 1000)
	
	accumulator += delta
	if accumulator > current_start_time + frame_time:
		var motion: ActionFormat.Motion = action.motions[current_frame]
		update(motion.sprite_layers)
		
		current_start_time = accumulator
		current_frame += 1
		if current_frame >= action.motions.size():
			set_current_action(current_action_idx) # reset current action


func update(sprite_layers: Array[ActionFormat.SpriteLayer]):
	if not is_processing():
		return
	
	var has_different_layer_count = %SpriteLayers.get_child_count() != sprite_layers.size()
	
	if has_different_layer_count:
		for node in %SpriteLayers.get_children():
			node.queue_free()
	
	for idx in sprite_layers.size():
		var sprite_layer = sprite_layers[idx]
		
		var base_dir = sprite_data.filepath.substr(0, sprite_data.filepath.length() - 4) # cut off .spr
		var image = load("%s/%s.png" % [base_dir, str(sprite_layer.sprite_index).pad_zeros(3)])
		
		var sprite: Sprite2D
		if has_different_layer_count:
			sprite = Sprite2D.new()
			sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
		else:
			sprite = %SpriteLayers.get_child(idx)
		
		sprite.texture = image
		sprite.position = sprite_layer.get_position()
		sprite.self_modulate = sprite_layer.get_color()
		sprite.scale = sprite_layer.get_scale()
		sprite.rotation_degrees = sprite_layer.rotation_degrees
		sprite.flip_h = sprite_layer.flip_h
		
		# TODO: use sprite and action together to generate AnimatedSprite2D with SpriteFrame Resources?
		# TODO: no. needs AnimationPlayer with config for different sprite positions in the animation
		
		if has_different_layer_count:
			%SpriteLayers.add_child(sprite)