Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TileSetAtlasSource::TileAnimationMode options and allow to shuffle tile animations #77257

Merged
merged 1 commit into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions doc/classes/TileSetAtlasSource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@
Returns how many animation frames has the tile at coordinates [param atlas_coords].
</description>
</method>
<method name="get_tile_animation_mode" qualifiers="const">
<return type="int" enum="TileSetAtlasSource.TileAnimationMode" />
<param index="0" name="atlas_coords" type="Vector2i" />
<description>
Returns the [enum TileAnimationMode] of the tile at [param atlas_coords]. See also [method set_tile_animation_mode].
</description>
</method>
<method name="get_tile_animation_separation" qualifiers="const">
<return type="Vector2i" />
<param index="0" name="atlas_coords" type="Vector2i" />
Expand Down Expand Up @@ -215,6 +222,14 @@
Sets how many animation frames the tile at coordinates [param atlas_coords] has.
</description>
</method>
<method name="set_tile_animation_mode">
<return type="void" />
<param index="0" name="atlas_coords" type="Vector2i" />
<param index="1" name="mode" type="int" enum="TileSetAtlasSource.TileAnimationMode" />
<description>
Sets the [enum TileAnimationMode] of the tile at [param atlas_coords] to [param mode]. See also [method get_tile_animation_mode].
</description>
</method>
<method name="set_tile_animation_separation">
<return type="void" />
<param index="0" name="atlas_coords" type="Vector2i" />
Expand Down Expand Up @@ -250,4 +265,15 @@
Disabling this setting might lead a small performance improvement, as generating the internal texture requires both memory and processing time when the TileSetAtlasSource resource is modified.
</member>
</members>
<constants>
<constant name="TILE_ANIMATION_MODE_DEFAULT" value="0" enum="TileAnimationMode">
Tile animations start at same time, looking identical.
</constant>
<constant name="TILE_ANIMATION_MODE_RANDOM_START_TIMES" value="1" enum="TileAnimationMode">
Tile animations start at random times, looking varied.
</constant>
<constant name="TILE_ANIMATION_MODE_MAX" value="2" enum="TileAnimationMode">
Represents the size of the [enum TileAnimationMode] enum.
</constant>
</constants>
</class>
10 changes: 10 additions & 0 deletions editor/plugins/tiles/tile_set_atlas_source_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
}
emit_signal(SNAME("changed"), "animation_speed");
return true;
} else if (p_name == "animation_mode") {
for (TileSelection tile : tiles) {
tile_set_atlas_source->set_tile_animation_mode(tile.tile, VariantCaster<TileSetAtlasSource::TileAnimationMode>::cast(p_value));
}
emit_signal(SNAME("changed"), "animation_mode");
return true;
} else if (p_name == "animation_frames_count") {
for (TileSelection tile : tiles) {
int frame_count = p_value;
Expand Down Expand Up @@ -349,6 +355,9 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
} else if (p_name == "animation_speed") {
r_ret = tile_set_atlas_source->get_tile_animation_speed(coords);
return true;
} else if (p_name == "animation_mode") {
r_ret = tile_set_atlas_source->get_tile_animation_mode(coords);
return true;
} else if (p_name == "animation_frames_count") {
r_ret = tile_set_atlas_source->get_tile_animation_frames_count(coords);
return true;
Expand Down Expand Up @@ -417,6 +426,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_columns")));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, PNAME("animation_separation")));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("animation_speed")));
p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_mode"), PROPERTY_HINT_ENUM, "Default,Random Start Times"));
p_list->push_back(PropertyInfo(Variant::INT, PNAME("animation_frames_count"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
// Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does.
if (tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile) == 1) {
Expand Down
19 changes: 16 additions & 3 deletions scene/2d/tile_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1317,8 +1317,21 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
ci = prev_ci;
}

Vector2 p_position = E_cell.key - tile_position;
Vector2 p_atlas_coords = c.get_atlas_coords();

// Random animation offset.
real_t p_random_animation_offset = 0.0;
if (atlas_source->get_tile_animation_mode(p_atlas_coords) != TileSetAtlasSource::TILE_ANIMATION_MODE_DEFAULT) {
Array to_hash;
to_hash.push_back(p_position);
to_hash.push_back(q.layer);
to_hash.push_back(Variant(this));
p_random_animation_offset = RandomPCG(to_hash.hash()).randf();
}

// Drawing the tile in the canvas item.
draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, get_self_modulate(), tile_data);
draw_tile(ci, p_position, tile_set, c.source_id, p_atlas_coords, c.alternative_tile, -1, get_self_modulate(), tile_data, p_random_animation_offset);

// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
Expand Down Expand Up @@ -1436,7 +1449,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
}

void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override) {
void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override, real_t p_animation_offset) {
ERR_FAIL_COND(!p_tile_set.is_valid());
ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
Expand Down Expand Up @@ -1504,7 +1517,7 @@ void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<
real_t time = 0.0;
for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
real_t frame_duration = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame) / speed;
RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, 0.0);
RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, p_animation_offset);

Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame);
tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
Expand Down
2 changes: 1 addition & 1 deletion scene/2d/tile_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ class TileMap : public Node2D {
void set_quadrant_size(int p_size);
int get_quadrant_size() const;

static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr);
static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr, real_t p_animation_offset = 0.0);

