Animated Tilesets for All-Stars Resource Packs

This PR adds animated tilesets! I spent the day working on these, and it wasn't easy. This is primarily to help animate the All-Stars' grass tiles. You should be able to animate the other tilesets as well, but I haven't tested them.

JSONs are provided in the assets for Conveyer Belts and Liquids. There's two ways to animate the tilesets. The first is by the traditional way as used by `AnimatedSprite2D`, and the other is by how Godot animates tilesets normally as seen with the conveyer belts and liquids.

The last thing is that while doing this, I actually managed to fix the Resource Pack bug where reloading also reloads the blocks! It was surprisingly straightforward. I just edited the `BlockClass.gd` file to erase the cells when a block is hit or destroyed.

Let me know if you have any suggestions for things I should change or fix.
This commit is contained in:
KirbyKidJ
2025-09-30 00:04:03 -07:00
parent 9311424f55
commit 8b5d9afba9
14 changed files with 332 additions and 34 deletions

View File

@@ -4,14 +4,32 @@ extends Node
@export var tile_map: TileMapLayer
@export var texture: Texture = null:
set(value):
texture = value
texture = AtlasTexture.new()
texture.atlas = value
texture_changed.emit()
signal texture_changed
@export var atlas_id := 0
@export var resource_setter: ResourceSetterNew
@onready var resource_getter = ResourceGetter.new()
@onready var animation_timer = Timer.new()
var animation_atlas: AtlasTexture
var animation_json: Dictionary
var animation_frame: int = -1
var animation_loop: bool
func _ready() -> void:
animation_timer.one_shot = true
animation_timer.timeout.connect(run_frame)
add_child(animation_timer)
# Reset Tilemaps and Tilesets
if Global.level_editor == null and Global.current_game_mode != Global.GameMode.CUSTOM_LEVEL and atlas_id > 0:
tile_map.tile_set = tile_map.tile_set.duplicate(true)
tile_map = tile_map.duplicate()
# Update Textures
update()
texture_changed.connect(update)
@@ -19,3 +37,32 @@ func update() -> void:
var source = tile_map.tile_set.get_source(atlas_id)
if source != null:
source.texture = texture
if resource_setter != null: # Handles custom animations
animation_json = resource_setter.get_variation_json(resource_getter.get_resource(resource_setter.resource_json).data.get("animations", {}))
if animation_json.is_empty():
animation_loop = false
animation_timer.stop()
return
elif animation_json.has("loop"): # CREATE animations and frames based on the usual SMB1R format
animation_loop = animation_json.loop
animation_timer.start(1.0 / animation_json.speed)
else: # CREATE animations and frames based on GODOT's system
for id in animation_json:
if not id.begins_with("Tile:"): continue
var tile_id = int(id)
var coords = source.get_tile_id(tile_id)
var data = animation_json[id]
source.set_tile_animation_mode(coords, data.get("mode", TileSetAtlasSource.TILE_ANIMATION_MODE_DEFAULT))
source.set_tile_animation_speed(coords, data.get("speed", 1.0))
if not data.get("frames", []).is_empty():
source.set_tile_animation_frames_count(coords, data.frames.size())
for i in data.frames.size():
source.set_tile_animation_frame_duration(coords, i, data.frames[i].duration)
func run_frame() -> void:
var frames = animation_json.get("frames", [])
if frames.is_empty(): return
animation_frame = wrapi(animation_frame + 1, 0, frames.size())
var rect = Rect2(frames[animation_frame][0], frames[animation_frame][1], frames[animation_frame][2], frames[animation_frame][3])
texture.region = rect
if animation_loop: animation_timer.start(1.0 / animation_json.speed)