Skip to content

Commit

Permalink
Add "Explicit Start Frame" tile animation mode
Browse files Browse the repository at this point in the history
  • Loading branch information
rakkarage committed Sep 28, 2023
1 parent 2048fe5 commit 148ee11
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 44 deletions.
3 changes: 3 additions & 0 deletions doc/classes/TileMap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,16 @@
<param index="2" name="source_id" type="int" default="-1" />
<param index="3" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
<param index="4" name="alternative_tile" type="int" default="0" />
<param index="5" name="explicit_start_frame" type="int" default="-1" />
<description>
Sets the tile identifiers for the cell on layer [param layer] at coordinates [param coords]. Each tile of the [TileSet] is identified using three parts:
- The source identifier [param source_id] identifies a [TileSetSource] identifier. See [method TileSet.set_source_id],
- The atlas coordinates identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]). For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code]),
- The alternative tile identifier [param alternative_tile] identifies a tile alternative in the atlas (if the source is a [TileSetAtlasSource]), and the scene for a [TileSetScenesCollectionSource].
If [param source_id] is set to [code]-1[/code], [param atlas_coords] to [code]Vector2i(-1, -1)[/code] or [param alternative_tile] to [code]-1[/code], the cell will be erased. An erased cell gets [b]all[/b] its identifiers automatically set to their respective invalid values, namely [code]-1[/code], [code]Vector2i(-1, -1)[/code] and [code]-1[/code].
If [param layer] is negative, the layers are accessed from the last one.
Sets the [param explicit_start_frame] to use for this tile.
If [param explicit_start_frame] is set to [code]-1[/code], uses the default, cached, or loaded explicit start frame instead.
</description>
</method>
<method name="set_cells_terrain_connect">
Expand Down
5 changes: 4 additions & 1 deletion doc/classes/TileSetAtlasSource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,10 @@
<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">
<constant name="TILE_ANIMATION_MODE_EXPLICIT_START_FRAME" value="2" enum="TileAnimationMode">
Tile animations start at the explicitly selected start frame.
</constant>
<constant name="TILE_ANIMATION_MODE_MAX" value="3" enum="TileAnimationMode">
Represents the size of the [enum TileAnimationMode] enum.
</constant>
<constant name="TRANSFORM_FLIP_H" value="4096">
Expand Down
67 changes: 42 additions & 25 deletions editor/plugins/tiles/tile_map_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}
}
_fix_invalid_tiles_in_tile_map_selection();
Expand All @@ -655,7 +655,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}
}
}
Expand Down Expand Up @@ -699,7 +699,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
for (const Vector2i &E : tile_map_selection) {
Vector2i coords = E;
drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
tile_map->set_cell(tile_map_layer, coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
tile_map->set_cell(tile_map_layer, coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE, selected_explicit_start_frame);
}
} else {
// Select tiles
Expand All @@ -725,7 +725,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_modified.has(coords)) {
drag_modified.insert(coords, tile_map->get_cell(tile_map_layer, coords));
}
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}
_fix_invalid_tiles_in_tile_map_selection();
} else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
Expand All @@ -751,7 +751,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}
}
}
Expand Down Expand Up @@ -1351,7 +1351,7 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
if (patterns_item_list->is_visible_in_tree() && patterns_item_list->has_point(patterns_item_list->get_local_mouse_position())) {
// Restore the cells.
for (KeyValue<Vector2i, TileMapCell> kv : drag_modified) {
tile_map->set_cell(tile_map_layer, kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile);
tile_map->set_cell(tile_map_layer, kv.key, kv.value.source_id, kv.value.get_atlas_coords(), kv.value.alternative_tile, selected_explicit_start_frame);
}

if (!EditorNode::get_singleton()->is_resource_read_only(tile_set)) {
Expand Down Expand Up @@ -1403,10 +1403,10 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
// Move the tiles.
undo_redo->create_action(TTR("Move tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : cells_do) {
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}
for (const KeyValue<Vector2i, TileMapCell> &E : cells_undo) {
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}

// Update the selection.
Expand Down Expand Up @@ -1463,8 +1463,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
case DRAG_TYPE_PAINT: {
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : drag_modified) {
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key));
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key), selected_explicit_start_frame);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}
undo_redo->commit_action(false);
} break;
Expand All @@ -1475,8 +1475,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key));
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key), selected_explicit_start_frame);
}
undo_redo->commit_action();
} break;
Expand All @@ -1487,16 +1487,16 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
if (!drag_erasing && E.value.source_id == TileSet::INVALID_SOURCE) {
continue;
}
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key));
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key), selected_explicit_start_frame);
}
undo_redo->commit_action();
} break;
case DRAG_TYPE_BUCKET: {
undo_redo->create_action(TTR("Paint tiles"));
for (const KeyValue<Vector2i, TileMapCell> &E : drag_modified) {
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key));
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E.key, tile_map->get_cell_source_id(tile_map_layer, E.key), tile_map->get_cell_atlas_coords(tile_map_layer, E.key), tile_map->get_cell_alternative_tile(tile_map_layer, E.key), selected_explicit_start_frame);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile, selected_explicit_start_frame);
}
undo_redo->commit_action(false);
} break;
Expand All @@ -1506,8 +1506,8 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
TypedArray<Vector2i> used_cells = tile_map_clipboard->get_used_cells();
for (int i = 0; i < used_cells.size(); i++) {
Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(mpos - mouse_offset), used_cells[i], tile_map_clipboard);
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i]));
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, coords, tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords));
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, coords, tile_map_clipboard->get_cell_source_id(used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(used_cells[i]), selected_explicit_start_frame);
undo_redo->add_undo_method(tile_map, "set_cell", tile_map_layer, coords, tile_map->get_cell_source_id(tile_map_layer, coords), tile_map->get_cell_atlas_coords(tile_map_layer, coords), tile_map->get_cell_alternative_tile(tile_map_layer, coords), selected_explicit_start_frame);
}
undo_redo->commit_action();
} break;
Expand Down Expand Up @@ -1866,21 +1866,23 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
for (const TileMapCell &E : tile_set_selection) {
if (E.source_id == source_id && E.alternative_tile == 0) {
for (int frame = 0; frame < atlas->get_tile_animation_frames_count(E.get_atlas_coords()); frame++) {
Vector2i coords = E.get_atlas_coords();
for (int frame = 0; frame < atlas->get_tile_animation_frames_count(coords); frame++) {
Color color = selection_color;
if (frame > 0) {
if (frame != (atlas->get_tile_animation_mode(coords) == TileSetAtlasSource::TILE_ANIMATION_MODE_EXPLICIT_START_FRAME ? selected_explicit_start_frame : 0)) {
color.a *= 0.3;
}
TilesEditorUtils::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(E.get_atlas_coords(), frame), color);
TilesEditorUtils::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(coords, frame), color);
}
}
}

