diff options
Diffstat (limited to 'scene/2d')
33 files changed, 636 insertions, 243 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 25ad6bd5c9..b7ace804ef 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -69,10 +69,7 @@ bool AnimatedSprite::_edit_use_rect() const { Ref<Texture> t; if (animation) t = frames->get_frame(animation, frame); - if (t.is_null()) - return false; - - return true; + return t.is_valid(); } Rect2 AnimatedSprite::get_anchorable_rect() const { @@ -646,6 +643,7 @@ void AnimatedSprite::_reset_timeout() { void AnimatedSprite::set_animation(const StringName &p_animation) { ERR_EXPLAIN(vformat("There is no animation with name '%s'.", p_animation)); + ERR_FAIL_COND(frames == NULL); ERR_FAIL_COND(frames->get_animation_names().find(p_animation) == -1); if (animation == p_animation) diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index b322cfe8f1..b701e84a9c 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -657,10 +657,10 @@ void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_body_inout"), &Area2D::_body_inout); ClassDB::bind_method(D_METHOD("_area_inout"), &Area2D::_area_inout); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsBody2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsBody2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsBody2D"))); - ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsBody2D"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); + ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 73f583111b..932af469d0 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -457,8 +457,8 @@ void AudioStreamPlayer2D::set_stream_paused(bool p_pause) { if (p_pause != stream_paused) { stream_paused = p_pause; - stream_paused_fade_in = p_pause ? false : true; - stream_paused_fade_out = p_pause ? true : false; + stream_paused_fade_in = !p_pause; + stream_paused_fade_out = p_pause; } } diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index e9cdfa2303..ffa3d4edb4 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -37,7 +37,7 @@ class AudioStreamPlayer2D : public Node2D { - GDCLASS(AudioStreamPlayer2D, Node2D) + GDCLASS(AudioStreamPlayer2D, Node2D); private: enum { diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 11846654c5..a0d74dd283 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -29,10 +29,11 @@ /*************************************************************************/ #include "camera_2d.h" + +#include "core/engine.h" #include "core/math/math_funcs.h" #include "scene/scene_string_names.h" #include "servers/visual_server.h" -#include <editor/editor_node.h> void Camera2D::_update_scroll() { @@ -44,15 +45,16 @@ void Camera2D::_update_scroll() { return; } + if (!viewport) + return; + if (current) { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); Transform2D xform = get_camera_transform(); - if (viewport) { - viewport->set_canvas_transform(xform); - } + viewport->set_canvas_transform(xform); Size2 screen_size = viewport->get_visible_rect().size; Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5) : Point2()); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index a020ab5029..2604eb04e4 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -46,7 +46,7 @@ class StyleBox; class CanvasItemMaterial : public Material { - GDCLASS(CanvasItemMaterial, Material) + GDCLASS(CanvasItemMaterial, Material); public: enum BlendMode { @@ -143,7 +143,7 @@ public: void set_particles_anim_v_frames(int p_frames); int get_particles_anim_v_frames() const; - void set_particles_anim_loop(bool p_frames); + void set_particles_anim_loop(bool p_loop); bool get_particles_anim_loop() const; static void init_shaders(); diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index bd7bb97b03..009d664462 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -70,7 +70,7 @@ void CanvasModulate::_bind_methods() { void CanvasModulate::set_color(const Color &p_color) { color = p_color; - if (is_inside_tree()) { + if (is_visible_in_tree()) { VS::get_singleton()->canvas_set_modulate(get_canvas(), color); } } diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 375375285d..36c88e395a 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -218,12 +218,13 @@ void CollisionObject2D::shape_owner_set_transform(uint32_t p_owner, const Transf ERR_FAIL_COND(!shapes.has(p_owner)); ShapeData &sd = shapes[p_owner]; + sd.xform = p_transform; for (int i = 0; i < sd.shapes.size(); i++) { if (area) { - Physics2DServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, p_transform); + Physics2DServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, sd.xform); } else { - Physics2DServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform); + Physics2DServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, sd.xform); } } } @@ -387,7 +388,7 @@ String CollisionObject2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (shapes.empty()) { - if (warning == String()) { + if (!warning.empty()) { warning += "\n"; } warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 8aa3330f37..4e7d01c8e6 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -36,7 +36,7 @@ class CollisionObject2D : public Node2D { - GDCLASS(CollisionObject2D, Node2D) + GDCLASS(CollisionObject2D, Node2D); bool area; RID rid; diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index e913b4a866..26c61f47bd 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -38,7 +38,7 @@ class CollisionObject2D; class CollisionShape2D : public Node2D { - GDCLASS(CollisionShape2D, Node2D) + GDCLASS(CollisionShape2D, Node2D); Ref<Shape2D> shape; Rect2 rect; uint32_t owner_id; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 721b52edaa..75315bfc6e 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -29,8 +29,9 @@ /*************************************************************************/ #include "cpu_particles_2d.h" -#include "particles_2d.h" + #include "scene/2d/canvas_item.h" +#include "scene/2d/particles_2d.h" #include "scene/resources/particles_material.h" #include "servers/visual_server.h" @@ -85,7 +86,9 @@ void CPUParticles2D::set_randomness_ratio(float p_ratio) { void CPUParticles2D::set_use_local_coordinates(bool p_enable) { local_coords = p_enable; + set_notify_transform(!p_enable); } + void CPUParticles2D::set_speed_scale(float p_scale) { speed_scale = p_scale; @@ -247,6 +250,8 @@ void CPUParticles2D::restart() { frame_remainder = 0; cycle = 0; + set_emitting(true); + { int pc = particles.size(); PoolVector<Particle>::Write w = particles.write(); @@ -324,9 +329,9 @@ void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv case PARAM_ANGULAR_VELOCITY: { _adjust_curve_range(p_curve, -360, 360); } break; - /*case PARAM_ORBIT_VELOCITY: { + case PARAM_ORBIT_VELOCITY: { _adjust_curve_range(p_curve, -500, 500); - } break;*/ + } break; case PARAM_LINEAR_ACCEL: { _adjust_curve_range(p_curve, -200, 200); } break; @@ -466,7 +471,7 @@ void CPUParticles2D::_validate_property(PropertyInfo &property) const { property.usage = 0; } - if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_CIRCLE) { + if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { property.usage = 0; } @@ -489,12 +494,6 @@ void CPUParticles2D::_validate_property(PropertyInfo &property) const { if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { property.usage = 0; } - - /* - if (property.name.begins_with("orbit_") && !flags[FLAG_DISABLE_Z]) { - property.usage = 0; - } - */ } static uint32_t idhash(uint32_t x) { @@ -533,7 +532,8 @@ void CPUParticles2D::_particles_process(float p_delta) { time = Math::fmod(time, lifetime); cycle++; if (one_shot && cycle > 0) { - emitting = false; + set_emitting(false); + _change_notify(); } } @@ -545,6 +545,8 @@ void CPUParticles2D::_particles_process(float p_delta) { velocity_xform[2] = Vector2(); } + float system_phase = time / lifetime; + for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -552,21 +554,26 @@ void CPUParticles2D::_particles_process(float p_delta) { if (!emitting && !p.active) continue; - float restart_time = (float(i) / float(pcount)) * lifetime; float local_delta = p_delta; + // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. + // While we use time in tests later on, for randomness we use the phase as done in the + // original shader code, and we later multiply by lifetime to get the time. + float restart_phase = float(i) / float(pcount); + if (randomness_ratio > 0.0) { uint32_t seed = cycle; - if (restart_time >= time) { + if (restart_phase >= system_phase) { seed -= uint32_t(1); } seed *= uint32_t(pcount); seed += uint32_t(i); float random = float(idhash(seed) % uint32_t(65536)) / 65536.0; - restart_time += randomness_ratio * random * 1.0 / float(pcount); + restart_phase += randomness_ratio * random * 1.0 / float(pcount); } - restart_time *= (1.0 - explosiveness_ratio); + restart_phase *= (1.0 - explosiveness_ratio); + float restart_time = restart_phase * lifetime; bool restart = false; if (time > prev_time) { @@ -643,8 +650,9 @@ void CPUParticles2D::_particles_process(float p_delta) { case EMISSION_SHAPE_POINT: { //do none } break; - case EMISSION_SHAPE_CIRCLE: { - p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius; + case EMISSION_SHAPE_SPHERE: { + Vector3 sphere_shape = Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0).normalized() * emission_sphere_radius; + p.transform[2] = Vector2(sphere_shape.x, sphere_shape.y); } break; case EMISSION_SHAPE_RECTANGLE: { p.transform[2] = Vector2(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * emission_rect_extents; @@ -688,16 +696,12 @@ void CPUParticles2D::_particles_process(float p_delta) { if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]); } - /* - float tex_orbit_velocity = 0.0; - - if (flags[FLAG_DISABLE_Z]) { - if (curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_INITIAL_ORBIT_VELOCITY]->interpolate(p.custom[1]); - } + float tex_orbit_velocity = 0.0; + if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]); } -*/ + float tex_angular_velocity = 0.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]); @@ -748,22 +752,19 @@ void CPUParticles2D::_particles_process(float p_delta) { force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2(); //apply tangential acceleration; Vector2 yx = Vector2(diff.y, diff.x); - force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2(); + force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2(); //apply attractor forces p.velocity += force * local_delta; //orbit velocity -#if 0 - if (flags[FLAG_DISABLE_Z]) { - - float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random); - if (orbit_amount != 0.0) { - float ang = orbit_amount * DELTA * pi * 2.0; - mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang))); - TRANSFORM[3].xy -= diff.xy; - TRANSFORM[3].xy += rot * diff.xy; - } + float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); + if (orbit_amount != 0.0) { + float ang = orbit_amount * local_delta * Math_PI * 2.0; + // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, + // but we use -ang here to reproduce its behavior. + Transform2D rot = Transform2D(-ang, Vector2()); + p.transform[2] -= diff; + p.transform[2] += rot.basis_xform(diff); } -#endif if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { p.velocity = p.velocity.normalized() * tex_linear_velocity; } @@ -865,11 +866,6 @@ void CPUParticles2D::_update_particle_data_buffer() { PoolVector<Particle>::Read r = particles.read(); float *ptr = w.ptr(); - Transform2D un_transform; - if (!local_coords) { - un_transform = get_global_transform().affine_inverse(); - } - if (draw_order != DRAW_ORDER_INDEX) { ow = particle_order.write(); order = ow.ptr(); @@ -891,7 +887,7 @@ void CPUParticles2D::_update_particle_data_buffer() { Transform2D t = r[idx].transform; if (!local_coords) { - t = un_transform * t; + t = inv_emission_transform * t; } if (r[idx].active) { @@ -978,7 +974,7 @@ void CPUParticles2D::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { if (!redraw) - return; // dont add to render list + return; // don't add to render list RID texrid; if (texture.is_valid()) { @@ -1060,6 +1056,42 @@ void CPUParticles2D::_notification(int p_what) { _update_particle_data_buffer(); } + + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + + inv_emission_transform = get_global_transform().affine_inverse(); + + if (!local_coords) { + + int pc = particles.size(); + + PoolVector<float>::Write w = particle_data.write(); + PoolVector<Particle>::Read r = particles.read(); + float *ptr = w.ptr(); + + for (int i = 0; i < pc; i++) { + + Transform2D t = inv_emission_transform * r[i].transform; + + if (r[i].active) { + + ptr[0] = t.elements[0][0]; + ptr[1] = t.elements[1][0]; + ptr[2] = 0; + ptr[3] = t.elements[2][0]; + ptr[4] = t.elements[0][1]; + ptr[5] = t.elements[1][1]; + ptr[6] = 0; + ptr[7] = t.elements[2][1]; + + } else { + zeromem(ptr, sizeof(float) * 8); + } + + ptr += 13; + } + } + } } void CPUParticles2D::convert_from_particles(Node *p_particles) { @@ -1174,15 +1206,16 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); ADD_GROUP("Drawing", ""); + // No visibility_rect property contrarily to Particles2D, it's updated automatically. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); @@ -1263,12 +1296,10 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); - /* ADD_GROUP("Orbit Velocity", "orbit_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); -*/ ADD_GROUP("Linear Accel", "linear_"); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL); @@ -1324,10 +1355,12 @@ void CPUParticles2D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_MAX); BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(FLAG_ROTATE_Y); // Unused, but exposed for consistency with 3D. + BIND_ENUM_CONSTANT(FLAG_DISABLE_Z); // Unused, but exposed for consistency with 3D. BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT); - BIND_ENUM_CONSTANT(EMISSION_SHAPE_CIRCLE); + BIND_ENUM_CONSTANT(EMISSION_SHAPE_SPHERE); BIND_ENUM_CONSTANT(EMISSION_SHAPE_RECTANGLE); BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINTS); BIND_ENUM_CONSTANT(EMISSION_SHAPE_DIRECTED_POINTS); @@ -1361,10 +1394,10 @@ CPUParticles2D::CPUParticles2D() { set_spread(45); set_flatness(0); - set_param(PARAM_INITIAL_LINEAR_VELOCITY, 1); - //set_param(PARAM_ORBIT_VELOCITY, 0); - set_param(PARAM_LINEAR_ACCEL, 0); + set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param(PARAM_ANGULAR_VELOCITY, 0); + set_param(PARAM_ORBIT_VELOCITY, 0); + set_param(PARAM_LINEAR_ACCEL, 0); set_param(PARAM_RADIAL_ACCEL, 0); set_param(PARAM_TANGENTIAL_ACCEL, 0); set_param(PARAM_DAMPING, 0); @@ -1377,7 +1410,7 @@ CPUParticles2D::CPUParticles2D() { set_emission_sphere_radius(1); set_emission_rect_extents(Vector2(1, 1)); - set_gravity(Vector2(0, 98.8)); + set_gravity(Vector2(0, 98)); for (int i = 0; i < PARAM_MAX; i++) { set_param_randomness(Parameter(i), 0); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 23d2586331..813f5ddc6e 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -68,12 +68,14 @@ public: enum Flags { FLAG_ALIGN_Y_TO_VELOCITY, + FLAG_ROTATE_Y, // Unused, but exposed for consistency with 3D. + FLAG_DISABLE_Z, // Unused, but exposed for consistency with 3D. FLAG_MAX }; enum EmissionShape { EMISSION_SHAPE_POINT, - EMISSION_SHAPE_CIRCLE, + EMISSION_SHAPE_SPHERE, EMISSION_SHAPE_RECTANGLE, EMISSION_SHAPE_POINTS, EMISSION_SHAPE_DIRECTED_POINTS, @@ -116,7 +118,7 @@ private: const Particle *particles; bool operator()(int p_a, int p_b) const { - return particles[p_a].time < particles[p_b].time; + return particles[p_a].time > particles[p_b].time; } }; @@ -142,6 +144,8 @@ private: int fixed_fps; bool fractional_delta; + Transform2D inv_emission_transform; + DrawOrder draw_order; Ref<Texture> texture; @@ -248,7 +252,7 @@ public: void set_color(const Color &p_color); Color get_color() const; - void set_color_ramp(const Ref<Gradient> &p_texture); + void set_color_ramp(const Ref<Gradient> &p_ramp); Ref<Gradient> get_color_ramp() const; void set_particle_flag(Flags p_flag, bool p_enable); diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 5b14b3e8e1..d8156a0afe 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -61,9 +61,7 @@ void Joint2D::_update_joint(bool p_only_free) { if (!body_a || !body_b) return; - if (!body_a) { - SWAP(body_a, body_b); - } + SWAP(body_a, body_b); joint = _configure_joint(body_a, body_b); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 6b12db9e44..7f01ff8806 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -435,7 +435,7 @@ void Light2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_texture_offset", "get_texture_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_scale", PROPERTY_HINT_RANGE, "0.01,50,0.01"), "set_texture_scale", "get_texture_scale"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "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, "-2048,2048,0.1,or_lesser,or_greater"), "set_height", "get_height"); diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 7767f61ecf..ad405fabbb 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -38,13 +38,13 @@ VARIANT_ENUM_CAST(Line2D::LineJointMode) VARIANT_ENUM_CAST(Line2D::LineCapMode) VARIANT_ENUM_CAST(Line2D::LineTextureMode) -Line2D::Line2D() : - Node2D() { +Line2D::Line2D() { _joint_mode = LINE_JOINT_SHARP; _begin_cap_mode = LINE_CAP_NONE; _end_cap_mode = LINE_CAP_NONE; _width = 10; _default_color = Color(0.4, 0.5, 1); + _texture_mode = LINE_TEXTURE_NONE; _sharp_limit = 2.f; _round_precision = 8; } @@ -125,6 +125,7 @@ void Line2D::set_point_position(int i, Vector2 p_pos) { } Vector2 Line2D::get_point_position(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), Vector2()); return _points.get(i); } diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 2c02ad6303..14afa463ba 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -35,7 +35,7 @@ class Line2D : public Node2D { - GDCLASS(Line2D, Node2D) + GDCLASS(Line2D, Node2D); public: enum LineJointMode { diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index b382ca7b33..bcd4bca940 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -50,6 +50,8 @@ void MeshInstance2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &MeshInstance2D::set_normal_map); ClassDB::bind_method(D_METHOD("get_normal_map"), &MeshInstance2D::get_normal_map); + ADD_SIGNAL(MethodInfo("texture_changed")); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map"); diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h index 4d81c8088a..af552415ca 100644 --- a/scene/2d/mesh_instance_2d.h +++ b/scene/2d/mesh_instance_2d.h @@ -34,7 +34,7 @@ #include "scene/2d/node_2d.h" class MeshInstance2D : public Node2D { - GDCLASS(MeshInstance2D, Node2D) + GDCLASS(MeshInstance2D, Node2D); Ref<Mesh> mesh; diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp new file mode 100644 index 0000000000..ca75302163 --- /dev/null +++ b/scene/2d/multimesh_instance_2d.cpp @@ -0,0 +1,111 @@ +/*************************************************************************/ +/* multimesh_instance_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "multimesh_instance_2d.h" + +void MultiMeshInstance2D::_notification(int p_what) { + + if (p_what == NOTIFICATION_DRAW) { + if (multimesh.is_valid()) { + draw_multimesh(multimesh, texture, normal_map); + } + } +} + +void MultiMeshInstance2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh"), &MultiMeshInstance2D::set_multimesh); + ClassDB::bind_method(D_METHOD("get_multimesh"), &MultiMeshInstance2D::get_multimesh); + + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &MultiMeshInstance2D::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &MultiMeshInstance2D::get_texture); + + ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &MultiMeshInstance2D::set_normal_map); + ClassDB::bind_method(D_METHOD("get_normal_map"), &MultiMeshInstance2D::get_normal_map); + + ADD_SIGNAL(MethodInfo("texture_changed")); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multimesh", PROPERTY_HINT_RESOURCE_TYPE, "MultiMesh"), "set_multimesh", "get_multimesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map"); +} + +void MultiMeshInstance2D::set_multimesh(const Ref<MultiMesh> &p_multimesh) { + + multimesh = p_multimesh; + update(); +} + +Ref<MultiMesh> MultiMeshInstance2D::get_multimesh() const { + + return multimesh; +} + +void MultiMeshInstance2D::set_texture(const Ref<Texture> &p_texture) { + + if (p_texture == texture) + return; + texture = p_texture; + update(); + emit_signal("texture_changed"); + _change_notify("texture"); +} + +Ref<Texture> MultiMeshInstance2D::get_texture() const { + + return texture; +} + +void MultiMeshInstance2D::set_normal_map(const Ref<Texture> &p_texture) { + + normal_map = p_texture; + update(); +} + +Ref<Texture> MultiMeshInstance2D::get_normal_map() const { + + return normal_map; +} + +Rect2 MultiMeshInstance2D::_edit_get_rect() const { + + if (multimesh.is_valid()) { + AABB aabb = multimesh->get_aabb(); + return Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y); + } + + return Node2D::_edit_get_rect(); +} + +MultiMeshInstance2D::MultiMeshInstance2D() { +} + +MultiMeshInstance2D::~MultiMeshInstance2D() { +} diff --git a/scene/2d/multimesh_instance_2d.h b/scene/2d/multimesh_instance_2d.h new file mode 100644 index 0000000000..3795497183 --- /dev/null +++ b/scene/2d/multimesh_instance_2d.h @@ -0,0 +1,65 @@ +/*************************************************************************/ +/* multimesh_instance_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef MULTIMESH_INSTANCE_2D_H +#define MULTIMESH_INSTANCE_2D_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/multimesh.h" + +class MultiMeshInstance2D : public Node2D { + GDCLASS(MultiMeshInstance2D, Node2D); + + Ref<MultiMesh> multimesh; + + Ref<Texture> texture; + Ref<Texture> normal_map; + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_multimesh(const Ref<MultiMesh> &p_multimesh); + Ref<MultiMesh> get_multimesh() const; + + void set_texture(const Ref<Texture> &p_texture); + Ref<Texture> get_texture() const; + + void set_normal_map(const Ref<Texture> &p_texture); + Ref<Texture> get_normal_map() const; + + virtual Rect2 _edit_get_rect() const; + + MultiMeshInstance2D(); + ~MultiMeshInstance2D(); +}; + +#endif // MULTIMESH_INSTANCE_2D_H diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index 0f6af358bd..e389d5f98f 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -312,7 +312,7 @@ void NavigationPolygon::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines); ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); + ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines"); } diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index baf5b5967b..9a6b63b9a3 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -105,6 +105,11 @@ void ParallaxLayer::_notification(int p_what) { orig_scale = get_scale(); _update_mirroring(); } break; + case NOTIFICATION_EXIT_TREE: { + + set_position(orig_offset); + set_scale(orig_scale); + } break; } } diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 9701998f5d..7759897420 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -41,6 +41,12 @@ void Particles2D::set_emitting(bool p_emitting) { VS::get_singleton()->particles_set_emitting(particles, p_emitting); + + if (p_emitting && one_shot) { + set_process_internal(true); + } else if (!p_emitting) { + set_process_internal(false); + } } void Particles2D::set_amount(int p_amount) { @@ -60,8 +66,16 @@ void Particles2D::set_one_shot(bool p_enable) { one_shot = p_enable; VS::get_singleton()->particles_set_one_shot(particles, one_shot); - if (!one_shot && is_emitting()) - VisualServer::get_singleton()->particles_restart(particles); + + if (is_emitting()) { + + set_process_internal(true); + if (!one_shot) + VisualServer::get_singleton()->particles_restart(particles); + } + + if (!one_shot) + set_process_internal(false); } void Particles2D::set_pre_process_time(float p_time) { @@ -278,6 +292,7 @@ void Particles2D::_validate_property(PropertyInfo &property) const { void Particles2D::restart() { VS::get_singleton()->particles_restart(particles); + VS::get_singleton()->particles_set_emitting(particles, true); } void Particles2D::_notification(int p_what) { @@ -313,6 +328,14 @@ void Particles2D::_notification(int p_what) { if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { _update_particle_emission_transform(); } + + if (p_what == NOTIFICATION_INTERNAL_PROCESS) { + + if (one_shot && !is_emitting()) { + _change_notify(); + set_process_internal(false); + } + } } void Particles2D::_bind_methods() { diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index a0104b4b16..0276978f83 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -37,7 +37,7 @@ class Particles2D : public Node2D { private: - GDCLASS(Particles2D, Node2D) + GDCLASS(Particles2D, Node2D); public: enum DrawOrder { diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 4097006b33..e062067248 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -264,7 +264,7 @@ void PathFollow2D::_validate_property(PropertyInfo &property) const { if (path && path->get_curve().is_valid()) max = path->get_curve()->get_baked_length(); - property.hint_string = "0," + rtos(max) + ",0.01,or_greater"; + property.hint_string = "0," + rtos(max) + ",0.01,or_lesser"; } } @@ -306,8 +306,8 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead); ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotate"), "set_rotate", "is_rotating"); @@ -319,8 +319,24 @@ void PathFollow2D::_bind_methods() { void PathFollow2D::set_offset(float p_offset) { offset = p_offset; - if (path) + if (path) { + if (path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { + float path_length = path->get_curve()->get_baked_length(); + + if (loop) { + while (offset > path_length) + offset -= path_length; + + while (offset < 0) + offset += path_length; + + } else { + offset = CLAMP(offset, 0, path_length); + } + } + _update_transform(); + } _change_notify("offset"); _change_notify("unit_offset"); } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 578c9aa5f9..95acf13fad 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -203,8 +203,8 @@ void StaticBody2D::set_friction(real_t p_friction) { return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -217,8 +217,8 @@ void StaticBody2D::set_friction(real_t p_friction) { real_t StaticBody2D::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -233,8 +233,8 @@ void StaticBody2D::set_bounce(real_t p_bounce) { return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -247,8 +247,8 @@ void StaticBody2D::set_bounce(real_t p_bounce) { real_t StaticBody2D::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; @@ -630,8 +630,8 @@ void RigidBody2D::set_friction(real_t p_friction) { return; } - ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_friction < 0 || p_friction > 1); @@ -643,8 +643,8 @@ void RigidBody2D::set_friction(real_t p_friction) { } real_t RigidBody2D::get_friction() const { - ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_friction has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 1; @@ -659,8 +659,8 @@ void RigidBody2D::set_bounce(real_t p_bounce) { return; } - ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method set_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1); @@ -672,8 +672,8 @@ void RigidBody2D::set_bounce(real_t p_bounce) { } real_t RigidBody2D::get_bounce() const { - ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead.") - WARN_DEPRECATED + ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physics material instead."); + WARN_DEPRECATED; if (physics_material_override.is_null()) { return 0; @@ -1541,7 +1541,7 @@ Vector2 KinematicCollision2D::get_remainder() const { return collision.remainder; } Object *KinematicCollision2D::get_local_shape() const { - ERR_FAIL_COND_V(!owner, NULL); + if (!owner) return NULL; uint32_t ownerid = owner->shape_find_owner(collision.local_shape); return owner->shape_owner_get_owner(ownerid); } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 89dd1e5341..66e5ce250f 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -157,8 +157,8 @@ private: bool operator<(const ShapePair &p_sp) const { if (body_shape == p_sp.body_shape) return local_shape < p_sp.local_shape; - else - return body_shape < p_sp.body_shape; + + return body_shape < p_sp.body_shape; } ShapePair() {} diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index bed6f8a816..f0c46a5fb7 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -33,15 +33,19 @@ #include "core/engine.h" #include "scene/resources/texture.h" +const float DEFAULT_GIZMO_EXTENTS = 10.0; + void Position2D::_draw_cross() { - draw_line(Point2(-10, 0), Point2(+10, 0), Color(1, 0.5, 0.5)); - draw_line(Point2(0, -10), Point2(0, +10), Color(0.5, 1, 0.5)); + float extents = get_gizmo_extents(); + draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(1, 0.5, 0.5)); + draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.5, 1, 0.5)); } Rect2 Position2D::_edit_get_rect() const { - return Rect2(Point2(-10, -10), Size2(20, 20)); + float extents = get_gizmo_extents(); + return Rect2(Point2(-extents, -extents), Size2(extents * 2, extents * 2)); } bool Position2D::_edit_use_rect() const { @@ -66,5 +70,31 @@ void Position2D::_notification(int p_what) { } } +void Position2D::set_gizmo_extents(float p_extents) { + if (p_extents == DEFAULT_GIZMO_EXTENTS) { + set_meta("_gizmo_extents_", Variant()); + } else { + set_meta("_gizmo_extents_", p_extents); + } + + update(); +} + +float Position2D::get_gizmo_extents() const { + if (has_meta("_gizmo_extents_")) { + return get_meta("_gizmo_extents_"); + } else { + return DEFAULT_GIZMO_EXTENTS; + } +} + +void Position2D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_set_gizmo_extents", "extents"), &Position2D::set_gizmo_extents); + ClassDB::bind_method(D_METHOD("_get_gizmo_extents"), &Position2D::get_gizmo_extents); + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "gizmo_extents", PROPERTY_HINT_RANGE, "0,1000,0.1,or_greater", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_gizmo_extents", "_get_gizmo_extents"); +} + Position2D::Position2D() { } diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h index c95315fea3..f5ec3ef01a 100644 --- a/scene/2d/position_2d.h +++ b/scene/2d/position_2d.h @@ -35,16 +35,21 @@ class Position2D : public Node2D { - GDCLASS(Position2D, Node2D) + GDCLASS(Position2D, Node2D); void _draw_cross(); protected: void _notification(int p_what); + static void _bind_methods(); public: virtual Rect2 _edit_get_rect() const; virtual bool _edit_use_rect() const; + + void set_gizmo_extents(float p_extents); + float get_gizmo_extents() const; + Position2D(); }; diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index cf9877e6f8..0f48b44387 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -36,9 +36,12 @@ class Skeleton2D; class Bone2D : public Node2D { - GDCLASS(Bone2D, Node2D) + GDCLASS(Bone2D, Node2D); friend class Skeleton2D; +#ifdef TOOLS_ENABLED + friend class AnimatedValuesBackup; +#endif Bone2D *parent_bone; Skeleton2D *skeleton; @@ -71,6 +74,9 @@ class Skeleton2D : public Node2D { GDCLASS(Skeleton2D, Node2D); friend class Bone2D; +#ifdef TOOLS_ENABLED + friend class AnimatedValuesBackup; +#endif struct Bone { bool operator<(const Bone &p_bone) const { diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index a8c7622828..6626fccf1c 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -63,10 +63,7 @@ Rect2 Sprite::_edit_get_rect() const { } bool Sprite::_edit_use_rect() const { - if (texture.is_null()) - return false; - - return true; + return texture.is_valid(); } Rect2 Sprite::get_anchorable_rect() const { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index b321bcf3ce..fc53c9e4ac 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -30,9 +30,11 @@ #include "tile_map.h" +#include "collision_object_2d.h" #include "core/io/marshalls.h" #include "core/method_bind_ext.gen.inc" #include "core/os/os.h" +#include "scene/2d/area_2d.h" #include "servers/physics_2d_server.h" int TileMap::_get_quadrant_size() const { @@ -60,14 +62,21 @@ void TileMap::_notification(int p_what) { c = Object::cast_to<Node2D>(c->get_parent()); } + if (use_parent) { + _clear_quadrants(); + collision_parent = Object::cast_to<CollisionObject2D>(get_parent()); + } + pending_update = true; _recreate_quadrants(); update_dirty_quadrants(); RID space = get_world_2d()->get_space(); _update_quadrant_transform(); _update_quadrant_space(space); + update_configuration_warning(); } break; + case NOTIFICATION_EXIT_TREE: { _update_quadrant_space(RID()); @@ -82,30 +91,46 @@ void TileMap::_notification(int p_what) { q.navpoly_ids.clear(); } + if (collision_parent) { + collision_parent->remove_shape_owner(q.shape_owner_id); + q.shape_owner_id = -1; + } + for (Map<PosKey, Quadrant::Occluder>::Element *F = q.occluder_instances.front(); F; F = F->next()) { VS::get_singleton()->free(F->get().id); } q.occluder_instances.clear(); } + collision_parent = NULL; navigation = NULL; } break; + case NOTIFICATION_TRANSFORM_CHANGED: { //move stuff _update_quadrant_transform(); } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + + if (use_parent) { + _recreate_quadrants(); + } + + } break; } } void TileMap::_update_quadrant_space(const RID &p_space) { - for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { + if (!use_parent) { + for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_space(q.body, p_space); + Quadrant &q = E->get(); + Physics2DServer::get_singleton()->body_set_space(q.body, p_space); + } } } @@ -116,6 +141,10 @@ void TileMap::_update_quadrant_transform() { Transform2D global_transform = get_global_transform(); + Transform2D local_transform; + if (collision_parent) + local_transform = get_transform(); + Transform2D nav_rel; if (navigation) nav_rel = get_relative_transform_to_parent(navigation); @@ -125,8 +154,11 @@ void TileMap::_update_quadrant_transform() { Quadrant &q = E->get(); Transform2D xform; xform.set_origin(q.pos); - xform = global_transform * xform; - Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); + + if (!use_parent) { + xform = global_transform * xform; + Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); + } if (navigation) { for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) { @@ -202,47 +234,55 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Size2 s = p_sc; Vector2 offset = p_offset; - if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) - offset.y += cell_size.y; - else if (tile_origin == TILE_ORIGIN_CENTER) { - offset += cell_size / 2; - } - - if (s.y > s.x) { - if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose)) - offset.y += s.y - s.x; - } else if (s.y < s.x) { - if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose)) - offset.x += s.x - s.y; - } - if (p_cell.transpose) { SWAP(xform.elements[0].x, xform.elements[0].y); SWAP(xform.elements[1].x, xform.elements[1].y); SWAP(offset.x, offset.y); SWAP(s.x, s.y); } + if (p_cell.flip_h) { xform.elements[0].x = -xform.elements[0].x; xform.elements[1].x = -xform.elements[1].x; - if (tile_origin == TILE_ORIGIN_TOP_LEFT || tile_origin == TILE_ORIGIN_BOTTOM_LEFT) - offset.x = s.x - offset.x; - else if (tile_origin == TILE_ORIGIN_CENTER) - offset.x = s.x - offset.x / 2; + offset.x = s.x - offset.x; } + if (p_cell.flip_v) { xform.elements[0].y = -xform.elements[0].y; xform.elements[1].y = -xform.elements[1].y; - if (tile_origin == TILE_ORIGIN_TOP_LEFT) - offset.y = s.y - offset.y; - else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - offset.y += s.y; - } else if (tile_origin == TILE_ORIGIN_CENTER) { - offset.y += s.y; + offset.y = s.y - offset.y; + } + /* For a future CheckBox to Center Texture: + offset += cell_size / 2 - s / 2; */ + xform.elements[2] += offset; +} + +void TileMap::_add_shape(int &shape_idx, const Quadrant &p_q, const Ref<Shape2D> &p_shape, const TileSet::ShapeData &p_shape_data, const Transform2D &p_xform, const Vector2 &p_metadata) { + Physics2DServer *ps = Physics2DServer::get_singleton(); + + if (!use_parent) { + ps->body_add_shape(p_q.body, p_shape->get_rid(), p_xform); + ps->body_set_shape_metadata(p_q.body, shape_idx, p_metadata); + ps->body_set_shape_as_one_way_collision(p_q.body, shape_idx, p_shape_data.one_way_collision, p_shape_data.one_way_collision_margin); + + } else if (collision_parent) { + Transform2D xform = p_xform; + xform.set_origin(xform.get_origin() + p_q.pos); + + collision_parent->shape_owner_add_shape(p_q.shape_owner_id, p_shape); + + int real_index = collision_parent->shape_owner_get_shape_index(p_q.shape_owner_id, shape_idx); + RID rid = collision_parent->get_rid(); + + if (Object::cast_to<Area2D>(collision_parent) != NULL) { + ps->area_set_shape_transform(rid, real_index, get_transform() * xform); + } else { + ps->body_set_shape_transform(rid, real_index, get_transform() * xform); + ps->body_set_shape_metadata(rid, real_index, p_metadata); + ps->body_set_shape_as_one_way_collision(rid, real_index, p_shape_data.one_way_collision, p_shape_data.one_way_collision_margin); } } - xform.elements[2].x += offset.x; - xform.elements[2].y += offset.y; + shape_idx++; } void TileMap::update_dirty_quadrants() { @@ -288,7 +328,11 @@ void TileMap::update_dirty_quadrants() { q.canvas_items.clear(); - ps->body_clear_shapes(q.body); + if (!use_parent) { + ps->body_clear_shapes(q.body); + } else if (collision_parent) { + collision_parent->shape_owner_clear_shapes(q.shape_owner_id); + } int shape_idx = 0; if (navigation) { @@ -390,64 +434,26 @@ void TileMap::update_dirty_quadrants() { rect.size.x += fp_adjust; rect.size.y += fp_adjust; - if (rect.size.y > rect.size.x) { - if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose)) - tile_ofs.y += rect.size.y - rect.size.x; - } else if (rect.size.y < rect.size.x) { - if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose)) - tile_ofs.x += rect.size.x - rect.size.y; - } - - /* rect.size.x+=fp_adjust; - rect.size.y+=fp_adjust;*/ - - if (c.transpose) + if (c.transpose) { SWAP(tile_ofs.x, tile_ofs.y); + /* For a future CheckBox to Center Texture: + rect.position.x += cell_size.x / 2 - rect.size.y / 2; + rect.position.y += cell_size.y / 2 - rect.size.x / 2; + } else { + rect.position += cell_size / 2 - rect.size / 2; */ + } if (c.flip_h) { rect.size.x = -rect.size.x; tile_ofs.x = -tile_ofs.x; } + if (c.flip_v) { rect.size.y = -rect.size.y; tile_ofs.y = -tile_ofs.y; } - Vector2 center_ofs; - - if (tile_origin == TILE_ORIGIN_TOP_LEFT) { - rect.position += tile_ofs; - - } else if (tile_origin == TILE_ORIGIN_BOTTOM_LEFT) { - - rect.position += tile_ofs; - - if (c.transpose) { - if (c.flip_h) - rect.position.x -= cell_size.x; - else - rect.position.x += cell_size.x; - } else { - if (c.flip_v) - rect.position.y -= cell_size.y; - else - rect.position.y += cell_size.y; - } - - } else if (tile_origin == TILE_ORIGIN_CENTER) { - - rect.position += tile_ofs; - - if (c.flip_h) - rect.position.x -= cell_size.x / 2; - else - rect.position.x += cell_size.x / 2; - - if (c.flip_v) - rect.position.y -= cell_size.y / 2; - else - rect.position.y += cell_size.y / 2; - } + rect.position += tile_ofs; Ref<Texture> normal_map = tile_set->tile_get_normal_map(c.id); Color modulate = tile_set->tile_get_modulate(c.id); @@ -471,7 +477,7 @@ void TileMap::update_dirty_quadrants() { Vector2 shape_ofs = shapes[j].shape_transform.get_origin(); - _fix_cell_transform(xform, c, shape_ofs + center_ofs, s); + _fix_cell_transform(xform, c, shape_ofs, s); xform *= shapes[j].shape_transform.untranslated(); @@ -485,21 +491,15 @@ void TileMap::update_dirty_quadrants() { 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++; + _add_shape(shape_idx, q, convex, shapes[j], xform, Vector2(E->key().x, E->key().y)); #ifdef DEBUG_ENABLED } else { - print_error("The TileSet asigned to the TileMap " + get_name() + " has an invalid convex shape."); + print_error("The TileSet assigned 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++; + _add_shape(shape_idx, q, shape, shapes[j], xform, Vector2(E->key().x, E->key().y)); } } } @@ -523,7 +523,7 @@ void TileMap::update_dirty_quadrants() { if (navpoly.is_valid()) { Transform2D xform; xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, npoly_ofs + center_ofs, s); + _fix_cell_transform(xform, c, npoly_ofs, s); int pid = navigation->navpoly_add(navpoly, nav_rel * xform); @@ -573,7 +573,7 @@ void TileMap::update_dirty_quadrants() { } Transform2D navxform; navxform.set_origin(offset.floor()); - _fix_cell_transform(navxform, c, npoly_ofs + center_ofs, s); + _fix_cell_transform(navxform, c, npoly_ofs, s); vs->canvas_item_set_transform(debug_navigation_item, navxform); vs->canvas_item_add_triangle_array(debug_navigation_item, indices, vertices, colors); @@ -593,7 +593,7 @@ void TileMap::update_dirty_quadrants() { Vector2 occluder_ofs = tile_set->tile_get_occluder_offset(c.id); Transform2D xform; xform.set_origin(offset.floor() + q.pos); - _fix_cell_transform(xform, c, occluder_ofs + center_ofs, s); + _fix_cell_transform(xform, c, occluder_ofs, s); RID orid = VS::get_singleton()->canvas_light_occluder_create(); VS::get_singleton()->canvas_light_occluder_set_transform(orid, get_global_transform() * xform); @@ -674,22 +674,29 @@ Map<TileMap::PosKey, TileMap::Quadrant>::Element *TileMap::_create_quadrant(cons xform.set_origin(q.pos); //q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); - q.body = Physics2DServer::get_singleton()->body_create(); - Physics2DServer::get_singleton()->body_set_mode(q.body, use_kinematic ? Physics2DServer::BODY_MODE_KINEMATIC : Physics2DServer::BODY_MODE_STATIC); - - Physics2DServer::get_singleton()->body_attach_object_instance_id(q.body, get_instance_id()); - Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); - Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, friction); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, bounce); - - if (is_inside_tree()) { - xform = get_global_transform() * xform; - RID space = get_world_2d()->get_space(); - Physics2DServer::get_singleton()->body_set_space(q.body, space); - } + if (!use_parent) { + q.body = Physics2DServer::get_singleton()->body_create(); + Physics2DServer::get_singleton()->body_set_mode(q.body, use_kinematic ? Physics2DServer::BODY_MODE_KINEMATIC : Physics2DServer::BODY_MODE_STATIC); + + Physics2DServer::get_singleton()->body_attach_object_instance_id(q.body, get_instance_id()); + Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); + Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask); + Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, friction); + Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, bounce); + + if (is_inside_tree()) { + xform = get_global_transform() * xform; + RID space = get_world_2d()->get_space(); + Physics2DServer::get_singleton()->body_set_space(q.body, space); + } - Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); + Physics2DServer::get_singleton()->body_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); + } else if (collision_parent) { + xform = get_transform() * xform; + q.shape_owner_id = collision_parent->create_shape_owner(this); + } else { + q.shape_owner_id = -1; + } rect_cache_dirty = true; quadrant_order_dirty = true; @@ -699,7 +706,12 @@ Map<TileMap::PosKey, TileMap::Quadrant>::Element *TileMap::_create_quadrant(cons void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) { Quadrant &q = Q->get(); - Physics2DServer::get_singleton()->free(q.body); + if (!use_parent) { + Physics2DServer::get_singleton()->free(q.body); + } else if (collision_parent) { + collision_parent->remove_shape_owner(q.shape_owner_id); + } + for (List<RID>::Element *E = q.canvas_items.front(); E; E = E->next()) { VisualServer::get_singleton()->free(E->get()); @@ -927,8 +939,17 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) { _make_quadrant_dirty(Q); } else if (tile_set->tile_get_tile_mode(id) == TileSet::SINGLE_TILE) { + E->get().autotile_coord_x = 0; E->get().autotile_coord_y = 0; + } else if (tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { + + if (tile_set->autotile_get_bitmask(id, Vector2(p_x, p_y)) == TileSet::BIND_CENTER) { + Vector2 coord = tile_set->atlastile_get_subtile_by_priority(id, this, Vector2(p_x, p_y)); + + E->get().autotile_coord_x = (int)coord.x; + E->get().autotile_coord_y = (int)coord.y; + } } } } @@ -1184,20 +1205,24 @@ Rect2 TileMap::_edit_get_rect() const { void TileMap::set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; - for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { + if (!use_parent) { + for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); + Quadrant &q = E->get(); + Physics2DServer::get_singleton()->body_set_collision_layer(q.body, collision_layer); + } } } void TileMap::set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; - for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { + if (!use_parent) { + for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask); + Quadrant &q = E->get(); + Physics2DServer::get_singleton()->body_set_collision_mask(q.body, collision_mask); + } } } @@ -1233,13 +1258,40 @@ void TileMap::set_collision_use_kinematic(bool p_use_kinematic) { _recreate_quadrants(); } +bool TileMap::get_collision_use_parent() const { + + return use_parent; +} + +void TileMap::set_collision_use_parent(bool p_use_parent) { + + if (use_parent == p_use_parent) return; + + _clear_quadrants(); + + use_parent = p_use_parent; + set_notify_local_transform(use_parent); + + if (use_parent && is_inside_tree()) { + collision_parent = Object::cast_to<CollisionObject2D>(get_parent()); + } else { + collision_parent = NULL; + } + + _recreate_quadrants(); + _change_notify(); + update_configuration_warning(); +} + void TileMap::set_collision_friction(float p_friction) { friction = p_friction; - for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { + if (!use_parent) { + for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, p_friction); + Quadrant &q = E->get(); + Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_FRICTION, p_friction); + } } } @@ -1251,10 +1303,12 @@ float TileMap::get_collision_friction() const { void TileMap::set_collision_bounce(float p_bounce) { bounce = p_bounce; - for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { + if (!use_parent) { + for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { - Quadrant &q = E->get(); - Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, p_bounce); + Quadrant &q = E->get(); + Physics2DServer::get_singleton()->body_set_param(q.body, Physics2DServer::BODY_PARAM_BOUNCE, p_bounce); + } } } float TileMap::get_collision_bounce() const { @@ -1453,6 +1507,12 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(p); } +void TileMap::_validate_property(PropertyInfo &property) const { + if (use_parent && property.name != "collision_use_parent" && property.name.begins_with("collision_")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + Vector2 TileMap::map_to_world(const Vector2 &p_pos, bool p_ignore_ofs) const { return _map_to_world(p_pos.x, p_pos.y, p_ignore_ofs); @@ -1601,6 +1661,20 @@ bool TileMap::get_clip_uv() const { return clip_uv; } +String TileMap::get_configuration_warning() const { + + String warning = Node2D::get_configuration_warning(); + + if (use_parent && !collision_parent) { + if (!warning.empty()) { + warning += "\n"; + } + return TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); + } + + return warning; +} + void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset); @@ -1636,6 +1710,9 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_use_kinematic", "use_kinematic"), &TileMap::set_collision_use_kinematic); ClassDB::bind_method(D_METHOD("get_collision_use_kinematic"), &TileMap::get_collision_use_kinematic); + ClassDB::bind_method(D_METHOD("set_collision_use_parent", "use_parent"), &TileMap::set_collision_use_parent); + ClassDB::bind_method(D_METHOD("get_collision_use_parent"), &TileMap::get_collision_use_parent); + ClassDB::bind_method(D_METHOD("set_collision_layer", "layer"), &TileMap::set_collision_layer); ClassDB::bind_method(D_METHOD("get_collision_layer"), &TileMap::get_collision_layer); @@ -1701,6 +1778,7 @@ void TileMap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_clip_uv"), "set_clip_uv", "get_clip_uv"); ADD_GROUP("Collision", "collision_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_parent", PROPERTY_HINT_NONE, ""), "set_collision_use_parent", "get_collision_use_parent"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_kinematic", PROPERTY_HINT_NONE, ""), "set_collision_use_kinematic", "get_collision_use_kinematic"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce"); @@ -1749,6 +1827,8 @@ TileMap::TileMap() { bounce = 0; mode = MODE_SQUARE; half_offset = HALF_OFFSET_DISABLED; + use_parent = false; + collision_parent = NULL; use_kinematic = false; navigation = NULL; y_sort_mode = false; @@ -1759,6 +1839,7 @@ TileMap::TileMap() { fp_adjust = 0.00001; tile_origin = TILE_ORIGIN_TOP_LEFT; set_notify_transform(true); + set_notify_local_transform(false); } TileMap::~TileMap() { diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 6a1467aa48..1caaefa213 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -37,6 +37,8 @@ #include "scene/2d/node_2d.h" #include "scene/resources/tile_set.h" +class CollisionObject2D; + class TileMap : public Node2D { GDCLASS(TileMap, Node2D); @@ -74,6 +76,8 @@ private: Mode mode; Transform2D custom_transform; HalfOffset half_offset; + bool use_parent; + CollisionObject2D *collision_parent; bool use_kinematic; Navigation2D *navigation; @@ -123,6 +127,7 @@ private: Vector2 pos; List<RID> canvas_items; RID body; + uint32_t shape_owner_id; SelfList<Quadrant> dirty_list; @@ -145,6 +150,7 @@ private: pos = q.pos; canvas_items = q.canvas_items; body = q.body; + shape_owner_id = q.shape_owner_id; cells = q.cells; navpoly_ids = q.navpoly_ids; occluder_instances = q.occluder_instances; @@ -154,6 +160,7 @@ private: pos = q.pos; canvas_items = q.canvas_items; body = q.body; + shape_owner_id = q.shape_owner_id; cells = q.cells; occluder_instances = q.occluder_instances; navpoly_ids = q.navpoly_ids; @@ -188,6 +195,8 @@ private: void _fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc); + void _add_shape(int &shape_idx, const Quadrant &p_q, const Ref<Shape2D> &p_shape, const TileSet::ShapeData &p_shape_data, const Transform2D &p_xform, const Vector2 &p_metadata); + Map<PosKey, Quadrant>::Element *_create_quadrant(const PosKey &p_qk); void _erase_quadrant(Map<PosKey, Quadrant>::Element *Q); void _make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q, bool update = true); @@ -218,6 +227,7 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const; virtual void _changed_callback(Object *p_changed, const char *p_prop); public: @@ -271,6 +281,9 @@ public: void set_collision_use_kinematic(bool p_use_kinematic); bool get_collision_use_kinematic() const; + void set_collision_use_parent(bool p_use_parent); + bool get_collision_use_parent() const; + void set_collision_friction(float p_friction); float get_collision_friction() const; @@ -314,6 +327,8 @@ public: void set_clip_uv(bool p_enable); bool get_clip_uv() const; + String get_configuration_warning() const; + void fix_invalid_tiles(); void clear(); |