summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/animated_sprite.cpp26
-rw-r--r--scene/2d/animated_sprite.h3
-rw-r--r--scene/2d/area_2d.cpp5
-rw-r--r--scene/2d/audio_stream_player_2d.cpp6
-rw-r--r--scene/2d/audio_stream_player_2d.h2
-rw-r--r--scene/2d/canvas_item.cpp6
-rw-r--r--scene/2d/canvas_item.h2
-rw-r--r--scene/2d/collision_object_2d.cpp7
-rw-r--r--scene/2d/light_2d.cpp2
-rw-r--r--scene/2d/light_occluder_2d.cpp61
-rw-r--r--scene/2d/light_occluder_2d.h9
-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.cpp2
-rw-r--r--scene/2d/tile_map.cpp30
-rw-r--r--scene/2d/tile_map.h2
17 files changed, 151 insertions, 26 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index f8384bd1e4..932db8f001 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -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()), DEFVAL(false));
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 2a225e5797..b322cfe8f1 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -261,8 +261,9 @@ void Area2D::_area_inout(int p_status, const RID &p_area, int p_instance, int p_
Map<ObjectID, AreaState>::Element *E = area_map.find(objid);
- ERR_FAIL_COND(!area_in && !E);
-
+ if (!area_in && !E) {
+ return; //likely removed from the tree
+ }
locked = true;
if (area_in) {
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 7b28ad2c12..faefd85968 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -473,6 +473,10 @@ bool AudioStreamPlayer2D::get_stream_paused() const {
return stream_paused;
}
+Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
+ return stream_playback;
+}
+
void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream);
@@ -512,6 +516,8 @@ void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer2D::set_stream_paused);
ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer2D::get_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback);
+
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer2D::_bus_layout_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index caf5c6ee49..0cd18fb93b 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -130,6 +130,8 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ Ref<AudioStreamPlayback> get_stream_playback();
+
AudioStreamPlayer2D();
~AudioStreamPlayer2D();
};
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index 2739f71543..78e98deb93 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -891,13 +891,13 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Colo
VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, p_antialiased);
}
-void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) {
+void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform, const Color &p_modulate) {
ERR_FAIL_COND(p_mesh.is_null());
RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), texture_rid, normal_map_rid);
+ VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid);
}
void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) {
@@ -1168,7 +1168,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "antialiased"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1)));
- ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()));
+ ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture>()));
ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index bf7cfa8e75..a020ab5029 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -317,7 +317,7 @@ public:
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
- void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);
+ void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);
void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
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/light_2d.cpp b/scene/2d/light_2d.cpp
index d1fce74085..6b12db9e44 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -438,7 +438,7 @@ void Light2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_energy", "get_energy");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix,Mask"), "set_mode", "get_mode");
ADD_GROUP("Range", "range_");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "range_height", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "range_height", PROPERTY_HINT_RANGE, "-2048,2048,0.1,or_lesser,or_greater"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_min", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_min", "get_z_range_min");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_max", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_max", "get_z_range_max");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_layer_min", PROPERTY_HINT_RANGE, "-512,512,1"), "set_layer_range_min", "get_layer_range_min");
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 5334caed67..3a3f90ac4b 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -32,9 +32,59 @@
#include "core/engine.h"
+#define LINE_GRAB_WIDTH 8
+Rect2 OccluderPolygon2D::_edit_get_rect() const {
+
+ if (rect_cache_dirty) {
+ if (closed) {
+ PoolVector<Vector2>::Read r = polygon.read();
+ item_rect = Rect2();
+ for (int i = 0; i < polygon.size(); i++) {
+ Vector2 pos = r[i];
+ if (i == 0)
+ item_rect.position = pos;
+ else
+ item_rect.expand_to(pos);
+ }
+ rect_cache_dirty = false;
+ } else {
+ if (polygon.size() == 0) {
+ item_rect = Rect2();
+ } else {
+ Vector2 d = Vector2(LINE_GRAB_WIDTH, LINE_GRAB_WIDTH);
+ item_rect = Rect2(polygon[0] - d, 2 * d);
+ for (int i = 1; i < polygon.size(); i++) {
+ item_rect.expand_to(polygon[i] - d);
+ item_rect.expand_to(polygon[i] + d);
+ }
+ }
+ }
+ }
+
+ return item_rect;
+}
+
+bool OccluderPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (closed) {
+ return Geometry::is_point_in_polygon(p_point, Variant(polygon));
+ } else {
+ const real_t d = LINE_GRAB_WIDTH / 2 + p_tolerance;
+ PoolVector<Vector2>::Read points = polygon.read();
+ for (int i = 0; i < polygon.size() - 1; i++) {
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]);
+ if (p.distance_to(p_point) <= d)
+ return true;
+ }
+
+ return false;
+ }
+}
+
void OccluderPolygon2D::set_polygon(const PoolVector<Vector2> &p_polygon) {
polygon = p_polygon;
+ rect_cache_dirty = true;
VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, p_polygon, closed);
emit_changed();
}
@@ -100,6 +150,7 @@ OccluderPolygon2D::OccluderPolygon2D() {
occ_polygon = VS::get_singleton()->canvas_occluder_polygon_create();
closed = true;
cull = CULL_DISABLED;
+ rect_cache_dirty = true;
}
OccluderPolygon2D::~OccluderPolygon2D() {
@@ -164,6 +215,16 @@ void LightOccluder2D::_notification(int p_what) {
}
}
+Rect2 LightOccluder2D::_edit_get_rect() const {
+
+ return occluder_polygon.is_valid() ? occluder_polygon->_edit_get_rect() : Rect2();
+}
+
+bool LightOccluder2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return occluder_polygon.is_valid() ? occluder_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+}
+
void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon) {
#ifdef DEBUG_ENABLED
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index 498d65d764..7931cd0b30 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -50,10 +50,16 @@ private:
bool closed;
CullMode cull;
+ mutable Rect2 item_rect;
+ mutable bool rect_cache_dirty;
+
protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_polygon(const PoolVector<Vector2> &p_polygon);
PoolVector<Vector2> get_polygon() const;
@@ -85,6 +91,9 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon);
Ref<OccluderPolygon2D> get_occluder_polygon() const;
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 fec861ad2f..4097006b33 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -95,7 +95,7 @@ void Path2D::_notification(int p_what) {
return;
}
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
const float line_width = 2 * EDSCALE;
#else
const float line_width = 2;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 46b4f0a5d2..885c9ea8bc 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1392,18 +1392,21 @@ 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: {}
+ default: {
+ }
}
}
return ret;
@@ -1463,12 +1466,23 @@ 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;
- default: {}
+ case HALF_OFFSET_NEGATIVE_Y: {
+ if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) {
+ ret.y += 0.5;
+ }
+ } break;
+ default: {
+ }
}
// Account for precision errors on the border (GH-23250).
@@ -1678,7 +1692,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");
@@ -1704,6 +1718,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 {