xiandie/addons/property-inspector/pro_animation_sprite2d/pro_animated_sprite.gd

167 lines
4.5 KiB
GDScript

@tool
class_name ProAnimatedSprite2D extends AnimatedSprite2D
@export var autostart := true
@export var action_configs: Array[Dictionary] = []
@export var move_configs: Array[Dictionary] = []
# 0.0 means no light
# negative value means subtract, positive value means add
@export_range(-1.0, 1.0) var light_energy := 0.0:
set(val):
light2d.energy = abs(val)
if val > 0:
light2d.blend_mode = Light2D.BLEND_MODE_ADD
else:
light2d.blend_mode = Light2D.BLEND_MODE_SUB
light_energy = val * modulate.a
const ACTION_CONFIG = {
"animation_intro": "", "intro_loop": 1, "animation_wait_time": 0.0, "animation_next": ""
}
const MOVE_CONFIG = {"animation": "", "velocity": Vector2.ZERO, "duration": 10000000.0}
static func new_move_config() -> Dictionary:
return MOVE_CONFIG.duplicate()
static func new_action_config() -> Dictionary:
return ACTION_CONFIG.duplicate()
# 从 intro 到 next 的配置信息
var auto_checkout_dict = {
# intro -> {state_config instance}
}
# 播放 animation 的同时,进行移动
var animation_velocity = {
# animation -> velocity
}
var light2d := PointLight2D.new()
func _ready() -> void:
if light_energy != 0.0:
add_child(light2d)
frame_changed.connect(_on_frame_changed)
if Engine.is_editor_hint():
return
_load_config()
if autostart and animation:
# 制造一点错差
frame = randi() % sprite_frames.get_frame_count(animation)
play()
animation_finished.connect(_on_animation_finished)
animation_looped.connect(_on_animation_finished)
animation_changed.connect(_on_animation_start)
animation_looped.connect(_on_animation_start)
func _load_config():
# load auto_checkout_dict
for i in range(action_configs.size()):
action_configs[i].merge(ACTION_CONFIG)
var state_config = action_configs[i]
# 不必关闭循环
# if sprite_frames and sprite_frames.has_animation(state_config.animation_intro):
# intro 的 animation 关闭循环
# sprite_frames.set_animation_loop(state_config.animation_intro, false)
auto_checkout_dict[state_config.animation_intro] = action_configs[i]
# load animation_frame_offsets
for i in range(move_configs.size()):
move_configs[i].merge(MOVE_CONFIG)
var move_config = move_configs[i]
if sprite_frames and sprite_frames.has_animation(move_config.animation):
animation_velocity[move_config.animation] = move_config.velocity
func _on_frame_changed():
if light_energy == 0.0:
return
var texture = sprite_frames.get_frame_texture(animation, frame)
if not texture:
return
light2d.texture = texture
light_energy = light_energy * modulate.a
func _reset_loop(intro: String):
for c in action_configs:
if c.animation_intro == intro:
auto_checkout_dict[intro].intro_loop = max(1, c.intro_loop)
func _on_animation_finished() -> void:
var intro = animation
if auto_checkout_dict.has(intro):
auto_checkout_dict[intro].intro_loop -= 1
if auto_checkout_dict[intro].intro_loop <= 0:
# reset loop
_reset_loop(intro)
var wait_time = auto_checkout_dict[intro].animation_wait_time
var next = auto_checkout_dict[intro].animation_next
if wait_time > 0:
pause()
get_tree().create_timer(wait_time).timeout.connect(play.bind(next))
else:
play(next)
var velocity := Vector2.ZERO
func _on_animation_start():
if not animation or not animation_velocity.has(animation):
velocity = Vector2.ZERO
return
velocity = animation_velocity[animation] * speed_scale
# if GlobalConfig.DEBUG:
# print("animation ", animation, " velocity=", velocity)
func _physics_process(delta: float) -> void:
if Engine.is_editor_hint() or not velocity or not is_playing():
return
if flip_h:
position.x -= velocity.x * delta
else:
position.x += velocity.x * delta
if not velocity.y:
return
if flip_v:
position.y -= velocity.y * delta
else:
position.y += velocity.y * delta
# temporary set velocity
func set_animation_velocity(anim: String, v: Vector2) -> void:
animation_velocity[anim] = v
if GlobalConfig.DEBUG:
print("set_animation_velocity:", anim, v)
func play_with_velocity(anim: String, velocity: Vector2) -> void:
set_animation_velocity(anim, velocity)
play(anim)
# -1 means loop forever, 0 is invalid (which means no loop and return)
func play_with_loop(anim: String, loop := -1, wait := 0.0, next := "") -> void:
if loop < 0:
auto_checkout_dict.erase(anim)
sprite_frames.set_animation_loop(anim, true)
elif loop == 0:
return
else:
auto_checkout_dict[anim] = {
"animation_intro": anim,
"intro_loop": loop,
"animation_wait_time": wait,
"animation_next": next
}
# 设置完配置后播放
play(anim)