// Layers management.
int get_layers_count() const;
Expand Down
33 changes: 33 additions & 0 deletions scene/resources/tile_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3923,6 +3923,9 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value)
} else if (components[1] == "animation_speed") {
set_tile_animation_speed(coords, p_value);
return true;
} else if (components[1] == "animation_mode") {
set_tile_animation_mode(coords, VariantCaster<TileSetAtlasSource::TileAnimationMode>::cast(p_value));
return true;
} else if (components[1] == "animation_frames_count") {
set_tile_animation_frames_count(coords, p_value);
return true;
Expand Down Expand Up @@ -3990,6 +3993,9 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const {
} else if (components[1] == "animation_speed") {
r_ret = get_tile_animation_speed(coords);
return true;
} else if (components[1] == "animation_mode") {
r_ret = get_tile_animation_mode(coords);
return true;
} else if (components[1] == "animation_frames_count") {
r_ret = get_tile_animation_frames_count(coords);
return true;
Expand Down Expand Up @@ -4065,6 +4071,13 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
}
tile_property_list.push_back(property_info);

// animation_mode.
property_info = PropertyInfo(Variant::INT, "animation_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
if (E_tile.value.animation_mode == TILE_ANIMATION_MODE_DEFAULT) {
property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
tile_property_list.push_back(property_info);

// animation_frames_count.
tile_property_list.push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));

Expand Down Expand Up @@ -4227,6 +4240,20 @@ real_t TileSetAtlasSource::get_tile_animation_speed(const Vector2i p_atlas_coord
return tiles[p_atlas_coords].animation_speed;
}

void TileSetAtlasSource::set_tile_animation_mode(const Vector2i p_atlas_coords, TileSetAtlasSource::TileAnimationMode p_mode) {
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));

tiles[p_atlas_coords].animation_mode = p_mode;

emit_signal(SNAME("changed"));
}

TileSetAtlasSource::TileAnimationMode TileSetAtlasSource::get_tile_animation_mode(const Vector2i p_atlas_coords) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TILE_ANIMATION_MODE_DEFAULT, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));

return tiles[p_atlas_coords].animation_mode;
}

void TileSetAtlasSource::set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count) {
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
ERR_FAIL_COND(p_frames_count < 1);
Expand Down Expand Up @@ -4552,6 +4579,8 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tile_animation_separation", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_separation);
ClassDB::bind_method(D_METHOD("set_tile_animation_speed", "atlas_coords", "speed"), &TileSetAtlasSource::set_tile_animation_speed);
ClassDB::bind_method(D_METHOD("get_tile_animation_speed", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_speed);
ClassDB::bind_method(D_METHOD("set_tile_animation_mode", "atlas_coords", "mode"), &TileSetAtlasSource::set_tile_animation_mode);
ClassDB::bind_method(D_METHOD("get_tile_animation_mode", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_mode);
ClassDB::bind_method(D_METHOD("set_tile_animation_frames_count", "atlas_coords", "frames_count"), &TileSetAtlasSource::set_tile_animation_frames_count);
ClassDB::bind_method(D_METHOD("get_tile_animation_frames_count", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_frames_count);
ClassDB::bind_method(D_METHOD("set_tile_animation_frame_duration", "atlas_coords", "frame_index", "duration"), &TileSetAtlasSource::set_tile_animation_frame_duration);
Expand All @@ -4574,6 +4603,10 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_padded_texture"), &TileSetAtlasSource::_update_padded_texture);
ClassDB::bind_method(D_METHOD("get_runtime_texture"), &TileSetAtlasSource::get_runtime_texture);
ClassDB::bind_method(D_METHOD("get_runtime_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_runtime_tile_texture_region);

BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_DEFAULT)
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_RANDOM_START_TIMES)
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_MAX)
}

TileSetAtlasSource::~TileSetAtlasSource() {
Expand Down
12 changes: 12 additions & 0 deletions scene/resources/tile_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,13 @@ class TileSetSource : public Resource {
class TileSetAtlasSource : public TileSetSource {
GDCLASS(TileSetAtlasSource, TileSetSource);

public:
enum TileAnimationMode {
TILE_ANIMATION_MODE_DEFAULT,
TILE_ANIMATION_MODE_RANDOM_START_TIMES,
TILE_ANIMATION_MODE_MAX,
};

private:
struct TileAlternativesData {
Vector2i size_in_atlas = Vector2i(1, 1);
Expand All @@ -599,6 +606,7 @@ class TileSetAtlasSource : public TileSetSource {
int animation_columns = 0;
Vector2i animation_separation;
real_t animation_speed = 1.0;
TileSetAtlasSource::TileAnimationMode animation_mode = TILE_ANIMATION_MODE_DEFAULT;
LocalVector<real_t> animation_frames_durations;

// Alternatives
Expand Down Expand Up @@ -699,6 +707,8 @@ class TileSetAtlasSource : public TileSetSource {
Vector2i get_tile_animation_separation(const Vector2i p_atlas_coords) const;
void set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed);
real_t get_tile_animation_speed(const Vector2i p_atlas_coords) const;
void set_tile_animation_mode(const Vector2i p_atlas_coords, const TileSetAtlasSource::TileAnimationMode p_mode);
TileSetAtlasSource::TileAnimationMode get_tile_animation_mode(const Vector2i p_atlas_coords) const;
void set_tile_animation_frames_count(const Vector2i p_atlas_coords, int p_frames_count);
int get_tile_animation_frames_count(const Vector2i p_atlas_coords) const;
void set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration);
Expand Down Expand Up @@ -930,4 +940,6 @@ VARIANT_ENUM_CAST(TileSet::TileShape);
VARIANT_ENUM_CAST(TileSet::TileLayout);
VARIANT_ENUM_CAST(TileSet::TileOffsetAxis);

VARIANT_ENUM_CAST(TileSetAtlasSource::TileAnimationMode);

#endif // TILE_SET_H