summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/cpu_particles_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp46
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/3d/bone_attachment_3d.cpp2
-rw-r--r--scene/3d/skeleton_3d.cpp1
-rw-r--r--scene/gui/code_edit.cpp4
-rw-r--r--scene/gui/color_picker.cpp2
-rw-r--r--scene/gui/graph_edit.cpp6
-rw-r--r--scene/gui/graph_node.cpp2
-rw-r--r--scene/gui/popup.cpp8
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--scene/gui/scroll_bar.cpp2
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/text_edit.cpp14
-rw-r--r--scene/resources/bit_map.cpp2
-rw-r--r--scene/resources/default_theme/default_theme.cpp4
-rw-r--r--scene/resources/tile_set.cpp391
-rw-r--r--scene/resources/tile_set.h36
18 files changed, 393 insertions, 137 deletions
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index b836497627..cf2632f380 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -155,7 +155,7 @@ void CPUParticles2D::_update_mesh_texture() {
Vector<Vector2> vertices;
vertices.push_back(-tex_size * 0.5);
vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, 0));
- vertices.push_back(-tex_size * 0.5 + Vector2(tex_size.x, tex_size.y));
+ vertices.push_back(-tex_size * 0.5 + tex_size);
vertices.push_back(-tex_size * 0.5 + Vector2(0, tex_size.y));
Vector<Vector2> uvs;
AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture);
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index a139a92ab4..03db9c0d32 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -891,7 +891,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
modulate.a *= 0.3;
}
}
- draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, modulate);
+ draw_tile(canvas_item, E_cell->key() - position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, modulate);
// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
@@ -1008,15 +1008,19 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) {
}
}
-void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation) {
+void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation) {
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));
ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
-
TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
+ // Check for the frame.
+ if (p_frame >= 0) {
+ ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords));
+ }
+
// Get the texture.
Ref<Texture2D> tex = atlas_source->get_texture();
if (!tex.is_valid()) {
@@ -1032,13 +1036,15 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe
// Get tile data.
TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile));
- // Compute the offset
- Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords);
+ // Get the tile modulation.
+ Color modulate = tile_data->get_modulate() * p_modulation;
+
+ // Compute the offset.
Vector2i tile_offset = atlas_source->get_tile_effective_texture_offset(p_atlas_coords, p_alternative_tile);
- // Compute the destination rectangle in the CanvasItem.
+ // Get destination rect.
Rect2 dest_rect;
- dest_rect.size = source_rect.size;
+ dest_rect.size = atlas_source->get_tile_texture_region(p_atlas_coords).size;
dest_rect.size.x += FP_ADJUST;
dest_rect.size.y += FP_ADJUST;
@@ -1057,12 +1063,28 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe
dest_rect.size.y = -dest_rect.size.y;
}
- // Get the tile modulation.
- Color modulate = tile_data->get_modulate();
- modulate = Color(modulate.r * p_modulation.r, modulate.g * p_modulation.g, modulate.b * p_modulation.b, modulate.a * p_modulation.a);
-
// Draw the tile.
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ if (p_frame >= 0) {
+ Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, p_frame);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) {
+ Rect2i source_rect = atlas_source->get_tile_texture_region(p_atlas_coords, 0);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else {
+ real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
+ real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
+ 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);
+
+ Rect2i source_rect = atlas_source->get_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());
+
+ time += frame_duration;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);
+ }
}
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 3ac50fc7cc..ca38baa550 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -305,7 +305,7 @@ public:
void set_quadrant_size(int p_size);
int get_quadrant_size() const;
- static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0));
+ static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0));
// Layers management.
int get_layers_count() const;
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index 70361f4787..c34c150145 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -161,7 +161,7 @@ void BoneAttachment3D::_check_bind() {
bone_idx = sk->find_bone(bone_name);
}
if (bone_idx != -1) {
- sk->call_deferred("connect", "bone_pose_changed", callable_mp(this, &BoneAttachment3D::on_bone_pose_update));
+ sk->call_deferred(SNAME("connect"), "bone_pose_changed", callable_mp(this, &BoneAttachment3D::on_bone_pose_update));
bound = true;
call_deferred(SNAME("on_bone_pose_update"), bone_idx);
}
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 0f5de621ea..b7a79a2645 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -520,6 +520,7 @@ void Skeleton3D::set_bone_parent(int p_bone, int p_parent) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
+ ERR_FAIL_COND(p_bone == p_parent);
bones.write[p_bone].parent = p_parent;
process_order_dirty = true;
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 4dfd6902e6..5d1106bb41 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -296,7 +296,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
mpos.x = get_size().x - mpos.x;
}
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int line = pos.y;
int col = pos.x;
@@ -321,7 +321,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
mpos.x = get_size().x - mpos.x;
}
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int line = pos.y;
int col = pos.x;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index efb6b7d200..046715e17e 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -996,7 +996,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mev = p_event;
if (mev.is_valid()) {
Viewport *r = get_tree()->get_root();
- if (!r->get_visible_rect().has_point(Point2(mev->get_global_position().x, mev->get_global_position().y))) {
+ if (!r->get_visible_rect().has_point(mev->get_global_position())) {
return;
}
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index b9b02b1427..bca3b2059d 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -697,7 +697,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
} else if (!just_disconnected) {
String from = connecting_from;
int from_slot = connecting_index;
- Vector2 ofs = Vector2(mb->get_position().x, mb->get_position().y);
+ Vector2 ofs = mb->get_position();
if (!connecting_out) {
emit_signal(SNAME("connection_from_empty"), from, from_slot, ofs);
@@ -2103,7 +2103,7 @@ void GraphEdit::arrange_nodes() {
largest_node_size = 0.0f;
}
- emit_signal("begin_node_move");
+ emit_signal(SNAME("begin_node_move"));
for (const Set<StringName>::Element *E = selected_nodes.front(); E; E = E->next()) {
GraphNode *gn = Object::cast_to<GraphNode>(node_names[E->get()]);
gn->set_drag(true);
@@ -2116,7 +2116,7 @@ void GraphEdit::arrange_nodes() {
gn->set_position_offset(pos);
gn->set_drag(false);
}
- emit_signal("end_node_move");
+ emit_signal(SNAME("end_node_move"));
arranging_graph = false;
}
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 08c8c60d7a..cbdf2a498a 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -871,7 +871,7 @@ void GraphNode::gui_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND_MSG(get_parent_control() == nullptr, "GraphNode must be the child of a GraphEdit node.");
if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- Vector2 mpos = Vector2(mb->get_position().x, mb->get_position().y);
+ Vector2 mpos = mb->get_position();
if (close_rect.size != Size2() && close_rect.has_point(mpos)) {
//send focus to parent
get_parent_control()->grab_focus();
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index e9414598a2..be05fd5a60 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -194,7 +194,7 @@ Popup::~Popup() {
}
Size2 PopupPanel::_get_contents_minimum_size() const {
- Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name());
+ Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
Size2 ms;
@@ -217,7 +217,7 @@ Size2 PopupPanel::_get_contents_minimum_size() const {
}
void PopupPanel::_update_child_rects() {
- Ref<StyleBox> p = get_theme_stylebox("panel", get_class_name());
+ Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name());
Vector2 cpos(p->get_offset());
Vector2 csize(get_size() - p->get_minimum_size());
@@ -244,9 +244,9 @@ void PopupPanel::_update_child_rects() {
void PopupPanel::_notification(int p_what) {
if (p_what == NOTIFICATION_THEME_CHANGED) {
- panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name()));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
} else if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) {
- panel->add_theme_style_override("panel", get_theme_stylebox("panel", get_class_name()));
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name()));
_update_child_rects();
} else if (p_what == NOTIFICATION_WM_SIZE_CHANGED) {
_update_child_rects();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index eb88570663..3eaae5181d 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -333,7 +333,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font>
} else {
frame->lines.write[i].offset.y = 0;
}
- frame->lines.write[i].offset += Vector2(offset.x, offset.y);
+ frame->lines.write[i].offset += offset;
float h = frame->lines[i].text_buf->get_size().y;
if (frame->min_size_over.y > 0) {
@@ -578,7 +578,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
} else {
frame->lines.write[i].offset.y = 0;
}
- frame->lines.write[i].offset += Vector2(offset.x, offset.y);
+ frame->lines.write[i].offset += offset;
float h = frame->lines[i].text_buf->get_size().y;
if (frame->min_size_over.y > 0) {
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 4edf373fbf..4a3a6837d5 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -560,7 +560,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) {
if (mm.is_valid()) {
if (drag_node_touching && !drag_node_touching_deaccel) {
- Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y);
+ Vector2 motion = mm->get_relative();
drag_node_accum -= motion;
Vector2 diff = drag_node_from + drag_node_accum;
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 0c051f61e2..0c0ec39c7f 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -167,7 +167,7 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
if (mm.is_valid()) {
if (drag_touching && !drag_touching_deaccel) {
- Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y);
+ Vector2 motion = mm->get_relative();
drag_accum -= motion;
if (beyond_deadzone || (scroll_h && Math::abs(drag_accum.x) > deadzone) || (scroll_v && Math::abs(drag_accum.y) > deadzone)) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 06dfc31621..09899413f2 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1444,7 +1444,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_reset_caret_blink_timer();
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int row = pos.y;
int col = pos.x;
@@ -1547,7 +1547,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) {
_reset_caret_blink_timer();
- Point2i pos = get_line_column_at_pos(Point2i(mpos.x, mpos.y));
+ Point2i pos = get_line_column_at_pos(mpos);
int row = pos.y;
int col = pos.x;
@@ -5385,7 +5385,7 @@ void TextEdit::_update_selection_mode_pointer() {
dragging_selection = true;
Point2 mp = get_local_mouse_pos();
- Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y));
+ Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
@@ -5402,7 +5402,7 @@ void TextEdit::_update_selection_mode_word() {
dragging_selection = true;
Point2 mp = get_local_mouse_pos();
- Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y));
+ Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
@@ -5450,7 +5450,7 @@ void TextEdit::_update_selection_mode_line() {
dragging_selection = true;
Point2 mp = get_local_mouse_pos();
- Point2i pos = get_line_column_at_pos(Point2i(mp.x, mp.y));
+ Point2i pos = get_line_column_at_pos(mp);
int line = pos.y;
int col = pos.x;
@@ -5765,7 +5765,7 @@ void TextEdit::_update_minimap_hover() {
return;
}
- const int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y));
+ const int row = get_minimap_line_at_pos(mp);
const bool new_hovering_minimap = row >= get_first_visible_line() && row <= get_last_full_visible_line();
if (new_hovering_minimap != hovering_minimap) {
@@ -5786,7 +5786,7 @@ void TextEdit::_update_minimap_click() {
minimap_clicked = true;
dragging_minimap = true;
- int row = get_minimap_line_at_pos(Point2i(mp.x, mp.y));
+ int row = get_minimap_line_at_pos(mp);
if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) {
minimap_scroll_ratio = v_scroll->get_as_ratio();
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index de557494c3..49ed9dcb82 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -48,7 +48,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol
img->convert(Image::FORMAT_LA8);
ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8);
- create(Size2(img->get_width(), img->get_height()));
+ create(img->get_size());
const uint8_t *r = img->get_data().ptr();
uint8_t *w = bitmask.ptrw();
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 7346b6efc7..492e0512e4 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -51,7 +51,7 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl
} else {
texture = Ref<ImageTexture>(memnew(ImageTexture));
Ref<Image> img = memnew(Image(p_src));
- const Size2 orig_size = Size2(img->get_width(), img->get_height());
+ const Size2 orig_size = img->get_size();
img->convert(Image::FORMAT_RGBA8);
img->resize(orig_size.x * scale, orig_size.y * scale);
@@ -97,7 +97,7 @@ template <class T>
static Ref<Texture2D> make_icon(T p_src) {
Ref<ImageTexture> texture(memnew(ImageTexture));
Ref<Image> img = memnew(Image(p_src));
- const Size2 orig_size = Size2(img->get_width(), img->get_height());
+ const Size2 orig_size = img->get_size();
img->convert(Image::FORMAT_RGBA8);
img->resize(orig_size.x * scale, orig_size.y * scale);
texture->create_from_image(img);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 918fc3fe9c..67cbd0e094 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -3119,7 +3119,7 @@ Vector2i TileSetAtlasSource::get_atlas_grid_size() const {
}
bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) {
- Vector<String> components = String(p_name).split("/", true, 2);
+ Vector<String> components = String(p_name).split("/", true, 3);
// Compute the vector2i if we have coordinates.
Vector<String> coords_split = components[0].split(":");
@@ -3138,8 +3138,32 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value)
// Properties.
if (components[1] == "size_in_atlas") {
move_tile_in_atlas(coords, coords, p_value);
+ return true;
} else if (components[1] == "next_alternative_id") {
tiles[coords].next_alternative_id = p_value;
+ return true;
+ } else if (components[1] == "animation_columns") {
+ set_tile_animation_columns(coords, p_value);
+ return true;
+ } else if (components[1] == "animation_separation") {
+ set_tile_animation_separation(coords, p_value);
+ return true;
+ } else if (components[1] == "animation_speed") {
+ set_tile_animation_speed(coords, p_value);
+ return true;
+ } else if (components[1] == "animation_frames_count") {
+ set_tile_animation_frames_count(coords, p_value);
+ return true;
+ } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
+ int frame = components[1].trim_prefix("animation_frame_").to_int();
+ if (components[2] == "duration") {
+ if (frame >= get_tile_animation_frames_count(coords)) {
+ set_tile_animation_frames_count(coords, frame + 1);
+ }
+ set_tile_animation_frame_duration(coords, frame, p_value);
+ return true;
+ }
+ return false;
} else if (components[1].is_valid_int()) {
int alternative_id = components[1].to_int();
if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
@@ -3185,6 +3209,28 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const {
} else if (components[1] == "next_alternative_id") {
r_ret = tiles[coords].next_alternative_id;
return true;
+ } else if (components[1] == "animation_columns") {
+ r_ret = get_tile_animation_columns(coords);
+ return true;
+ } else if (components[1] == "animation_separation") {
+ r_ret = get_tile_animation_separation(coords);
+ return true;
+ } else if (components[1] == "animation_speed") {
+ r_ret = get_tile_animation_speed(coords);
+ return true;
+ } else if (components[1] == "animation_frames_count") {
+ r_ret = get_tile_animation_frames_count(coords);
+ return true;
+ } else if (components.size() >= 3 && components[1].begins_with("animation_frame_") && components[1].trim_prefix("animation_frame_").is_valid_int()) {
+ int frame = components[1].trim_prefix("animation_frame_").to_int();
+ if (frame < 0 || frame >= get_tile_animation_frames_count(coords)) {
+ return false;
+ }
+ if (components[2] == "duration") {
+ r_ret = get_tile_animation_frame_duration(coords, frame);
+ return true;
+ }
+ return false;
} else if (components[1].is_valid_int()) {
int alternative_id = components[1].to_int();
if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) {
@@ -3226,6 +3272,40 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
}
tile_property_list.push_back(property_info);
+ // animation_columns.
+ property_info = PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().animation_columns == 0) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
+ // animation_separation.
+ property_info = PropertyInfo(Variant::INT, "animation_separation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().animation_separation == Vector2i()) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+
+ // animation_speed.
+ property_info = PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (E_tile->get().animation_speed == 1.0) {
+ 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_NETWORK));
+
+ // animation_frame_*.
+ bool store_durations = tiles[E_tile->key()].animation_frames_durations.size() >= 2;
+ for (int i = 0; i < (int)tiles[E_tile->key()].animation_frames_durations.size(); i++) {
+ property_info = PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ if (!store_durations) {
+ property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ }
+ tile_property_list.push_back(property_info);
+ }
+
for (Map<int, TileData *>::Element *E_alternative = E_tile->get().alternatives.front(); E_alternative; E_alternative = E_alternative->next()) {
// Add a dummy property to show the alternative exists.
tile_property_list.push_back(PropertyInfo(Variant::INT, vformat("%d", E_alternative->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
@@ -3234,11 +3314,10 @@ void TileSetAtlasSource::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> alternative_property_list;
E_alternative->get()->get_property_list(&alternative_property_list);
for (PropertyInfo &alternative_property_info : alternative_property_list) {
- bool valid;
- Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name, &valid);
+ Variant default_value = ClassDB::class_get_default_property_value("TileData", alternative_property_info.name);
Variant value = E_alternative->get()->get(alternative_property_info.name);
- if (valid && value == default_value) {
- property_info.usage ^= PROPERTY_USAGE_STORAGE;
+ if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value))) {
+ alternative_property_info.usage ^= PROPERTY_USAGE_STORAGE;
}
alternative_property_info.name = vformat("%s/%s", vformat("%d", E_alternative->key()), alternative_property_info.name);
tile_property_list.push_back(alternative_property_info);
@@ -3257,33 +3336,27 @@ void TileSetAtlasSource::create_tile(const Vector2i p_atlas_coords, const Vector
// Create a tile if it does not exists.
ERR_FAIL_COND(p_atlas_coords.x < 0 || p_atlas_coords.y < 0);
ERR_FAIL_COND(p_size.x <= 0 || p_size.y <= 0);
- for (int x = 0; x < p_size.x; x++) {
- for (int y = 0; y < p_size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- ERR_FAIL_COND_MSG(tiles.has(coords), vformat("Cannot create tile at position %s with size %s. Already a tile present at %s.", p_atlas_coords, p_size, coords));
- }
- }
+
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, p_size, 1, Vector2i(), 1);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot create tile, tiles are already present in the space the tile would cover.");
+
+ // Initialize the tile data.
+ TileAlternativesData tad;
+ tad.size_in_atlas = p_size;
+ tad.animation_frames_durations.push_back(1.0);
+ tad.alternatives[0] = memnew(TileData);
+ tad.alternatives[0]->set_tile_set(tile_set);
+ tad.alternatives[0]->set_allow_transform(false);
+ tad.alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
+ tad.alternatives[0]->notify_property_list_changed();
+ tad.alternatives_ids.append(0);
// Create and resize the tile.
- tiles.insert(p_atlas_coords, TileSetAtlasSource::TileAlternativesData());
+ tiles.insert(p_atlas_coords, tad);
tiles_ids.append(p_atlas_coords);
tiles_ids.sort();
- tiles[p_atlas_coords].size_in_atlas = p_size;
- tiles[p_atlas_coords].alternatives[0] = memnew(TileData);
- tiles[p_atlas_coords].alternatives[0]->set_tile_set(tile_set);
- tiles[p_atlas_coords].alternatives[0]->set_allow_transform(false);
- tiles[p_atlas_coords].alternatives[0]->connect("changed", callable_mp((Resource *)this, &TileSetAtlasSource::emit_changed));
- tiles[p_atlas_coords].alternatives[0]->notify_property_list_changed();
- tiles[p_atlas_coords].alternatives_ids.append(0);
-
- // Add all covered positions to the mapping cache
- for (int x = 0; x < p_size.x; x++) {
- for (int y = 0; y < p_size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache[coords] = p_atlas_coords;
- }
- }
+ _create_coords_mapping_cache(p_atlas_coords);
emit_signal(SNAME("changed"));
}
@@ -3292,14 +3365,7 @@ void TileSetAtlasSource::remove_tile(Vector2i p_atlas_coords) {
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
// Remove all covered positions from the mapping cache
- Size2i size = tiles[p_atlas_coords].size_in_atlas;
-
- for (int x = 0; x < size.x; x++) {
- for (int y = 0; y < size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache.erase(coords);
- }
- }
+ _clear_coords_mapping_cache(p_atlas_coords);
// Free tile data.
for (Map<int, TileData *>::Element *E_tile_data = tiles[p_atlas_coords].alternatives.front(); E_tile_data; E_tile_data = E_tile_data->next()) {
@@ -3326,6 +3392,118 @@ Vector2i TileSetAtlasSource::get_tile_at_coords(Vector2i p_atlas_coords) const {
return _coords_mapping_cache[p_atlas_coords];
}
+void TileSetAtlasSource::set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND(p_frame_columns < 0);
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, p_frame_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
+
+ _clear_coords_mapping_cache(p_atlas_coords);
+
+ tiles[p_atlas_coords].animation_columns = p_frame_columns;
+
+ _create_coords_mapping_cache(p_atlas_coords);
+
+ emit_signal(SNAME("changed"));
+}
+
+int TileSetAtlasSource::get_tile_animation_columns(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_columns;
+}
+
+void TileSetAtlasSource::set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND(p_separation.x < 0 || p_separation.y < 0);
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, p_separation, tad.animation_frames_durations.size(), p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
+
+ _clear_coords_mapping_cache(p_atlas_coords);
+
+ tiles[p_atlas_coords].animation_separation = p_separation;
+
+ _create_coords_mapping_cache(p_atlas_coords);
+
+ emit_signal(SNAME("changed"));
+}
+
+Vector2i TileSetAtlasSource::get_tile_animation_separation(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_separation;
+}
+
+void TileSetAtlasSource::set_tile_animation_speed(const Vector2i p_atlas_coords, real_t p_speed) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_COND(p_speed <= 0);
+
+ tiles[p_atlas_coords].animation_speed = p_speed;
+
+ emit_signal(SNAME("changed"));
+}
+
+real_t TileSetAtlasSource::get_tile_animation_speed(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1.0, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_speed;
+}
+
+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);
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ bool room_for_tile = has_room_for_tile(p_atlas_coords, tad.size_in_atlas, tad.animation_columns, tad.animation_separation, p_frames_count, p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, "Cannot set animation columns count, tiles are already present in the space the tile would cover.");
+
+ _clear_coords_mapping_cache(p_atlas_coords);
+
+ int old_size = tiles[p_atlas_coords].animation_frames_durations.size();
+ tiles[p_atlas_coords].animation_frames_durations.resize(p_frames_count);
+ for (int i = old_size; i < p_frames_count; i++) {
+ tiles[p_atlas_coords].animation_frames_durations[i] = 1.0;
+ }
+
+ _create_coords_mapping_cache(p_atlas_coords);
+
+ notify_property_list_changed();
+
+ emit_signal(SNAME("changed"));
+}
+
+int TileSetAtlasSource::get_tile_animation_frames_count(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ return tiles[p_atlas_coords].animation_frames_durations.size();
+}
+
+void TileSetAtlasSource::set_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index, real_t p_duration) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_INDEX(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size());
+ ERR_FAIL_COND(p_duration <= 0.0);
+
+ tiles[p_atlas_coords].animation_frames_durations[p_frame_index] = p_duration;
+
+ emit_signal(SNAME("changed"));
+}
+
+real_t TileSetAtlasSource::get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ ERR_FAIL_INDEX_V(p_frame_index, (int)tiles[p_atlas_coords].animation_frames_durations.size(), 0.0);
+ return tiles[p_atlas_coords].animation_frames_durations[p_frame_index];
+}
+
+real_t TileSetAtlasSource::get_tile_animation_total_duration(const Vector2i p_atlas_coords) const {
+ ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), 1, vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+
+ real_t sum = 0.0;
+ for (int frame = 0; frame < (int)tiles[p_atlas_coords].animation_frames_durations.size(); frame++) {
+ sum += tiles[p_atlas_coords].animation_frames_durations[frame];
+ }
+ return sum;
+}
+
Vector2i TileSetAtlasSource::get_tile_size_in_atlas(Vector2i p_atlas_coords) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Vector2i(-1, -1), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
@@ -3341,16 +3519,34 @@ Vector2i TileSetAtlasSource::get_tile_id(int p_index) const {
return tiles_ids[p_index];
}
-Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords) const {
+bool TileSetAtlasSource::has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile) const {
+ for (int frame = 0; frame < p_frames_count; frame++) {
+ Vector2i frame_coords = p_atlas_coords + (p_size + p_animation_separation) * ((p_animation_columns > 0) ? Vector2i(frame % p_animation_columns, frame / p_animation_columns) : Vector2i(frame, 0));
+ for (int x = 0; x < p_size.x; x++) {
+ for (int y = 0; y < p_size.y; y++) {
+ Vector2i coords = frame_coords + Vector2i(x, y);
+ if (_coords_mapping_cache.has(coords) && _coords_mapping_cache[coords] != p_ignored_tile) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+Rect2i TileSetAtlasSource::get_tile_texture_region(Vector2i p_atlas_coords, int p_frame) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), Rect2i(), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ ERR_FAIL_INDEX_V(p_frame, (int)tiles[p_atlas_coords].animation_frames_durations.size(), Rect2i());
+
+ const TileAlternativesData &tad = tiles[p_atlas_coords];
- Vector2i size_in_atlas = tiles[p_atlas_coords].size_in_atlas;
+ Vector2i size_in_atlas = tad.size_in_atlas;
Vector2 region_size = texture_region_size * size_in_atlas + separation * (size_in_atlas - Vector2i(1, 1));
- Vector2 origin = margins + (p_atlas_coords * (texture_region_size + separation));
+ Vector2i frame_coords = p_atlas_coords + (size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(p_frame % tad.animation_columns, p_frame / tad.animation_columns) : Vector2i(p_frame, 0));
+ Vector2 origin = margins + (frame_coords * (texture_region_size + separation));
return Rect2(origin, region_size);
- ;
}
Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const {
@@ -3369,56 +3565,23 @@ Vector2i TileSetAtlasSource::get_tile_effective_texture_offset(Vector2i p_atlas_
return effective_texture_offset;
}
-bool TileSetAtlasSource::can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) const {
- ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
-
- Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
- if (new_atlas_coords.x < 0 || new_atlas_coords.y < 0) {
- return false;
- }
-
- Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas;
- ERR_FAIL_COND_V(size.x <= 0 || size.y <= 0, false);
-
- Size2i grid_size = get_atlas_grid_size();
- if (new_atlas_coords.x + size.x > grid_size.x || new_atlas_coords.y + size.y > grid_size.y) {
- return false;
- }
-
- Rect2i new_rect = Rect2i(new_atlas_coords, size);
- // Check if the new tile can fit in the new rect.
- for (int x = new_rect.position.x; x < new_rect.get_end().x; x++) {
- for (int y = new_rect.position.y; y < new_rect.get_end().y; y++) {
- Vector2i coords = get_tile_at_coords(Vector2i(x, y));
- if (coords != p_atlas_coords && coords != TileSetSource::INVALID_ATLAS_COORDS) {
- return false;
- }
- }
- }
-
- return true;
-}
-
void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords, Vector2i p_new_size) {
- bool can_move = can_move_tile_in_atlas(p_atlas_coords, p_new_atlas_coords, p_new_size);
- ERR_FAIL_COND_MSG(!can_move, vformat("Cannot move tile at position %s with size %s. Tile already present.", p_new_atlas_coords, p_new_size));
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
// Compute the actual new rect from arguments.
Vector2i new_atlas_coords = (p_new_atlas_coords != INVALID_ATLAS_COORDS) ? p_new_atlas_coords : p_atlas_coords;
- Vector2i size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tiles[p_atlas_coords].size_in_atlas;
+ Vector2i new_size = (p_new_size != Vector2i(-1, -1)) ? p_new_size : tad.size_in_atlas;
- if (new_atlas_coords == p_atlas_coords && size == tiles[p_atlas_coords].size_in_atlas) {
+ if (new_atlas_coords == p_atlas_coords && new_size == tad.size_in_atlas) {
return;
}
- // Remove all covered positions from the mapping cache.
- Size2i old_size = tiles[p_atlas_coords].size_in_atlas;
- for (int x = 0; x < old_size.x; x++) {
- for (int y = 0; y < old_size.y; y++) {
- Vector2i coords = p_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache.erase(coords);
- }
- }
+ bool room_for_tile = has_room_for_tile(new_atlas_coords, new_size, tad.animation_columns, tad.animation_separation, tad.animation_frames_durations.size(), p_atlas_coords);
+ ERR_FAIL_COND_MSG(!room_for_tile, vformat("Cannot move tile at position %s with size %s. Tile already present.", new_atlas_coords, new_size));
+
+ _clear_coords_mapping_cache(p_atlas_coords);
// Move the tile and update its size.
if (new_atlas_coords != p_atlas_coords) {
@@ -3429,15 +3592,9 @@ void TileSetAtlasSource::move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_
tiles_ids.append(new_atlas_coords);
tiles_ids.sort();
}
- tiles[new_atlas_coords].size_in_atlas = size;
+ tiles[new_atlas_coords].size_in_atlas = new_size;
- // Add all covered positions to the mapping cache again.
- for (int x = 0; x < size.x; x++) {
- for (int y = 0; y < size.y; y++) {
- Vector2i coords = new_atlas_coords + Vector2i(x, y);
- _coords_mapping_cache[coords] = new_atlas_coords;
- }
- }
+ _create_coords_mapping_cache(new_atlas_coords);
emit_signal(SNAME("changed"));
}
@@ -3566,12 +3723,25 @@ void TileSetAtlasSource::_bind_methods() {
// Base tiles
ClassDB::bind_method(D_METHOD("create_tile", "atlas_coords", "size"), &TileSetAtlasSource::create_tile, DEFVAL(Vector2i(1, 1)));
ClassDB::bind_method(D_METHOD("remove_tile", "atlas_coords"), &TileSetAtlasSource::remove_tile); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
- ClassDB::bind_method(D_METHOD("can_move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::can_move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
ClassDB::bind_method(D_METHOD("move_tile_in_atlas", "atlas_coords", "new_atlas_coords", "new_size"), &TileSetAtlasSource::move_tile_in_atlas, DEFVAL(INVALID_ATLAS_COORDS), DEFVAL(Vector2i(-1, -1)));
ClassDB::bind_method(D_METHOD("get_tile_size_in_atlas", "atlas_coords"), &TileSetAtlasSource::get_tile_size_in_atlas);
+ ClassDB::bind_method(D_METHOD("has_room_for_tile", "atlas_coords", "size", "animation_columns", "animation_separation", "frames_count", "ignored_tile"), &TileSetAtlasSource::has_room_for_tile, DEFVAL(INVALID_ATLAS_COORDS));
+
ClassDB::bind_method(D_METHOD("get_tile_at_coords", "atlas_coords"), &TileSetAtlasSource::get_tile_at_coords);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_columns", "atlas_coords", "frame_columns"), &TileSetAtlasSource::set_tile_animation_columns);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_columns", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_columns);
+ ClassDB::bind_method(D_METHOD("set_tile_animation_separation", "atlas_coords", "separation"), &TileSetAtlasSource::set_tile_animation_separation);
+ 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_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);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_frame_duration", "atlas_coords", "frame_index"), &TileSetAtlasSource::get_tile_animation_frame_duration);
+ ClassDB::bind_method(D_METHOD("get_tile_animation_total_duration", "atlas_coords"), &TileSetAtlasSource::get_tile_animation_total_duration);
+
// Alternative tiles
ClassDB::bind_method(D_METHOD("create_alternative_tile", "atlas_coords", "alternative_id_override"), &TileSetAtlasSource::create_alternative_tile, DEFVAL(INVALID_TILE_ALTERNATIVE));
ClassDB::bind_method(D_METHOD("remove_alternative_tile", "atlas_coords", "alternative_tile"), &TileSetAtlasSource::remove_alternative_tile);
@@ -3584,7 +3754,7 @@ void TileSetAtlasSource::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_atlas_grid_size"), &TileSetAtlasSource::get_atlas_grid_size);
ClassDB::bind_method(D_METHOD("has_tiles_outside_texture"), &TileSetAtlasSource::has_tiles_outside_texture);
ClassDB::bind_method(D_METHOD("clear_tiles_outside_texture"), &TileSetAtlasSource::clear_tiles_outside_texture);
- ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords"), &TileSetAtlasSource::get_tile_texture_region);
+ ClassDB::bind_method(D_METHOD("get_tile_texture_region", "atlas_coords", "frame"), &TileSetAtlasSource::get_tile_texture_region, DEFVAL(0));
}
TileSetAtlasSource::~TileSetAtlasSource() {
@@ -3618,6 +3788,45 @@ void TileSetAtlasSource::_compute_next_alternative_id(const Vector2i p_atlas_coo
};
}
+void TileSetAtlasSource::_clear_coords_mapping_cache(Vector2i p_atlas_coords) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
+ Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
+ for (int x = 0; x < tad.size_in_atlas.x; x++) {
+ for (int y = 0; y < tad.size_in_atlas.y; y++) {
+ Vector2i coords = frame_coords + Vector2i(x, y);
+ if (!_coords_mapping_cache.has(coords)) {
+ WARN_PRINT(vformat("TileSetAtlasSource has no cached tile at position %s, the position cache might be corrupted.", coords));
+ } else {
+ if (_coords_mapping_cache[coords] != p_atlas_coords) {
+ WARN_PRINT(vformat("The position cache at position %s is pointing to a wrong tile, the position cache might be corrupted.", coords));
+ }
+ _coords_mapping_cache.erase(coords);
+ }
+ }
+ }
+ }
+}
+
+void TileSetAtlasSource::_create_coords_mapping_cache(Vector2i p_atlas_coords) {
+ ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", Vector2i(p_atlas_coords)));
+
+ TileAlternativesData &tad = tiles[p_atlas_coords];
+ for (int frame = 0; frame < (int)tad.animation_frames_durations.size(); frame++) {
+ Vector2i frame_coords = p_atlas_coords + (tad.size_in_atlas + tad.animation_separation) * ((tad.animation_columns > 0) ? Vector2i(frame % tad.animation_columns, frame / tad.animation_columns) : Vector2i(frame, 0));
+ for (int x = 0; x < tad.size_in_atlas.x; x++) {
+ for (int y = 0; y < tad.size_in_atlas.y; y++) {
+ Vector2i coords = frame_coords + Vector2i(x, y);
+ if (_coords_mapping_cache.has(coords)) {
+ WARN_PRINT(vformat("The cache already has a tile for position %s, the position cache might be corrupted.", coords));
+ }
+ _coords_mapping_cache[coords] = p_atlas_coords;
+ }
+ }
+ }
+}
+
/////////////////////////////// TileSetScenesCollectionSource //////////////////////////////////////
void TileSetScenesCollectionSource::_compute_next_alternative_id() {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index ba7207241a..46cb1fb36d 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -447,16 +447,23 @@ public:
class TileSetAtlasSource : public TileSetSource {
GDCLASS(TileSetAtlasSource, TileSetSource);
-public:
+private:
struct TileAlternativesData {
Vector2i size_in_atlas = Vector2i(1, 1);
Vector2i texture_offset;
+
+ // Animation
+ int animation_columns = 0;
+ Vector2i animation_separation;
+ real_t animation_speed = 1.0;
+ LocalVector<real_t> animation_frames_durations;
+
+ // Alternatives
Map<int, TileData *> alternatives;
Vector<int> alternatives_ids;
int next_alternative_id = 1;
};
-private:
Ref<Texture2D> texture;
Vector2i margins;
Vector2i separation;
@@ -471,6 +478,9 @@ private:
void _compute_next_alternative_id(const Vector2i p_atlas_coords);
+ void _create_coords_mapping_cache(Vector2i p_atlas_coords);
+ void _clear_coords_mapping_cache(Vector2i p_atlas_coords);
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -513,18 +523,32 @@ public:
Vector2i get_texture_region_size() const;
// Base tiles.
- void create_tile(const Vector2i p_atlas_coords, const Vector2i p_size = Vector2i(1, 1)); // Create a tile if it does not exists, or add alternative tile if it does.
- void remove_tile(Vector2i p_atlas_coords); // Remove a tile. If p_tile_key.alternative_tile if different from 0, remove the alternative
+ void create_tile(const Vector2i p_atlas_coords, const Vector2i p_size = Vector2i(1, 1));
+ void remove_tile(Vector2i p_atlas_coords);
virtual bool has_tile(Vector2i p_atlas_coords) const override;
- bool can_move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1)) const;
void move_tile_in_atlas(Vector2i p_atlas_coords, Vector2i p_new_atlas_coords = INVALID_ATLAS_COORDS, Vector2i p_new_size = Vector2i(-1, -1));
Vector2i get_tile_size_in_atlas(Vector2i p_atlas_coords) const;
virtual int get_tiles_count() const override;
virtual Vector2i get_tile_id(int p_index) const override;
+ bool has_room_for_tile(Vector2i p_atlas_coords, Vector2i p_size, int p_animation_columns, Vector2i p_animation_separation, int p_frames_count, Vector2i p_ignored_tile = INVALID_ATLAS_COORDS) const;
+
Vector2i get_tile_at_coords(Vector2i p_atlas_coords) const;
+ // Animation.
+ void set_tile_animation_columns(const Vector2i p_atlas_coords, int p_frame_columns);
+ int get_tile_animation_columns(const Vector2i p_atlas_coords) const;
+ void set_tile_animation_separation(const Vector2i p_atlas_coords, const Vector2i p_separation);
+ 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_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);
+ real_t get_tile_animation_frame_duration(const Vector2i p_atlas_coords, int p_frame_index) const;
+ real_t get_tile_animation_total_duration(const Vector2i p_atlas_coords) const;
+
// Alternative tiles.
int create_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_id_override = -1);
void remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile);
@@ -542,7 +566,7 @@ public:
Vector2i get_atlas_grid_size() const;
bool has_tiles_outside_texture();
void clear_tiles_outside_texture();
- Rect2i get_tile_texture_region(Vector2i p_atlas_coords) const;
+ Rect2i get_tile_texture_region(Vector2i p_atlas_coords, int p_frame = 0) const;
Vector2i get_tile_effective_texture_offset(Vector2i p_atlas_coords, int p_alternative_tile) const;
~TileSetAtlasSource();