// Draw the hovered tile.
if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0 && !tile_set_dragging_selection) {
for (int frame = 0; frame < atlas->get_tile_animation_frames_count(hovered_tile.get_atlas_coords()); frame++) {
Color color = Color(1.0, 0.8, 0.0, frame == 0 ? 0.6 : 0.3);
TilesEditorUtils::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(hovered_tile.get_atlas_coords(), frame), color);
Vector2i coords = hovered_tile.get_atlas_coords();
if (coords != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0 && !tile_set_dragging_selection) {
for (int frame = 0; frame < atlas->get_tile_animation_frames_count(coords); frame++) {
Color color = Color(1.0, 0.8, 0.0, frame == (atlas->get_tile_animation_mode(coords) == TileSetAtlasSource::TILE_ANIMATION_MODE_EXPLICIT_START_FRAME ? selected_explicit_start_frame : 0) ? 0.6 : 0.3);
TilesEditorUtils::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(coords, frame), color);
}
}

Expand Down Expand Up @@ -1945,6 +1947,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS);
hovered_tile.alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
Vector2i original_coords = coords;
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
coords = atlas->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
Expand Down Expand Up @@ -1975,6 +1978,20 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
tile_set_selection.insert(TileMapCell(source_id, hovered_tile.get_atlas_coords(), 0));
}
}

// Set the selected explicit start frame if needed.
if (atlas->get_tile_animation_mode(coords) == TileSetAtlasSource::TILE_ANIMATION_MODE_EXPLICIT_START_FRAME) {
int frames_count = atlas->get_tile_animation_frames_count(coords);
if (frames_count > 1) {
int columns = atlas->get_tile_animation_columns(coords);
if (columns > 0) {
int rows = (frames_count + columns - 1) / columns;
selected_explicit_start_frame = original_coords.x - coords.x + columns * (original_coords.y - coords.y % rows);
} else {
selected_explicit_start_frame = original_coords.x - coords.x;
}
}
}
_update_selection_pattern_from_tileset_tiles_selection();
} else { // Released
if (tile_set_dragging_selection) {
Expand Down
2 changes: 2 additions & 0 deletions editor/plugins/tiles/tile_map_editor.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ class TileMapEditorTilesPlugin : public TileMapSubEditorPlugin {

void patterns_item_list_empty_clicked(const Vector2 &p_pos, MouseButton p_mouse_button_index);

int selected_explicit_start_frame = 0;

///// Bottom panel common ////
void _tab_changed();

Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/tiles/tile_set_atlas_source_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,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_mode"), PROPERTY_HINT_ENUM, "Default,Random Start Times,Explicit Start Frame"));
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
Loading

0 comments on commit 148ee11

Please sign in to comment.