diff options
Diffstat (limited to 'scene/2d')
30 files changed, 514 insertions, 239 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 075b0e6252..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,7 +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 == 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.cpp b/scene/2d/canvas_item.cpp index 78e98deb93..23f6404e3e 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -1074,6 +1074,7 @@ Vector2 CanvasItem::make_canvas_position_local(const Vector2 &screen_point) cons Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const { + ERR_FAIL_COND_V(p_event.is_null(), p_event); ERR_FAIL_COND_V(!is_inside_tree(), p_event); return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse()); 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/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 ff27e0a29a..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) { @@ -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 e116d404d6..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; } @@ -84,10 +84,10 @@ void Line2D::set_points(const PoolVector<Vector2> &p_points) { update(); } -void Line2D::set_width(float width) { - if (width < 0.0) - width = 0.0; - _width = width; +void Line2D::set_width(float p_width) { + if (p_width < 0.0) + p_width = 0.0; + _width = p_width; update(); } @@ -95,17 +95,37 @@ float Line2D::get_width() const { return _width; } +void Line2D::set_curve(const Ref<Curve> &p_curve) { + // Cleanup previous connection if any + if (_curve.is_valid()) { + _curve->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + } + + _curve = p_curve; + + // Connect to the curve so the line will update when it is changed + if (_curve.is_valid()) { + _curve->connect(CoreStringNames::get_singleton()->changed, this, "_curve_changed"); + } + + update(); +} + +Ref<Curve> Line2D::get_curve() const { + return _curve; +} + PoolVector<Vector2> Line2D::get_points() const { return _points; } -void Line2D::set_point_position(int i, Vector2 pos) { - _points.set(i, pos); +void Line2D::set_point_position(int i, Vector2 p_pos) { + _points.set(i, p_pos); update(); } Vector2 Line2D::get_point_position(int i) const { - ERR_FAIL_INDEX_V(i, _points.size(), Vector2()) + ERR_FAIL_INDEX_V(i, _points.size(), Vector2()); return _points.get(i); } @@ -121,11 +141,11 @@ void Line2D::clear_points() { } } -void Line2D::add_point(Vector2 pos, int atpos) { - if (atpos < 0 || _points.size() < atpos) { - _points.append(pos); +void Line2D::add_point(Vector2 p_pos, int p_atpos) { + if (p_atpos < 0 || _points.size() < p_atpos) { + _points.append(p_pos); } else { - _points.insert(atpos, pos); + _points.insert(p_atpos, p_pos); } update(); } @@ -135,8 +155,8 @@ void Line2D::remove_point(int i) { update(); } -void Line2D::set_default_color(Color color) { - _default_color = color; +void Line2D::set_default_color(Color p_color) { + _default_color = p_color; update(); } @@ -144,18 +164,18 @@ Color Line2D::get_default_color() const { return _default_color; } -void Line2D::set_gradient(const Ref<Gradient> &gradient) { +void Line2D::set_gradient(const Ref<Gradient> &p_gradient) { // Cleanup previous connection if any if (_gradient.is_valid()) { - (**_gradient).disconnect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); + _gradient->disconnect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); } - _gradient = gradient; + _gradient = p_gradient; // Connect to the gradient so the line will update when the ColorRamp is changed if (_gradient.is_valid()) { - (**_gradient).connect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); + _gradient->connect(CoreStringNames::get_singleton()->changed, this, "_gradient_changed"); } update(); @@ -165,8 +185,8 @@ Ref<Gradient> Line2D::get_gradient() const { return _gradient; } -void Line2D::set_texture(const Ref<Texture> &texture) { - _texture = texture; +void Line2D::set_texture(const Ref<Texture> &p_texture) { + _texture = p_texture; update(); } @@ -174,8 +194,8 @@ Ref<Texture> Line2D::get_texture() const { return _texture; } -void Line2D::set_texture_mode(const LineTextureMode mode) { - _texture_mode = mode; +void Line2D::set_texture_mode(const LineTextureMode p_mode) { + _texture_mode = p_mode; update(); } @@ -183,8 +203,8 @@ Line2D::LineTextureMode Line2D::get_texture_mode() const { return _texture_mode; } -void Line2D::set_joint_mode(LineJointMode mode) { - _joint_mode = mode; +void Line2D::set_joint_mode(LineJointMode p_mode) { + _joint_mode = p_mode; update(); } @@ -192,8 +212,8 @@ Line2D::LineJointMode Line2D::get_joint_mode() const { return _joint_mode; } -void Line2D::set_begin_cap_mode(LineCapMode mode) { - _begin_cap_mode = mode; +void Line2D::set_begin_cap_mode(LineCapMode p_mode) { + _begin_cap_mode = p_mode; update(); } @@ -201,8 +221,8 @@ Line2D::LineCapMode Line2D::get_begin_cap_mode() const { return _begin_cap_mode; } -void Line2D::set_end_cap_mode(LineCapMode mode) { - _end_cap_mode = mode; +void Line2D::set_end_cap_mode(LineCapMode p_mode) { + _end_cap_mode = p_mode; update(); } @@ -218,10 +238,10 @@ void Line2D::_notification(int p_what) { } } -void Line2D::set_sharp_limit(float limit) { - if (limit < 0.f) - limit = 0.f; - _sharp_limit = limit; +void Line2D::set_sharp_limit(float p_limit) { + if (p_limit < 0.f) + p_limit = 0.f; + _sharp_limit = p_limit; update(); } @@ -229,10 +249,10 @@ float Line2D::get_sharp_limit() const { return _sharp_limit; } -void Line2D::set_round_precision(int precision) { - if (precision < 1) - precision = 1; - _round_precision = precision; +void Line2D::set_round_precision(int p_precision) { + if (p_precision < 1) + p_precision = 1; + _round_precision = p_precision; update(); } @@ -268,10 +288,11 @@ void Line2D::_draw() { lb.round_precision = _round_precision; lb.sharp_limit = _sharp_limit; lb.width = _width; + lb.curve = *_curve; RID texture_rid; if (_texture.is_valid()) { - texture_rid = (**_texture).get_rid(); + texture_rid = _texture->get_rid(); lb.tile_aspect = _texture->get_size().aspect(); } @@ -312,6 +333,10 @@ void Line2D::_gradient_changed() { update(); } +void Line2D::_curve_changed() { + update(); +} + // static void Line2D::_bind_methods() { @@ -331,6 +356,9 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_width", "width"), &Line2D::set_width); ClassDB::bind_method(D_METHOD("get_width"), &Line2D::get_width); + ClassDB::bind_method(D_METHOD("set_curve", "curve"), &Line2D::set_curve); + ClassDB::bind_method(D_METHOD("get_curve"), &Line2D::get_curve); + ClassDB::bind_method(D_METHOD("set_default_color", "color"), &Line2D::set_default_color); ClassDB::bind_method(D_METHOD("get_default_color"), &Line2D::get_default_color); @@ -360,6 +388,7 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "width_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color"); ADD_GROUP("Fill", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); @@ -386,4 +415,5 @@ void Line2D::_bind_methods() { BIND_ENUM_CONSTANT(LINE_TEXTURE_STRETCH); ClassDB::bind_method(D_METHOD("_gradient_changed"), &Line2D::_gradient_changed); + ClassDB::bind_method(D_METHOD("_curve_changed"), &Line2D::_curve_changed); } diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 8a6f7b2dc5..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 { @@ -78,6 +78,9 @@ public: void set_width(float width); float get_width() const; + void set_curve(const Ref<Curve> &curve); + Ref<Curve> get_curve() const; + void set_default_color(Color color); Color get_default_color() const; @@ -113,6 +116,7 @@ protected: private: void _gradient_changed(); + void _curve_changed(); private: PoolVector<Vector2> _points; @@ -120,6 +124,7 @@ private: LineCapMode _begin_cap_mode; LineCapMode _end_cap_mode; float _width; + Ref<Curve> _curve; Color _default_color; Ref<Gradient> _gradient; Ref<Texture> _texture; diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index eb09d3c9d3..9fe5fb98b6 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -95,6 +95,7 @@ static inline Vector2 interpolate(const Rect2 &r, const Vector2 &v) { LineBuilder::LineBuilder() { joint_mode = Line2D::LINE_JOINT_SHARP; width = 10; + curve = NULL; default_color = Color(0.4, 0.5, 1); gradient = NULL; sharp_limit = 2.f; @@ -136,8 +137,8 @@ void LineBuilder::build() { Vector2 pos1 = points[1]; Vector2 f0 = (pos1 - pos0).normalized(); Vector2 u0 = rotate90(f0); - Vector2 pos_up0 = pos0 + u0 * hw; - Vector2 pos_down0 = pos0 - u0 * hw; + Vector2 pos_up0 = pos0; + Vector2 pos_down0 = pos0; Color color0; Color color1; @@ -145,12 +146,30 @@ void LineBuilder::build() { float current_distance0 = 0.f; float current_distance1 = 0.f; float total_distance = 0.f; + float width_factor = 1.f; _interpolate_color = gradient != NULL; + bool retrieve_curve = curve != NULL; bool distance_required = _interpolate_color || + retrieve_curve || texture_mode == Line2D::LINE_TEXTURE_TILE || texture_mode == Line2D::LINE_TEXTURE_STRETCH; - if (distance_required) + if (distance_required) { total_distance = calculate_total_distance(points); + //Ajust totalDistance. + // The line's outer length will be a little higher due to begin and end caps + if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) { + if (retrieve_curve) + total_distance += width * curve->interpolate_baked(0.f) * 0.5f; + else + total_distance += width * 0.5f; + } + if (end_cap_mode == Line2D::LINE_CAP_BOX || end_cap_mode == Line2D::LINE_CAP_ROUND) { + if (retrieve_curve) + total_distance += width * curve->interpolate_baked(1.f) * 0.5f; + else + total_distance += width * 0.5f; + } + } if (_interpolate_color) color0 = gradient->get_color(0); else @@ -159,22 +178,28 @@ void LineBuilder::build() { float uvx0 = 0.f; float uvx1 = 0.f; + if (retrieve_curve) + width_factor = curve->interpolate_baked(0.f); + + pos_up0 += u0 * hw * width_factor; + pos_down0 -= u0 * hw * width_factor; + // Begin cap if (begin_cap_mode == Line2D::LINE_CAP_BOX) { // Push back first vertices a little bit - pos_up0 -= f0 * hw; - pos_down0 -= f0 * hw; - // The line's outer length will be a little higher due to begin and end caps - total_distance += width; - current_distance0 += hw; + pos_up0 -= f0 * hw * width_factor; + pos_down0 -= f0 * hw * width_factor; + + current_distance0 += hw * width_factor; current_distance1 = current_distance0; } else if (begin_cap_mode == Line2D::LINE_CAP_ROUND) { if (texture_mode == Line2D::LINE_TEXTURE_TILE) { - uvx0 = 0.5f / tile_aspect; + uvx0 = width_factor * 0.5f / tile_aspect; + } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { + uvx0 = width * width_factor / total_distance; } - new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, fmin(uvx0 * 2, 1.f), 1.f)); - total_distance += width; - current_distance0 += hw; + new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, uvx0 * 2, 1.f)); + current_distance0 += hw * width_factor; current_distance1 = current_distance0; } @@ -206,13 +231,23 @@ void LineBuilder::build() { const float dp = u0.dot(f1); const Orientation orientation = (dp > 0.f ? UP : DOWN); + if (distance_required) { + current_distance1 += pos0.distance_to(pos1); + } + if (_interpolate_color) { + color1 = gradient->get_color_at_offset(current_distance1 / total_distance); + } + if (retrieve_curve) { + width_factor = curve->interpolate_baked(current_distance1 / total_distance); + } + Vector2 inner_normal0, inner_normal1; if (orientation == UP) { - inner_normal0 = u0 * hw; - inner_normal1 = u1 * hw; + inner_normal0 = u0 * hw * width_factor; + inner_normal1 = u1 * hw * width_factor; } else { - inner_normal0 = -u0 * hw; - inner_normal1 = -u1 * hw; + inner_normal0 = -u0 * hw * width_factor; + inner_normal1 = -u1 * hw * width_factor; } /* @@ -259,7 +294,8 @@ void LineBuilder::build() { Vector2 pos_up1, pos_down1; if (intersection_result == SEGMENT_INTERSECT) { // Fallback on bevel if sharp angle is too high (because it would produce very long miters) - if (current_joint_mode == Line2D::LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / hw_sq > sharp_limit_sq) { + float width_factor_sq = width_factor * width_factor; + if (current_joint_mode == Line2D::LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / (hw_sq * width_factor_sq) > sharp_limit_sq) { current_joint_mode = Line2D::LINE_JOINT_BEVEL; } if (current_joint_mode == Line2D::LINE_JOINT_SHARP) { @@ -271,9 +307,9 @@ void LineBuilder::build() { // Bevel or round if (orientation == UP) { pos_up1 = corner_pos_up; - pos_down1 = pos1 - u0 * hw; + pos_down1 = pos1 - u0 * hw * width_factor; } else { - pos_up1 = pos1 + u0 * hw; + pos_up1 = pos1 + u0 * hw * width_factor; pos_down1 = corner_pos_down; } } @@ -289,12 +325,6 @@ void LineBuilder::build() { // Add current line body quad // Triangles are clockwise - if (distance_required) { - current_distance1 += pos0.distance_to(pos1); - } - if (_interpolate_color) { - color1 = gradient->get_color_at_offset(current_distance1 / total_distance); - } if (texture_mode == Line2D::LINE_TEXTURE_TILE) { uvx1 = current_distance1 / (width * tile_aspect); } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { @@ -315,15 +345,15 @@ void LineBuilder::build() { } else { if (orientation == UP) { pos_up0 = corner_pos_up; - pos_down0 = pos1 - u1 * hw; + pos_down0 = pos1 - u1 * hw * width_factor; } else { - pos_up0 = pos1 + u1 * hw; + pos_up0 = pos1 + u1 * hw * width_factor; pos_down0 = corner_pos_down; } } } else { - pos_up0 = pos1 + u1 * hw; - pos_down0 = pos1 - u1 * hw; + pos_up0 = pos1 + u1 * hw * width_factor; + pos_down0 = pos1 - u1 * hw * width_factor; } // From this point, bu0 and bd0 concern the next segment @@ -362,26 +392,28 @@ void LineBuilder::build() { strip_begin(pos_up0, pos_down0, color1, uvx1); } } - // Last (or only) segment - pos1 = points[points.size() - 1]; - Vector2 pos_up1 = pos1 + u0 * hw; - Vector2 pos_down1 = pos1 - u0 * hw; - - // End cap (box) - if (end_cap_mode == Line2D::LINE_CAP_BOX) { - pos_up1 += f0 * hw; - pos_down1 += f0 * hw; - } - if (distance_required) { current_distance1 += pos0.distance_to(pos1); } if (_interpolate_color) { color1 = gradient->get_color(gradient->get_points_count() - 1); } + if (retrieve_curve) { + width_factor = curve->interpolate_baked(1.f); + } + + Vector2 pos_up1 = pos1 + u0 * hw * width_factor; + Vector2 pos_down1 = pos1 - u0 * hw * width_factor; + + // End cap (box) + if (end_cap_mode == Line2D::LINE_CAP_BOX) { + pos_up1 += f0 * hw * width_factor; + pos_down1 += f0 * hw * width_factor; + } + if (texture_mode == Line2D::LINE_TEXTURE_TILE) { uvx1 = current_distance1 / (width * tile_aspect); } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { @@ -394,7 +426,13 @@ void LineBuilder::build() { if (end_cap_mode == Line2D::LINE_CAP_ROUND) { // Note: color is not used in case we don't interpolate... Color color = _interpolate_color ? gradient->get_color(gradient->get_points_count() - 1) : Color(0, 0, 0); - new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f / tile_aspect, 0.f, 1.0f / tile_aspect, 1.f)); + float dist = 0; + if (texture_mode == Line2D::LINE_TEXTURE_TILE) { + dist = width_factor / tile_aspect; + } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) { + dist = width * width_factor / total_distance; + } + new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f * dist, 0.f, dist, 1.f)); } } diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index b961385e33..91b4518f9b 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -45,6 +45,7 @@ public: Line2D::LineCapMode begin_cap_mode; Line2D::LineCapMode end_cap_mode; float width; + Curve *curve; Color default_color; Gradient *gradient; Line2D::LineTextureMode texture_mode; 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/navigation_2d.cpp b/scene/2d/navigation_2d.cpp index 72b5f2fb12..f644db462b 100644 --- a/scene/2d/navigation_2d.cpp +++ b/scene/2d/navigation_2d.cpp @@ -92,7 +92,6 @@ void Navigation2D::_navpoly_link(int p_id) { if (!valid) { nm.polygons.pop_back(); ERR_CONTINUE(!valid); - continue; } p.center = center / plen; 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/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 8bccf117fd..f0c46a5fb7 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -33,6 +33,8 @@ #include "core/engine.h" #include "scene/resources/texture.h" +const float DEFAULT_GIZMO_EXTENTS = 10.0; + void Position2D::_draw_cross() { float extents = get_gizmo_extents(); diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h index dc9cc2df15..f5ec3ef01a 100644 --- a/scene/2d/position_2d.h +++ b/scene/2d/position_2d.h @@ -35,9 +35,7 @@ class Position2D : public Node2D { - GDCLASS(Position2D, Node2D) - - const float DEFAULT_GIZMO_EXTENTS = 10.0; + GDCLASS(Position2D, Node2D); void _draw_cross(); diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index d24c0a1561..0f48b44387 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -36,7 +36,7 @@ class Skeleton2D; class Bone2D : public Node2D { - GDCLASS(Bone2D, Node2D) + GDCLASS(Bone2D, Node2D); friend class Skeleton2D; #ifdef TOOLS_ENABLED 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 2b43861eea..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()) { @@ -220,11 +252,39 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const xform.elements[1].y = -xform.elements[1].y; offset.y = s.y - offset.y; } - - offset += cell_size / 2 - s / 2; + /* 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); + } + } + shape_idx++; +} + void TileMap::update_dirty_quadrants() { if (!pending_update) @@ -268,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) { @@ -372,10 +436,11 @@ void TileMap::update_dirty_quadrants() { 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; + rect.position += cell_size / 2 - rect.size / 2; */ } if (c.flip_h) { @@ -426,10 +491,7 @@ 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 assigned to the TileMap " + get_name() + " has an invalid convex shape."); @@ -437,10 +499,7 @@ void TileMap::update_dirty_quadrants() { } } } 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)); } } } @@ -615,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_set_state(q.body, Physics2DServer::BODY_STATE_TRANSFORM, xform); + 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); + } 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; @@ -640,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()); @@ -1134,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); + } } } @@ -1183,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); + } } } @@ -1201,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 { @@ -1403,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); @@ -1551,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); @@ -1586,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); @@ -1651,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"); @@ -1699,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; @@ -1709,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(); |