summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/animated_sprite.cpp28
-rw-r--r--scene/2d/animated_sprite.h3
-rw-r--r--scene/2d/area_2d.cpp4
-rw-r--r--scene/2d/collision_object_2d.cpp7
-rw-r--r--scene/2d/collision_polygon_2d.cpp35
-rw-r--r--scene/2d/cpu_particles_2d.cpp86
-rw-r--r--scene/2d/cpu_particles_2d.h3
-rw-r--r--scene/2d/line_2d.cpp10
-rw-r--r--scene/2d/line_2d.h2
-rw-r--r--scene/2d/parallax_background.cpp2
-rw-r--r--scene/2d/path_2d.cpp3
-rw-r--r--scene/2d/physics_body_2d.cpp20
-rw-r--r--scene/2d/polygon_2d.cpp4
-rw-r--r--scene/2d/sprite.cpp2
-rw-r--r--scene/2d/tile_map.cpp51
-rw-r--r--scene/2d/tile_map.h2
16 files changed, 146 insertions, 116 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 3d7ff5f1fd..7a50574be2 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -93,7 +93,7 @@ Rect2 AnimatedSprite::_get_rect() const {
Point2 ofs = offset;
if (centered)
- ofs -= s / 2;
+ ofs -= Size2(s) / 2;
if (s == Size2(0, 0))
s = Size2(1, 1);
@@ -393,19 +393,30 @@ void AnimatedSprite::_notification(int p_what) {
timeout = _get_frame_duration();
int fc = frames->get_frame_count(animation);
- if (frame >= fc - 1) {
+ if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) {
if (frames->get_animation_loop(animation)) {
- frame = 0;
+ if (backwards)
+ frame = fc - 1;
+ else
+ frame = 0;
+
emit_signal(SceneStringNames::get_singleton()->animation_finished);
} else {
- frame = fc - 1;
+ if (backwards)
+ frame = 0;
+ else
+ frame = fc - 1;
+
if (!is_over) {
is_over = true;
emit_signal(SceneStringNames::get_singleton()->animation_finished);
}
}
} else {
- frame++;
+ if (backwards)
+ frame--;
+ else
+ frame++;
}
update();
@@ -594,10 +605,12 @@ bool AnimatedSprite::_is_playing() const {
return playing;
}
-void AnimatedSprite::play(const StringName &p_animation) {
+void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards) {
if (p_animation)
set_animation(p_animation);
+
+ backwards = p_backwards;
_set_playing(true);
}
@@ -666,7 +679,7 @@ void AnimatedSprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite::_set_playing);
ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite::_is_playing);
- ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite::play, DEFVAL(StringName()));
+ ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite::play, DEFVAL(StringName()));
ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite::stop);
ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite::is_playing);
@@ -713,6 +726,7 @@ AnimatedSprite::AnimatedSprite() {
frame = 0;
speed_scale = 1.0f;
playing = false;
+ backwards = false;
animation = "default";
timeout = 0;
is_over = false;
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
index 8753f88799..2cc372bd93 100644
--- a/scene/2d/animated_sprite.h
+++ b/scene/2d/animated_sprite.h
@@ -128,6 +128,7 @@ class AnimatedSprite : public Node2D {
Ref<SpriteFrames> frames;
bool playing;
+ bool backwards;
StringName animation;
int frame;
float speed_scale;
@@ -169,7 +170,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName());
+ void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
void stop();
bool is_playing() const;
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 63c4758a34..2a225e5797 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -426,10 +426,10 @@ bool Area2D::is_monitoring() const {
void Area2D::set_monitorable(bool p_enable) {
- if (locked || Physics2DServer::get_singleton()->is_flushing_queries()) {
+ if (locked || (is_inside_tree() && Physics2DServer::get_singleton()->is_flushing_queries())) {
ERR_EXPLAIN("Function blocked during in/out signal. Use set_deferred(\"monitorable\",true/false)");
+ ERR_FAIL();
}
- ERR_FAIL_COND(locked || Physics2DServer::get_singleton()->is_flushing_queries());
if (p_enable == monitorable)
return;
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index d54070df8d..f43d97eb2a 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "collision_object_2d.h"
+
#include "scene/scene_string_names.h"
#include "servers/physics_2d_server.h"
@@ -56,7 +57,7 @@ void CollisionObject2D::_notification(int p_what) {
_update_pickable();
//get space
- }
+ } break;
case NOTIFICATION_ENTER_CANVAS: {
@@ -64,7 +65,7 @@ void CollisionObject2D::_notification(int p_what) {
Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
else
Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id());
- }
+ } break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -101,7 +102,7 @@ void CollisionObject2D::_notification(int p_what) {
Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, 0);
else
Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, 0);
- }
+ } break;
}
}
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 5edd49b3a3..ef7644fcab 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -78,40 +78,7 @@ void CollisionPolygon2D::_build_polygon() {
}
Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
-
- Vector<Vector<Vector2> > decomp;
- List<TriangulatorPoly> in_poly, out_poly;
-
- TriangulatorPoly inp;
- inp.Init(polygon.size());
- for (int i = 0; i < polygon.size(); i++) {
- inp.GetPoint(i) = polygon[i];
- }
- inp.SetOrientation(TRIANGULATOR_CCW);
- in_poly.push_back(inp);
- TriangulatorPartition tpart;
- if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed!
- ERR_PRINT("Convex decomposing failed!");
- return decomp;
- }
-
- decomp.resize(out_poly.size());
- int idx = 0;
-
- for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
-
- TriangulatorPoly &tp = I->get();
-
- decomp.write[idx].resize(tp.GetNumPoints());
-
- for (int i = 0; i < tp.GetNumPoints(); i++) {
-
- decomp.write[idx].write[i] = tp.GetPoint(i);
- }
-
- idx++;
- }
-
+ Vector<Vector<Vector2> > decomp = Geometry::decompose_polygon_in_convex(polygon);
return decomp;
}
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index c50a8d4a1a..721b52edaa 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -37,20 +37,8 @@
void CPUParticles2D::set_emitting(bool p_emitting) {
emitting = p_emitting;
- if (!is_processing_internal()) {
+ if (emitting)
set_process_internal(true);
- if (is_inside_tree()) {
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
-
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
- }
- }
}
void CPUParticles2D::set_amount(int p_amount) {
@@ -365,7 +353,8 @@ void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv
} break;
case PARAM_ANIM_OFFSET: {
} break;
- default: {}
+ default: {
+ }
}
}
Ref<Curve> CPUParticles2D::get_param_curve(Parameter p_param) const {
@@ -586,7 +575,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
if (restart_time >= prev_time && restart_time < time) {
restart = true;
if (fractional_delta) {
- local_delta = (time - restart_time) * lifetime;
+ local_delta = time - restart_time;
}
}
@@ -594,13 +583,13 @@ void CPUParticles2D::_particles_process(float p_delta) {
if (restart_time >= prev_time) {
restart = true;
if (fractional_delta) {
- local_delta = (lifetime - restart_time + time) * lifetime;
+ local_delta = lifetime - restart_time + time;
}
} else if (restart_time < time) {
restart = true;
if (fractional_delta) {
- local_delta = (time - restart_time) * lifetime;
+ local_delta = time - restart_time;
}
}
}
@@ -941,6 +930,26 @@ void CPUParticles2D::_update_particle_data_buffer() {
#endif
}
+void CPUParticles2D::_set_redraw(bool p_redraw) {
+ if (redraw == p_redraw)
+ return;
+ redraw = p_redraw;
+#ifndef NO_THREADS
+ update_mutex->lock();
+#endif
+ if (redraw) {
+ VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
+ } else {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
+ }
+#ifndef NO_THREADS
+ update_mutex->unlock();
+#endif
+ update(); // redraw to update render list
+}
+
void CPUParticles2D::_update_render_thread() {
#ifndef NO_THREADS
@@ -957,38 +966,19 @@ void CPUParticles2D::_update_render_thread() {
void CPUParticles2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- if (is_processing_internal()) {
-
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true);
-
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
- }
+ set_process_internal(emitting);
}
if (p_what == NOTIFICATION_EXIT_TREE) {
- if (is_processing_internal()) {
-
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
- }
+ _set_redraw(false);
}
if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) {
}
if (p_what == NOTIFICATION_DRAW) {
+ if (!redraw)
+ return; // dont add to render list
RID texrid;
if (texture.is_valid()) {
@@ -1005,26 +995,20 @@ void CPUParticles2D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- if (particles.size() == 0 || !is_visible_in_tree())
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
return;
+ }
float delta = get_process_delta_time();
if (emitting) {
-
inactive_time = 0;
} else {
inactive_time += delta;
if (inactive_time > lifetime * 1.2) {
set_process_internal(false);
-#ifndef NO_THREADS
- update_mutex->lock();
-#endif
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
- VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
+ _set_redraw(false);
-#ifndef NO_THREADS
- update_mutex->unlock();
-#endif
//reset variables
time = 0;
inactive_time = 0;
@@ -1033,6 +1017,7 @@ void CPUParticles2D::_notification(int p_what) {
return;
}
}
+ _set_redraw(true);
if (time == 0 && pre_process_time > 0.0) {
@@ -1354,6 +1339,7 @@ CPUParticles2D::CPUParticles2D() {
inactive_time = 0;
frame_remainder = 0;
cycle = 0;
+ redraw = false;
mesh = VisualServer::get_singleton()->mesh_create();
multimesh = VisualServer::get_singleton()->multimesh_create();
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index b1adf62980..23d2586331 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -103,6 +103,7 @@ private:
float inactive_time;
float frame_remainder;
int cycle;
+ bool redraw;
RID mesh;
RID multimesh;
@@ -179,6 +180,8 @@ private:
void _update_mesh_texture();
+ void _set_redraw(bool p_redraw);
+
protected:
static void _bind_methods();
void _notification(int p_what);
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 105eb82afb..73692e0535 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -112,6 +112,14 @@ int Line2D::get_point_count() const {
return _points.size();
}
+void Line2D::clear_points() {
+ int count = _points.size();
+ if (count > 0) {
+ _points.resize(0);
+ update();
+ }
+}
+
void Line2D::add_point(Vector2 pos) {
_points.append(pos);
update();
@@ -313,6 +321,8 @@ void Line2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_point", "position"), &Line2D::add_point);
ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point);
+ ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points);
+
ClassDB::bind_method(D_METHOD("set_width", "width"), &Line2D::set_width);
ClassDB::bind_method(D_METHOD("get_width"), &Line2D::get_width);
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index 5bbd38e460..32befab2d3 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -70,6 +70,8 @@ public:
int get_point_count() const;
+ void clear_points();
+
void add_point(Vector2 pos);
void remove_point(int i);
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index 96e13396c5..4ead1bbd1e 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -207,7 +207,7 @@ void ParallaxBackground::_bind_methods() {
ParallaxBackground::ParallaxBackground() {
scale = 1.0;
- set_layer(-1); //behind all by default
+ set_layer(-100); //behind all by default
base_scale = Vector2(1, 1);
ignore_camera_zoom = false;
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 271e132002..fec861ad2f 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -170,6 +170,9 @@ void PathFollow2D::_update_transform() {
return;
float path_length = c->get_baked_length();
+ if (path_length == 0) {
+ return;
+ }
float bounded_offset = offset;
if (loop)
bounded_offset = Math::fposmod(bounded_offset, path_length);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 44b81dc0cc..690f1d4b4a 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -199,7 +199,7 @@ real_t StaticBody2D::get_constant_angular_velocity() const {
#ifndef DISABLE_DEPRECATED
void StaticBody2D::set_friction(real_t p_friction) {
- if (p_friction == 1.0) { // default value, don't create an override for that
+ if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that
return;
}
@@ -229,7 +229,7 @@ real_t StaticBody2D::get_friction() const {
void StaticBody2D::set_bounce(real_t p_bounce) {
- if (p_bounce == 0.0) { // default value, don't create an override for that
+ if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that
return;
}
@@ -626,7 +626,7 @@ real_t RigidBody2D::get_weight() const {
#ifndef DISABLE_DEPRECATED
void RigidBody2D::set_friction(real_t p_friction) {
- if (p_friction == 1.0) { // default value, don't create an override for that
+ if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that
return;
}
@@ -655,7 +655,7 @@ real_t RigidBody2D::get_friction() const {
void RigidBody2D::set_bounce(real_t p_bounce) {
- if (p_bounce == 0.0) { // default value, don't create an override for that
+ if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that
return;
}
@@ -1198,6 +1198,9 @@ bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision
bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) {
+ if (sync_to_physics) {
+ ERR_PRINT("Functions move_and_slide and move_and_collide do not work together with 'sync to physics' option. Please read the documentation.");
+ }
Transform2D gt = get_global_transform();
Physics2DServer::MotionResult result;
bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes);
@@ -1309,9 +1312,6 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
motion = motion.slide(n);
lv = lv.slide(n);
}
-
- if (p_stop_on_slope)
- break;
}
if (!found_collision) {
@@ -1344,6 +1344,12 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci
on_floor = true;
on_floor_body = col.collider_rid;
floor_velocity = col.collider_vel;
+ if (p_stop_on_slope) {
+ // move and collide may stray the object a bit because of pre un-stucking,
+ // so only ensure that motion happens on floor direction in this case.
+ col.travel = p_floor_direction * p_floor_direction.dot(col.travel);
+ }
+
} else {
apply = false;
}
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 1c58073f1d..f6f1bad581 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -307,7 +307,9 @@ void Polygon2D::_notification(int p_what) {
if (invert || polygons.size() == 0) {
Vector<int> indices = Geometry::triangulate_polygon(points);
- VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
+ if (indices.size()) {
+ VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
+ }
} else {
//draw individual polygons
Vector<int> total_indices;
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index ba103a8bf0..a8c7622828 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -363,7 +363,7 @@ Rect2 Sprite::get_rect() const {
Point2 ofs = offset;
if (centered)
- ofs -= s / 2;
+ ofs -= Size2(s) / 2;
if (s == Size2(0, 0))
s = Size2(1, 1);
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 91e4f061cb..3562011bc2 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -479,10 +479,28 @@ void TileMap::update_dirty_quadrants() {
vs->canvas_item_add_set_transform(debug_canvas_item, xform);
shape->draw(debug_canvas_item, debug_collision_color);
}
- ps->body_add_shape(q.body, shape->get_rid(), xform);
- ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
- ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin);
- shape_idx++;
+
+ if (shape->has_meta("decomposed")) {
+ Array _shapes = shape->get_meta("decomposed");
+ for (int k = 0; k < _shapes.size(); k++) {
+ Ref<ConvexPolygonShape2D> convex = _shapes[k];
+ if (convex.is_valid()) {
+ ps->body_add_shape(q.body, convex->get_rid(), xform);
+ ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
+ ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin);
+ shape_idx++;
+#ifdef DEBUG_ENABLED
+ } else {
+ print_error("The TileSet asigned to the TileMap " + get_name() + " has an invalid convex shape.");
+#endif
+ }
+ }
+ } else {
+ ps->body_add_shape(q.body, shape->get_rid(), xform);
+ ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
+ ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[j].one_way_collision, shapes[j].one_way_collision_margin);
+ shape_idx++;
+ }
}
}
}
@@ -755,6 +773,7 @@ void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_
else
_make_quadrant_dirty(Q);
+ used_size_cache_dirty = true;
return;
}
@@ -1373,15 +1392,17 @@ Vector2 TileMap::_map_to_world(int p_x, int p_y, bool p_ignore_ofs) const {
if (!p_ignore_ofs) {
switch (half_offset) {
- case HALF_OFFSET_X: {
+ case HALF_OFFSET_X:
+ case HALF_OFFSET_NEGATIVE_X: {
if (ABS(p_y) & 1) {
- ret += get_cell_transform()[0] * 0.5;
+ ret += get_cell_transform()[0] * (half_offset == HALF_OFFSET_X ? 0.5 : -0.5);
}
} break;
- case HALF_OFFSET_Y: {
+ case HALF_OFFSET_Y:
+ case HALF_OFFSET_NEGATIVE_Y: {
if (ABS(p_x) & 1) {
- ret += get_cell_transform()[1] * 0.5;
+ ret += get_cell_transform()[1] * (half_offset == HALF_OFFSET_Y ? 0.5 : -0.5);
}
} break;
default: {}
@@ -1444,11 +1465,21 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
ret.x -= 0.5;
}
} break;
+ case HALF_OFFSET_NEGATIVE_X: {
+ if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) {
+ ret.x += 0.5;
+ }
+ } break;
case HALF_OFFSET_Y: {
if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) {
ret.y -= 0.5;
}
} break;
+ case HALF_OFFSET_NEGATIVE_Y: {
+ if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) {
+ ret.y += 0.5;
+ }
+ } break;
default: {}
}
@@ -1659,7 +1690,7 @@ void TileMap::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size", PROPERTY_HINT_RANGE, "1,8192,1"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "cell_custom_transform"), "set_custom_transform", "get_custom_transform");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled"), "set_half_offset", "get_half_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled,Offset Negative X,Offset Negative Y"), "set_half_offset", "get_half_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_tile_origin", PROPERTY_HINT_ENUM, "Top Left,Center,Bottom Left"), "set_tile_origin", "get_tile_origin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_y_sort"), "set_y_sort_mode", "is_y_sort_mode_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_clip_uv"), "set_clip_uv", "get_clip_uv");
@@ -1685,6 +1716,8 @@ void TileMap::_bind_methods() {
BIND_ENUM_CONSTANT(HALF_OFFSET_X);
BIND_ENUM_CONSTANT(HALF_OFFSET_Y);
BIND_ENUM_CONSTANT(HALF_OFFSET_DISABLED);
+ BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_X);
+ BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_Y);
BIND_ENUM_CONSTANT(TILE_ORIGIN_TOP_LEFT);
BIND_ENUM_CONSTANT(TILE_ORIGIN_CENTER);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index e450e1e256..6a1467aa48 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -52,6 +52,8 @@ public:
HALF_OFFSET_X,
HALF_OFFSET_Y,
HALF_OFFSET_DISABLED,
+ HALF_OFFSET_NEGATIVE_X,
+ HALF_OFFSET_NEGATIVE_Y,
};
enum TileOrigin {