Skip to content

Instantly share code, notes, and snippets.

@Aldlevine
Last active April 6, 2022 00:02
Show Gist options
  • Save Aldlevine/93b8958a39fe7ce7ad8c2b253ccec1c5 to your computer and use it in GitHub Desktop.
Save Aldlevine/93b8958a39fe7ce7ad8c2b253ccec1c5 to your computer and use it in GitHub Desktop.
Adds an animated atlas texture to Godot
extends AtlasTexture
class_name AnimatedAtlasTexture
export(int, 1, 100) var h_frames := 1
export(int, 1, 100) var v_frames := 1
export var fps := 10.0
var previous_frame := 0
var frame := 0
func _init() -> void:
var err = VisualServer.connect("frame_pre_draw", self, "_update")
assert(err == OK)
func _update() -> void:
if atlas:
previous_frame = frame
var img := atlas.get_data()
var size = img.get_size()
var frame_size = size / Vector2(h_frames, v_frames)
frame = int(int(OS.get_ticks_msec() / (1000.0 / fps)) % (h_frames * v_frames))
var frame_pos = Vector2(frame % h_frames, floor(float(frame) / h_frames))
region = Rect2(frame_size * frame_pos, frame_size)
if previous_frame != frame:
emit_changed()
## Use this instead of a TileSet for any TileSet that contains AnimatedAtlasTexture.
## Can be added as a script to any TileSet resource, or you can create it directly in the
## TileMap's tile_set field by selecting "New AnimatedTileSet" instead of "New TileSet"
## The key is that emit_changed() must be called for the TileMap to update.
tool
extends TileSet
class_name AnimatedTileSet
var _needs_update := false
func _init() -> void:
var err
var tiles := get_tiles_ids()
for tile in tiles:
var tex = tile_get_texture(tile)
if tex is AnimatedAtlasTexture:
err = tex.connect("changed", self, "_set_needs_update", [])
assert(err == OK)
err = VisualServer.connect("frame_pre_draw", self, "_update", [], CONNECT_DEFERRED)
assert(err == OK)
func _set_needs_update() -> void:
_needs_update = true
func _update() -> void:
if _needs_update:
emit_changed()
_needs_update = false
[plugin]
name="animated_atlas_texture"
description="Adds an animated atlas texture resource"
author="Aaron Levine"
version=""
script="plugin.gd"
tool
extends EditorPlugin
var resource : AnimatedAtlasTexture
func _enter_tree():
VisualServer.connect("frame_pre_draw", self, "_update")
func _exit_tree():
VisualServer.disconnect("frame_pre_draw", self, "_update")
func handles(object: Object) -> bool:
if object is AnimatedAtlasTexture:
resource = object as AnimatedAtlasTexture
return object is AnimatedAtlasTexture
func _update() -> void:
if resource is AnimatedAtlasTexture:
if resource.atlas:
var img := resource.atlas.get_data()
var size = img.get_size()
var frame_size = size / Vector2(resource.h_frames, resource.v_frames)
var frame = int(int(OS.get_ticks_msec() / (1000.0 / resource.fps)) % (resource.h_frames * resource.v_frames))
var frame_pos = Vector2(frame % resource.h_frames, floor(float(frame) / resource.h_frames))
resource.region = Rect2(frame_size * frame_pos, frame_size)
@boruok
Copy link

boruok commented Apr 6, 2022

Changed a lil bit, maked script straightforward + added support per AtlasTexture region (if you want make mutltiple AtlasTextures from single StreamTexture)

animated_atlas_texture.gd

class_name AnimatedAtlasTexture extends AtlasTexture


export(int, 1, 100) var h_frames := 1
export(int, 1, 100) var v_frames := 1
export var fps := 10.0

var frame_position : Vector2
var frame_size : Vector2
var frame_last := 0
var frame := 0


func init() -> void:
	frame_size = region.size / Vector2(h_frames, v_frames)
	frame_position = region.position
	VisualServer.connect("frame_pre_draw", self, "_on_frame_pre_draw")


func _on_frame_pre_draw() -> void:
	if !atlas: return

	frame = int(OS.get_ticks_msec() / (1000.0 / fps)) % (h_frames * v_frames)
	region = Rect2(
		frame_position + (frame_size * Vector2(frame % h_frames, frame / h_frames)),
		frame_size)

	if frame_last != frame:
		frame_last = frame
		emit_changed()

tilemap.gd

extends TileMap


func _ready() -> void:
	for tile in tile_set.get_tiles_ids():
		var texture := tile_set.tile_get_texture(tile)

		if texture is AnimatedAtlasTexture:
			texture.init()
			texture.connect("changed", self, "_on_AnimatedAtlasTexture_changed")


func _on_AnimatedAtlasTexture_changed() -> void:
	tile_set.emit_changed()

example regions
test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment