summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/animated_sprite_2d.cpp17
-rw-r--r--scene/2d/animated_sprite_2d.h7
-rw-r--r--scene/2d/area_2d.cpp1
-rw-r--r--scene/2d/audio_stream_player_2d.cpp404
-rw-r--r--scene/2d/audio_stream_player_2d.h35
-rw-r--r--scene/2d/camera_2d.cpp16
-rw-r--r--scene/2d/camera_2d.h1
-rw-r--r--scene/2d/collision_object_2d.cpp48
-rw-r--r--scene/2d/collision_object_2d.h12
-rw-r--r--scene/2d/collision_polygon_2d.cpp1
-rw-r--r--scene/2d/collision_polygon_2d.h1
-rw-r--r--scene/2d/collision_shape_2d.cpp6
-rw-r--r--scene/2d/cpu_particles_2d.cpp302
-rw-r--r--scene/2d/cpu_particles_2d.h62
-rw-r--r--scene/2d/gpu_particles_2d.cpp49
-rw-r--r--scene/2d/gpu_particles_2d.h44
-rw-r--r--scene/2d/joints_2d.cpp4
-rw-r--r--scene/2d/light_2d.cpp3
-rw-r--r--scene/2d/line_builder.cpp8
-rw-r--r--scene/2d/line_builder.h3
-rw-r--r--scene/2d/listener_2d.cpp112
-rw-r--r--scene/2d/listener_2d.h61
-rw-r--r--scene/2d/navigation_agent_2d.cpp9
-rw-r--r--scene/2d/navigation_agent_2d.h1
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp7
-rw-r--r--scene/2d/navigation_region_2d.cpp5
-rw-r--r--scene/2d/node_2d.cpp9
-rw-r--r--scene/2d/parallax_background.h2
-rw-r--r--scene/2d/parallax_layer.cpp1
-rw-r--r--scene/2d/path_2d.cpp2
-rw-r--r--scene/2d/physics_body_2d.cpp926
-rw-r--r--scene/2d/physics_body_2d.h175
-rw-r--r--scene/2d/position_2d.cpp3
-rw-r--r--scene/2d/ray_cast_2d.cpp31
-rw-r--r--scene/2d/ray_cast_2d.h4
-rw-r--r--scene/2d/remote_transform_2d.cpp1
-rw-r--r--scene/2d/skeleton_2d.cpp26
-rw-r--r--scene/2d/skeleton_2d.h18
-rw-r--r--scene/2d/sprite_2d.cpp1
-rw-r--r--scene/2d/tile_map.cpp106
-rw-r--r--scene/2d/tile_map.h10
-rw-r--r--scene/2d/touch_screen_button.cpp13
-rw-r--r--scene/2d/touch_screen_button.h2
-rw-r--r--scene/2d/visible_on_screen_notifier_2d.cpp6
44 files changed, 1497 insertions, 1058 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index da2ab6ada8..96a3134691 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -30,7 +30,6 @@
#include "animated_sprite_2d.h"
-#include "core/os/os.h"
#include "scene/main/viewport.h"
#include "scene/scene_string_names.h"
@@ -159,12 +158,12 @@ void AnimatedSprite2D::_notification(int p_what) {
return;
}
- float speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * speed_scale;
if (speed == 0) {
return; //do nothing
}
- float remaining = get_process_delta_time();
+ double remaining = get_process_delta_time();
while (remaining) {
if (timeout <= 0) {
@@ -205,7 +204,7 @@ void AnimatedSprite2D::_notification(int p_what) {
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
- float to_process = MIN(timeout, remaining);
+ double to_process = MIN(timeout, remaining);
remaining -= to_process;
timeout -= to_process;
}
@@ -310,8 +309,8 @@ int AnimatedSprite2D::get_frame() const {
return frame;
}
-void AnimatedSprite2D::set_speed_scale(float p_speed_scale) {
- float elapsed = _get_frame_duration() - timeout;
+void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
+ double elapsed = _get_frame_duration() - timeout;
speed_scale = MAX(p_speed_scale, 0.0f);
@@ -320,7 +319,7 @@ void AnimatedSprite2D::set_speed_scale(float p_speed_scale) {
timeout -= elapsed;
}
-float AnimatedSprite2D::get_speed_scale() const {
+double AnimatedSprite2D::get_speed_scale() const {
return speed_scale;
}
@@ -402,9 +401,9 @@ bool AnimatedSprite2D::is_playing() const {
return playing;
}
-float AnimatedSprite2D::_get_frame_duration() {
+double AnimatedSprite2D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- float speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * speed_scale;
if (speed > 0) {
return 1.0 / speed;
}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index ef0027edf1..ac4b20a6d9 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -33,7 +33,6 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/sprite_frames.h"
-#include "scene/resources/texture.h"
class AnimatedSprite2D : public Node2D {
GDCLASS(AnimatedSprite2D, Node2D);
@@ -56,7 +55,7 @@ class AnimatedSprite2D : public Node2D {
void _res_changed();
- float _get_frame_duration();
+ double _get_frame_duration();
void _reset_timeout();
void _set_playing(bool p_playing);
bool _is_playing() const;
@@ -94,8 +93,8 @@ public:
void set_frame(int p_frame);
int get_frame() const;
- void set_speed_scale(float p_speed_scale);
- float get_speed_scale() const;
+ void set_speed_scale(double p_speed_scale);
+ double get_speed_scale() const;
void set_centered(bool p_center);
bool is_centered() const;
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index cf84767151..d78b9847e6 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -32,7 +32,6 @@
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
-#include "servers/physics_server_2d.h"
void Area2D::set_space_override_mode(SpaceOverride p_mode) {
space_override = p_mode;
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 4b96689613..8401909384 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -30,129 +30,21 @@
#include "audio_stream_player_2d.h"
-#include "core/config/engine.h"
#include "scene/2d/area_2d.h"
+#include "scene/2d/listener_2d.h"
#include "scene/main/window.h"
-void AudioStreamPlayer2D::_mix_audio() {
- if (!stream_playback.is_valid() || !active.is_set() ||
- (stream_paused && !stream_paused_fade_out)) {
- return;
- }
-
- if (setseek.get() >= 0.0) {
- stream_playback->start(setseek.get());
- setseek.set(-1.0); //reset seek
- }
-
- //get data
- AudioFrame *buffer = mix_buffer.ptrw();
- int buffer_size = mix_buffer.size();
-
- if (stream_paused_fade_out) {
- // Short fadeout ramp
- buffer_size = MIN(buffer_size, 128);
- }
-
- stream_playback->mix(buffer, pitch_scale, buffer_size);
-
- //write all outputs
- int oc = output_count.get();
- for (int i = 0; i < oc; i++) {
- Output current = outputs[i];
-
- //see if current output exists, to keep volume ramp
- bool found = false;
- for (int j = i; j < prev_output_count; j++) {
- if (prev_outputs[j].viewport == current.viewport) {
- if (j != i) {
- SWAP(prev_outputs[j], prev_outputs[i]);
- }
- found = true;
- break;
- }
- }
-
- if (!found) {
- //create new if was not used before
- if (prev_output_count < MAX_OUTPUTS) {
- prev_outputs[prev_output_count] = prev_outputs[i]; //may be owned by another viewport
- prev_output_count++;
- }
- prev_outputs[i] = current;
- }
-
- //mix!
- AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol;
- AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol;
- AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = vol_prev;
-
- int cc = AudioServer::get_singleton()->get_channel_count();
-
- if (cc == 1) {
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, 0)) {
- continue; //may have been removed
- }
-
- AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 0);
-
- for (int j = 0; j < buffer_size; j++) {
- target[j] += buffer[j] * vol;
- vol += vol_inc;
- }
-
- } else {
- AudioFrame *targets[4];
- bool valid = true;
-
- for (int k = 0; k < cc; k++) {
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k)) {
- valid = false; //may have been removed
- break;
- }
-
- targets[k] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k);
- }
-
- if (!valid) {
- continue;
- }
-
- for (int j = 0; j < buffer_size; j++) {
- AudioFrame frame = buffer[j] * vol;
- for (int k = 0; k < cc; k++) {
- targets[k][j] += frame;
- }
- vol += vol_inc;
- }
- }
-
- prev_outputs[i] = current;
- }
-
- prev_output_count = oc;
-
- //stream is no longer active, disable this.
- if (!stream_playback->is_playing()) {
- active.clear();
- }
-
- output_ready.clear();
- stream_paused_fade_in = false;
- stream_paused_fade_out = false;
-}
-
void AudioStreamPlayer2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- AudioServer::get_singleton()->add_callback(_mix_audios, this);
+ AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this);
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
}
if (p_what == NOTIFICATION_EXIT_TREE) {
- AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+ stop();
+ AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
}
if (p_what == NOTIFICATION_PAUSED) {
@@ -168,120 +60,143 @@ void AudioStreamPlayer2D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
+ if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) {
+ _update_panning();
+ }
- if (!output_ready.is_set()) {
- Ref<World2D> world_2d = get_world_2d();
- ERR_FAIL_COND(world_2d.is_null());
-
- int new_output_count = 0;
-
- Vector2 global_pos = get_global_position();
-
- int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
-
- //check if any area is diverting sound into a bus
+ if (setplay.get() >= 0 && stream.is_valid()) {
+ active.set();
+ Ref<AudioStreamPlayback> new_playback = stream->instance_playback();
+ ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback.");
+ AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get());
+ stream_playbacks.push_back(new_playback);
+ setplay.set(-1);
+ }
- PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
+ if (!stream_playbacks.is_empty() && active.is_set()) {
+ // Stop playing if no longer active.
+ Vector<Ref<AudioStreamPlayback>> playbacks_to_remove;
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) {
+ emit_signal(SNAME("finished"));
+ playbacks_to_remove.push_back(playback);
+ }
+ }
+ // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble.
+ for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) {
+ stream_playbacks.erase(playback);
+ }
+ if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) {
+ // This node is no longer actively playing audio.
+ active.clear();
+ set_physics_process_internal(false);
+ }
+ }
- PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
+ while (stream_playbacks.size() > max_polyphony) {
+ AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]);
+ stream_playbacks.remove(0);
+ }
+ }
+}
- int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
+StringName AudioStreamPlayer2D::_get_actual_bus() {
+ Vector2 global_pos = get_global_position();
- for (int i = 0; i < areas; i++) {
- Area2D *area2d = Object::cast_to<Area2D>(sr[i].collider);
- if (!area2d) {
- continue;
- }
+ //check if any area is diverting sound into a bus
+ Ref<World2D> world_2d = get_world_2d();
+ ERR_FAIL_COND_V(world_2d.is_null(), SNAME("Master"));
- if (!area2d->is_overriding_audio_bus()) {
- continue;
- }
+ PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
+ PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
- StringName bus_name = area2d->get_audio_bus_name();
- bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
- break;
- }
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- const Set<Viewport *> viewports = world_2d->get_viewports();
+ for (int i = 0; i < areas; i++) {
+ Area2D *area2d = Object::cast_to<Area2D>(sr[i].collider);
+ if (!area2d) {
+ continue;
+ }
- for (Set<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
- Viewport *vp = E->get();
- if (vp->is_audio_listener_2d()) {
- //compute matrix to convert to screen
- Transform2D to_screen = vp->get_global_canvas_transform() * vp->get_canvas_transform();
- Vector2 screen_size = vp->get_visible_rect().size;
+ if (!area2d->is_overriding_audio_bus()) {
+ continue;
+ }
- //screen in global is used for attenuation
- Vector2 screen_in_global = to_screen.affine_inverse().xform(screen_size * 0.5);
+ return area2d->get_audio_bus_name();
+ }
+ return default_bus;
+}
- float dist = global_pos.distance_to(screen_in_global); //distance to screen center
+void AudioStreamPlayer2D::_update_panning() {
+ if (!active.is_set() || stream.is_null()) {
+ return;
+ }
- if (dist > max_distance) {
- continue; //can't hear this sound in this viewport
- }
+ Ref<World2D> world_2d = get_world_2d();
+ ERR_FAIL_COND(world_2d.is_null());
- float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
- multiplier *= Math::db2linear(volume_db); //also apply player volume!
+ Vector2 global_pos = get_global_position();
- //point in screen is used for panning
- Vector2 point_in_screen = to_screen.xform(global_pos);
+ Set<Viewport *> viewports = world_2d->get_viewports();
+ viewports.insert(get_viewport()); // TODO: This is a mediocre workaround for #50958. Remove when that bug is fixed!
- float pan = CLAMP(point_in_screen.x / screen_size.width, 0.0, 1.0);
+ volume_vector.resize(4);
+ volume_vector.write[0] = AudioFrame(0, 0);
+ volume_vector.write[1] = AudioFrame(0, 0);
+ volume_vector.write[2] = AudioFrame(0, 0);
+ volume_vector.write[3] = AudioFrame(0, 0);
- float l = 1.0 - pan;
- float r = pan;
+ for (Viewport *vp : viewports) {
+ if (!vp->is_audio_listener_2d()) {
+ continue;
+ }
+ //compute matrix to convert to screen
+ Vector2 screen_size = vp->get_visible_rect().size;
+ Vector2 listener_in_global;
+ Vector2 relative_to_listener;
+
+ //screen in global is used for attenuation
+ Listener2D *listener = vp->get_listener_2d();
+ if (listener) {
+ listener_in_global = listener->get_global_position();
+ relative_to_listener = global_pos - listener_in_global;
+ } else {
+ Transform2D to_listener = vp->get_global_canvas_transform() * vp->get_canvas_transform();
+ listener_in_global = to_listener.affine_inverse().xform(screen_size * 0.5);
+ relative_to_listener = to_listener.xform(global_pos) - screen_size * 0.5;
+ }
- outputs[new_output_count].vol = AudioFrame(l, r) * multiplier;
- outputs[new_output_count].bus_index = bus_index;
- outputs[new_output_count].viewport = vp; //keep pointer only for reference
- new_output_count++;
- if (new_output_count == MAX_OUTPUTS) {
- break;
- }
- }
- }
+ float dist = global_pos.distance_to(listener_in_global); // Distance to listener, or screen if none.
- output_count.set(new_output_count);
- output_ready.set();
+ if (dist > max_distance) {
+ continue; //can't hear this sound in this viewport
}
- //start playing if requested
- if (setplay.get() >= 0.0) {
- setseek.set(setplay.get());
- active.set();
- setplay.set(-1);
- }
+ float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
+ multiplier *= Math::db2linear(volume_db); //also apply player volume!
- //stop playing if no longer active
- if (!active.is_set()) {
- set_physics_process_internal(false);
- emit_signal(SNAME("finished"));
- }
- }
-}
+ float pan = CLAMP((relative_to_listener.x + screen_size.x * 0.5) / screen_size.x, 0.0, 1.0);
-void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
- AudioServer::get_singleton()->lock();
+ float l = 1.0 - pan;
+ float r = pan;
- mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
+ volume_vector.write[0] = AudioFrame(l, r) * multiplier;
+ }
- if (stream_playback.is_valid()) {
- stream_playback.unref();
- stream.unref();
- active.clear();
- setseek.set(-1);
+ for (const Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_bus_exclusive(playback, _get_actual_bus(), volume_vector);
}
- if (p_stream.is_valid()) {
- stream = p_stream;
- stream_playback = p_stream->instance_playback();
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_pitch_scale(playback, pitch_scale);
}
- AudioServer::get_singleton()->unlock();
+ last_mix_count = AudioServer::get_singleton()->get_mix_count();
+}
- if (p_stream.is_valid() && stream_playback.is_null()) {
- stream.unref();
- }
+void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
+ stop();
+ stream = p_stream;
}
Ref<AudioStream> AudioStreamPlayer2D::get_stream() const {
@@ -299,6 +214,9 @@ float AudioStreamPlayer2D::get_volume_db() const {
void AudioStreamPlayer2D::set_pitch_scale(float p_pitch_scale) {
ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_pitch_scale(playback, p_pitch_scale);
+ }
}
float AudioStreamPlayer2D::get_pitch_scale() const {
@@ -306,66 +224,64 @@ float AudioStreamPlayer2D::get_pitch_scale() const {
}
void AudioStreamPlayer2D::play(float p_from_pos) {
- if (!is_playing()) {
- // Reset the prev_output_count if the stream is stopped
- prev_output_count = 0;
+ if (stream.is_null()) {
+ return;
}
-
- if (stream_playback.is_valid()) {
- setplay.set(p_from_pos);
- output_ready.clear();
- set_physics_process_internal(true);
+ ERR_FAIL_COND_MSG(!is_inside_tree(), "Playback can only happen when a node is inside the scene tree");
+ if (stream->is_monophonic() && is_playing()) {
+ stop();
}
+
+ setplay.set(p_from_pos);
+ active.set();
+ set_physics_process_internal(true);
}
void AudioStreamPlayer2D::seek(float p_seconds) {
- if (stream_playback.is_valid()) {
- setseek.set(p_seconds);
+ if (is_playing()) {
+ stop();
+ play(p_seconds);
}
}
void AudioStreamPlayer2D::stop() {
- if (stream_playback.is_valid()) {
- active.clear();
- set_physics_process_internal(false);
- setplay.set(-1);
+ setplay.set(-1);
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->stop_playback_stream(playback);
}
+ stream_playbacks.clear();
+ active.clear();
+ set_physics_process_internal(false);
}
bool AudioStreamPlayer2D::is_playing() const {
- if (stream_playback.is_valid()) {
- return active.is_set() || setplay.get() >= 0;
+ for (const Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ if (AudioServer::get_singleton()->is_playback_active(playback)) {
+ return true;
+ }
}
-
return false;
}
float AudioStreamPlayer2D::get_playback_position() {
- if (stream_playback.is_valid()) {
- float ss = setseek.get();
- if (ss >= 0.0) {
- return ss;
- }
- return stream_playback->get_playback_position();
+ // Return the playback position of the most recently started playback stream.
+ if (!stream_playbacks.is_empty()) {
+ return AudioServer::get_singleton()->get_playback_position(stream_playbacks[stream_playbacks.size() - 1]);
}
-
return 0;
}
void AudioStreamPlayer2D::set_bus(const StringName &p_bus) {
- //if audio is active, must lock this
- AudioServer::get_singleton()->lock();
- bus = p_bus;
- AudioServer::get_singleton()->unlock();
+ default_bus = p_bus; // This will be pushed to the audio server during the next physics timestep, which is fast enough.
}
StringName AudioStreamPlayer2D::get_bus() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
- if (AudioServer::get_singleton()->get_bus_name(i) == bus) {
- return bus;
+ if (AudioServer::get_singleton()->get_bus_name(i) == default_bus) {
+ return default_bus;
}
}
- return "Master";
+ return SNAME("Master");
}
void AudioStreamPlayer2D::set_autoplay(bool p_enable) {
@@ -433,19 +349,35 @@ uint32_t AudioStreamPlayer2D::get_area_mask() const {
}
void AudioStreamPlayer2D::set_stream_paused(bool p_pause) {
- if (p_pause != stream_paused) {
- stream_paused = p_pause;
- stream_paused_fade_in = !p_pause;
- stream_paused_fade_out = p_pause;
+ // TODO this does not have perfect recall, fix that maybe? If there are zero playbacks registered with the AudioServer, this bool isn't persisted.
+ for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
+ AudioServer::get_singleton()->set_playback_paused(playback, p_pause);
}
}
bool AudioStreamPlayer2D::get_stream_paused() const {
- return stream_paused;
+ // There's currently no way to pause some playback streams but not others. Check the first and don't bother looking at the rest.
+ if (!stream_playbacks.is_empty()) {
+ return AudioServer::get_singleton()->is_playback_paused(stream_playbacks[0]);
+ }
+ return false;
}
Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
- return stream_playback;
+ if (!stream_playbacks.is_empty()) {
+ return stream_playbacks[stream_playbacks.size() - 1];
+ }
+ return nullptr;
+}
+
+void AudioStreamPlayer2D::set_max_polyphony(int p_max_polyphony) {
+ if (p_max_polyphony > 0) {
+ max_polyphony = p_max_polyphony;
+ }
+}
+
+int AudioStreamPlayer2D::get_max_polyphony() const {
+ return max_polyphony;
}
void AudioStreamPlayer2D::_bind_methods() {
@@ -486,6 +418,9 @@ void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer2D::set_stream_paused);
ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer2D::get_stream_paused);
+ ClassDB::bind_method(D_METHOD("set_max_polyphony", "max_polyphony"), &AudioStreamPlayer2D::set_max_polyphony);
+ ClassDB::bind_method(D_METHOD("get_max_polyphony"), &AudioStreamPlayer2D::get_max_polyphony);
+
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
@@ -496,6 +431,7 @@ void AudioStreamPlayer2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index 21f524c703..5360fd4934 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -31,7 +31,6 @@
#ifndef AUDIO_STREAM_PLAYER_2D_H
#define AUDIO_STREAM_PLAYER_2D_H
-#include "core/templates/safe_refcount.h"
#include "scene/2d/node_2d.h"
#include "servers/audio/audio_stream.h"
#include "servers/audio_server.h"
@@ -52,38 +51,31 @@ private:
Viewport *viewport = nullptr; //pointer only used for reference to previous mix
};
- Output outputs[MAX_OUTPUTS];
- SafeNumeric<int> output_count;
- SafeFlag output_ready;
-
- //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
- Output prev_outputs[MAX_OUTPUTS];
- int prev_output_count = 0;
-
- Ref<AudioStreamPlayback> stream_playback;
+ Vector<Ref<AudioStreamPlayback>> stream_playbacks;
Ref<AudioStream> stream;
- Vector<AudioFrame> mix_buffer;
- SafeNumeric<float> setseek{ -1.0 };
- SafeFlag active;
+ SafeFlag active{ false };
SafeNumeric<float> setplay{ -1.0 };
+ Vector<AudioFrame> volume_vector;
+
+ uint64_t last_mix_count = -1;
+
float volume_db = 0.0;
float pitch_scale = 1.0;
bool autoplay = false;
- bool stream_paused = false;
- bool stream_paused_fade_in = false;
- bool stream_paused_fade_out = false;
- StringName bus;
-
- void _mix_audio();
- static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->_mix_audio(); }
+ StringName default_bus = SNAME("Master");
+ int max_polyphony = 1;
void _set_playing(bool p_enable);
bool _is_active() const;
+ StringName _get_actual_bus();
+ void _update_panning();
void _bus_layout_changed();
+ static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->_update_panning(); }
+
uint32_t area_mask = 1;
float max_distance = 2000.0;
@@ -128,6 +120,9 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ void set_max_polyphony(int p_max_polyphony);
+ int get_max_polyphony() const;
+
Ref<AudioStreamPlayback> get_stream_playback();
AudioStreamPlayer2D();
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 2219437c14..bf91ce8e65 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -30,10 +30,7 @@
#include "camera_2d.h"
-#include "core/config/engine.h"
-#include "core/math/math_funcs.h"
-#include "scene/scene_string_names.h"
-#include "servers/rendering_server.h"
+#include "scene/main/window.h"
void Camera2D::_update_scroll() {
if (!is_inside_tree()) {
@@ -99,7 +96,7 @@ Transform2D Camera2D::get_camera_transform() {
Size2 screen_size = _get_camera_screen_size();
- Point2 new_camera_pos = get_global_transform().get_origin();
+ Point2 new_camera_pos = get_global_position();
Point2 ret_camera_pos;
if (!first) {
@@ -172,7 +169,7 @@ Transform2D Camera2D::get_camera_transform() {
Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());
- real_t angle = get_global_transform().get_rotation();
+ real_t angle = get_global_rotation();
if (rotating) {
screen_offset = screen_offset.rotated(angle);
}
@@ -264,6 +261,7 @@ void Camera2D::_notification(int p_what) {
if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
viewport->set_canvas_transform(Transform2D());
clear_current();
+ current = true;
}
}
remove_from_group(group_name);
@@ -308,8 +306,8 @@ void Camera2D::_notification(int p_what) {
limit_drawing_width = 3;
}
- Vector2 camera_origin = get_global_transform().get_origin();
- Vector2 camera_scale = get_global_transform().get_scale().abs();
+ Vector2 camera_origin = get_global_position();
+ Vector2 camera_scale = get_global_scale().abs();
Vector2 limit_points[4] = {
(Vector2(limit[SIDE_LEFT], limit[SIDE_TOP]) - camera_origin) / camera_scale,
(Vector2(limit[SIDE_RIGHT], limit[SIDE_TOP]) - camera_origin) / camera_scale,
@@ -492,7 +490,7 @@ void Camera2D::align() {
Size2 screen_size = _get_camera_screen_size();
- Point2 current_camera_pos = get_global_transform().get_origin();
+ Point2 current_camera_pos = get_global_position();
if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {
if (drag_horizontal_offset < 0) {
camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[SIDE_RIGHT] * drag_horizontal_offset;
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 95b49cf076..d697515547 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -32,7 +32,6 @@
#define CAMERA_2D_H
#include "scene/2d/node_2d.h"
-#include "scene/main/window.h"
class Camera2D : public Node2D {
GDCLASS(Camera2D, Node2D);
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 3ba3a4eec5..5d3a538f60 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -147,36 +147,40 @@ uint32_t CollisionObject2D::get_collision_mask() const {
return collision_mask;
}
-void CollisionObject2D::set_collision_layer_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision layer bit must be between 0 and 31 inclusive.");
+void CollisionObject2D::set_collision_layer_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t collision_layer = get_collision_layer();
if (p_value) {
- collision_layer |= 1 << p_bit;
+ collision_layer |= 1 << (p_layer_number - 1);
} else {
- collision_layer &= ~(1 << p_bit);
+ collision_layer &= ~(1 << (p_layer_number - 1));
}
set_collision_layer(collision_layer);
}
-bool CollisionObject2D::get_collision_layer_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision layer bit must be between 0 and 31 inclusive.");
- return get_collision_layer() & (1 << p_bit);
+bool CollisionObject2D::get_collision_layer_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void CollisionObject2D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void CollisionObject2D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool CollisionObject2D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool CollisionObject2D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
void CollisionObject2D::set_disable_mode(DisableMode p_mode) {
@@ -477,10 +481,8 @@ bool CollisionObject2D::is_pickable() const {
return pickable;
}
-void CollisionObject2D::_input_event(Node *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape) {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_viewport, p_input_event, p_shape);
- }
+void CollisionObject2D::_input_event_call(Viewport *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape) {
+ GDVIRTUAL_CALL(_input_event, p_viewport, p_input_event, p_shape);
emit_signal(SceneStringNames::get_singleton()->input_event, p_viewport, p_input_event, p_shape);
}
@@ -565,10 +567,10 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer"), &CollisionObject2D::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &CollisionObject2D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &CollisionObject2D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_layer_bit", "bit", "value"), &CollisionObject2D::set_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject2D::get_collision_layer_bit);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject2D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CollisionObject2D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject2D::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject2D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject2D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
@@ -593,7 +595,7 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject2D::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject2D::shape_find_owner);
- BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "viewport"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
+ GDVIRTUAL_BIND(_input_event, "viewport", "event", "shape_idx");
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index eca53eecfc..19abacb201 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -32,6 +32,7 @@
#define COLLISION_OBJECT_2D_H
#include "scene/2d/node_2d.h"
+#include "scene/main/viewport.h"
#include "scene/resources/shape_2d.h"
#include "servers/physics_server_2d.h"
@@ -88,7 +89,7 @@ protected:
void _update_pickable();
friend class Viewport;
- void _input_event(Node *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape);
+ void _input_event_call(Viewport *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape);
void _mouse_enter();
void _mouse_exit();
@@ -100,6 +101,7 @@ protected:
void set_body_mode(PhysicsServer2D::BodyMode p_mode);
+ GDVIRTUAL3(_input_event, Viewport *, Ref<InputEvent>, int)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
@@ -107,11 +109,11 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_layer_bit(int p_bit, bool p_value);
- bool get_collision_layer_bit(int p_bit) const;
+ void set_collision_layer_value(int p_layer_number, bool p_value);
+ bool get_collision_layer_value(int p_layer_number) const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 2a2fde80e2..8c8a292ad7 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -31,7 +31,6 @@
#include "collision_polygon_2d.h"
#include "collision_object_2d.h"
-#include "core/config/engine.h"
#include "core/math/geometry_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index 95dd8c9e21..6b32923010 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -32,7 +32,6 @@
#define COLLISION_POLYGON_2D_H
#include "scene/2d/node_2d.h"
-#include "scene/resources/shape_2d.h"
class CollisionObject2D;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 60780f1cc3..d52795f0d5 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -31,14 +31,8 @@
#include "collision_shape_2d.h"
#include "collision_object_2d.h"
-#include "core/config/engine.h"
-#include "scene/resources/capsule_shape_2d.h"
-#include "scene/resources/circle_shape_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
-#include "scene/resources/line_shape_2d.h"
-#include "scene/resources/rectangle_shape_2d.h"
-#include "scene/resources/segment_shape_2d.h"
void CollisionShape2D::_shape_changed() {
update();
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index a341ba69ac..b836497627 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -32,9 +32,7 @@
#include "core/core_string_names.h"
#include "scene/2d/gpu_particles_2d.h"
-#include "scene/main/canvas_item.h"
#include "scene/resources/particles_material.h"
-#include "servers/rendering_server.h"
void CPUParticles2D::set_emitting(bool p_emitting) {
if (emitting == p_emitting) {
@@ -65,7 +63,7 @@ void CPUParticles2D::set_amount(int p_amount) {
particle_order.resize(p_amount);
}
-void CPUParticles2D::set_lifetime(float p_lifetime) {
+void CPUParticles2D::set_lifetime(double p_lifetime) {
ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
}
@@ -74,7 +72,7 @@ void CPUParticles2D::set_one_shot(bool p_one_shot) {
one_shot = p_one_shot;
}
-void CPUParticles2D::set_pre_process_time(float p_time) {
+void CPUParticles2D::set_pre_process_time(double p_time) {
pre_process_time = p_time;
}
@@ -86,7 +84,7 @@ void CPUParticles2D::set_randomness_ratio(real_t p_ratio) {
randomness_ratio = p_ratio;
}
-void CPUParticles2D::set_lifetime_randomness(float p_random) {
+void CPUParticles2D::set_lifetime_randomness(double p_random) {
lifetime_randomness = p_random;
}
@@ -95,7 +93,7 @@ void CPUParticles2D::set_use_local_coordinates(bool p_enable) {
set_notify_transform(!p_enable);
}
-void CPUParticles2D::set_speed_scale(real_t p_scale) {
+void CPUParticles2D::set_speed_scale(double p_scale) {
speed_scale = p_scale;
}
@@ -107,7 +105,7 @@ int CPUParticles2D::get_amount() const {
return particles.size();
}
-float CPUParticles2D::get_lifetime() const {
+double CPUParticles2D::get_lifetime() const {
return lifetime;
}
@@ -115,7 +113,7 @@ bool CPUParticles2D::get_one_shot() const {
return one_shot;
}
-float CPUParticles2D::get_pre_process_time() const {
+double CPUParticles2D::get_pre_process_time() const {
return pre_process_time;
}
@@ -127,7 +125,7 @@ real_t CPUParticles2D::get_randomness_ratio() const {
return randomness_ratio;
}
-float CPUParticles2D::get_lifetime_randomness() const {
+double CPUParticles2D::get_lifetime_randomness() const {
return lifetime_randomness;
}
@@ -135,7 +133,7 @@ bool CPUParticles2D::get_use_local_coordinates() const {
return local_coords;
}
-real_t CPUParticles2D::get_speed_scale() const {
+double CPUParticles2D::get_speed_scale() const {
return speed_scale;
}
@@ -250,7 +248,7 @@ TypedArray<String> CPUParticles2D::get_configuration_warnings() const {
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
- if (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
+ if (get_param_max(PARAM_ANIM_SPEED) != 0.0 || get_param_max(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) {
warnings.push_back(TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
@@ -294,28 +292,34 @@ real_t CPUParticles2D::get_spread() const {
return spread;
}
-void CPUParticles2D::set_param(Parameter p_param, real_t p_value) {
+void CPUParticles2D::set_param_min(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- parameters[p_param] = p_value;
+ parameters_min[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_max(p_param, p_value);
+ }
}
-real_t CPUParticles2D::get_param(Parameter p_param) const {
+real_t CPUParticles2D::get_param_min(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return parameters[p_param];
+ return parameters_min[p_param];
}
-void CPUParticles2D::set_param_randomness(Parameter p_param, real_t p_value) {
+void CPUParticles2D::set_param_max(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- randomness[p_param] = p_value;
+ parameters_max[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_min(p_param, p_value);
+ }
}
-real_t CPUParticles2D::get_param_randomness(Parameter p_param) const {
+real_t CPUParticles2D::get_param_max(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return randomness[p_param];
+ return parameters_max[p_param];
}
static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
@@ -462,6 +466,31 @@ Vector2 CPUParticles2D::get_gravity() const {
return gravity;
}
+void CPUParticles2D::set_scale_curve_x(Ref<Curve> p_scale_curve) {
+ scale_curve_x = p_scale_curve;
+}
+
+void CPUParticles2D::set_scale_curve_y(Ref<Curve> p_scale_curve) {
+ scale_curve_y = p_scale_curve;
+}
+
+void CPUParticles2D::set_split_scale(bool p_split_scale) {
+ split_scale = p_split_scale;
+ notify_property_list_changed();
+}
+
+Ref<Curve> CPUParticles2D::get_scale_curve_x() const {
+ return scale_curve_x;
+}
+
+Ref<Curve> CPUParticles2D::get_scale_curve_y() const {
+ return scale_curve_y;
+}
+
+bool CPUParticles2D::get_split_scale() {
+ return split_scale;
+}
+
void CPUParticles2D::_validate_property(PropertyInfo &property) const {
if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
property.usage = PROPERTY_USAGE_NONE;
@@ -486,6 +515,9 @@ 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 = PROPERTY_USAGE_NONE;
}
+ if (property.name.begins_with("scale_curve_") && !split_scale) {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
}
static uint32_t idhash(uint32_t x) {
@@ -516,7 +548,7 @@ void CPUParticles2D::_update_internal() {
return;
}
- float delta = get_process_delta_time();
+ double delta = get_process_delta_time();
if (emitting) {
inactive_time = 0;
} else {
@@ -536,14 +568,14 @@ void CPUParticles2D::_update_internal() {
_set_redraw(true);
if (time == 0 && pre_process_time > 0.0) {
- float frame_time;
+ double frame_time;
if (fixed_fps > 0) {
frame_time = 1.0 / fixed_fps;
} else {
frame_time = 1.0 / 30.0;
}
- float todo = pre_process_time;
+ double todo = pre_process_time;
while (todo >= 0) {
_particles_process(frame_time);
@@ -552,16 +584,16 @@ void CPUParticles2D::_update_internal() {
}
if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
+ double frame_time = 1.0 / fixed_fps;
+ double decr = frame_time;
- float ldelta = delta;
+ double ldelta = delta;
if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
ldelta = 0.1;
} else if (ldelta <= 0.0) { //unlikely but..
ldelta = 0.001;
}
- float todo = frame_remainder + ldelta;
+ double todo = frame_remainder + ldelta;
while (todo >= frame_time) {
_particles_process(frame_time);
@@ -577,7 +609,7 @@ void CPUParticles2D::_update_internal() {
_update_particle_data_buffer();
}
-void CPUParticles2D::_particles_process(float p_delta) {
+void CPUParticles2D::_particles_process(double p_delta) {
p_delta *= speed_scale;
int pcount = particles.size();
@@ -585,7 +617,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
Particle *parray = w;
- float prev_time = time;
+ double prev_time = time;
time += p_delta;
if (time > lifetime) {
time = Math::fmod(time, lifetime);
@@ -604,7 +636,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
velocity_xform[2] = Vector2();
}
- float system_phase = time / lifetime;
+ double system_phase = time / lifetime;
for (int i = 0; i < pcount; i++) {
Particle &p = parray[i];
@@ -613,12 +645,12 @@ void CPUParticles2D::_particles_process(float p_delta) {
continue;
}
- float local_delta = p_delta;
+ double 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.
- real_t restart_phase = real_t(i) / real_t(pcount);
+ double restart_phase = double(i) / double(pcount);
if (randomness_ratio > 0.0) {
uint32_t seed = cycle;
@@ -627,12 +659,12 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
seed *= uint32_t(pcount);
seed += uint32_t(i);
- real_t random = (idhash(seed) % uint32_t(65536)) / 65536.0;
- restart_phase += randomness_ratio * random * 1.0 / pcount;
+ double random = double(idhash(seed) % uint32_t(65536)) / 65536.0;
+ restart_phase += randomness_ratio * random * 1.0 / double(pcount);
}
restart_phase *= (1.0 - explosiveness_ratio);
- float restart_time = restart_phase * lifetime;
+ double restart_time = restart_phase * lifetime;
bool restart = false;
if (time > prev_time) {
@@ -697,14 +729,14 @@ void CPUParticles2D::_particles_process(float p_delta) {
real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
- p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], Math::randf());
- real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
+ real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
p.rotation = Math::deg2rad(base_angle);
p.custom[0] = 0.0; // unused
p.custom[1] = 0.0; // phase [0..1]
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand);
p.custom[3] = 0.0;
p.transform = Transform2D();
p.time = 0;
@@ -768,51 +800,51 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.custom[1] = p.time / lifetime;
tv = p.time / p.lifetime;
- real_t tex_linear_velocity = 0.0;
+ real_t tex_linear_velocity = 1.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv);
}
- real_t tex_orbit_velocity = 0.0;
+ real_t tex_orbit_velocity = 1.0;
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv);
}
- real_t tex_angular_velocity = 0.0;
+ real_t tex_angular_velocity = 1.0;
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv);
}
- real_t tex_linear_accel = 0.0;
+ real_t tex_linear_accel = 1.0;
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv);
}
- real_t tex_tangential_accel = 0.0;
+ real_t tex_tangential_accel = 1.0;
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv);
}
- real_t tex_radial_accel = 0.0;
+ real_t tex_radial_accel = 1.0;
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv);
}
- real_t tex_damping = 0.0;
+ real_t tex_damping = 1.0;
if (curve_parameters[PARAM_DAMPING].is_valid()) {
tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv);
}
- real_t tex_angle = 0.0;
+ real_t tex_angle = 1.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- real_t tex_anim_speed = 0.0;
+ real_t tex_anim_speed = 1.0;
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv);
}
- real_t tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 1.0;
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv);
}
@@ -821,18 +853,18 @@ void CPUParticles2D::_particles_process(float p_delta) {
Vector2 pos = p.transform[2];
//apply linear acceleration
- force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2();
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * tex_linear_accel * Math::lerp(parameters_min[PARAM_LINEAR_ACCEL], parameters_max[PARAM_LINEAR_ACCEL], rand_from_seed(alt_seed)) : Vector2();
//apply radial acceleration
Vector2 org = emission_xform[2];
Vector2 diff = pos - org;
- force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2();
+ force += diff.length() > 0.0 ? diff.normalized() * (tex_radial_accel)*Math::lerp(parameters_min[PARAM_RADIAL_ACCEL], parameters_max[PARAM_RADIAL_ACCEL], rand_from_seed(alt_seed)) : Vector2();
//apply tangential acceleration;
Vector2 yx = Vector2(diff.y, diff.x);
- force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2();
+ force += yx.length() > 0.0 ? yx.normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector2();
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
- real_t orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
+ real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
if (orbit_amount != 0.0) {
real_t ang = orbit_amount * local_delta * Math_TAU;
// Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
@@ -845,9 +877,9 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.velocity = p.velocity.normalized() * tex_linear_velocity;
}
- if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
+ if (parameters_max[PARAM_DAMPING] + tex_damping > 0.0) {
real_t v = p.velocity.length();
- real_t damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+ real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(alt_seed));
v -= damp * local_delta;
if (v < 0.0) {
p.velocity = Vector2();
@@ -855,18 +887,32 @@ void CPUParticles2D::_particles_process(float p_delta) {
p.velocity = p.velocity.normalized() * v;
}
}
- real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
- base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
+ base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
p.rotation = Math::deg2rad(base_angle); //angle
- real_t animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
- p.custom[2] = animation_phase;
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + p.custom[1] * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed));
}
//apply color
//apply hue rotation
- real_t tex_scale = 1.0;
- if (curve_parameters[PARAM_SCALE].is_valid()) {
- tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ Vector2 tex_scale = Vector2(1.0, 1.0);
+ if (split_scale) {
+ if (scale_curve_x.is_valid()) {
+ tex_scale.x = scale_curve_x->interpolate(tv);
+ } else {
+ tex_scale.x = 1.0;
+ }
+ if (scale_curve_y.is_valid()) {
+ tex_scale.y = scale_curve_y->interpolate(tv);
+ } else {
+ tex_scale.y = 1.0;
+ }
+ } else {
+ if (curve_parameters[PARAM_SCALE].is_valid()) {
+ real_t tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ tex_scale.x = tmp_scale;
+ tex_scale.y = tmp_scale;
+ }
}
real_t tex_hue_variation = 0.0;
@@ -874,7 +920,7 @@ void CPUParticles2D::_particles_process(float p_delta) {
tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
}
- real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
+ real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand);
real_t hue_rot_c = Math::cos(hue_rot_angle);
real_t hue_rot_s = Math::sin(hue_rot_angle);
@@ -914,13 +960,15 @@ void CPUParticles2D::_particles_process(float p_delta) {
}
//scale by scale
- real_t base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], (real_t)1.0, p.scale_rand * randomness[PARAM_SCALE]);
- if (base_scale < 0.000001) {
- base_scale = 0.000001;
+ Vector2 base_scale = tex_scale * Math::lerp(parameters_min[PARAM_SCALE], parameters_max[PARAM_SCALE], p.scale_rand);
+ if (base_scale.x < 0.00001) {
+ base_scale.x = 0.00001;
}
-
- p.transform.elements[0] *= base_scale;
- p.transform.elements[1] *= base_scale;
+ if (base_scale.y < 0.00001) {
+ base_scale.y = 0.00001;
+ }
+ p.transform.elements[0] *= base_scale.x;
+ p.transform.elements[1] *= base_scale.y;
p.transform[2] += p.velocity * local_delta;
}
@@ -1132,18 +1180,24 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y);
set_emission_rect_extents(rect_extents);
+ Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE);
+ if (scale3D.is_valid()) {
+ split_scale = true;
+ scale_curve_x = scale3D->get_curve_x();
+ scale_curve_y = scale3D->get_curve_y();
+ }
Vector2 gravity = Vector2(material->get_gravity().x, material->get_gravity().y);
set_gravity(gravity);
set_lifetime_randomness(material->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
- set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
+ set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \
{ \
Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
if (ctex.is_valid()) \
set_param_curve(m_param, ctex->get_curve()); \
} \
- set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
+ set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param));
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
@@ -1226,11 +1280,11 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles2D::set_spread);
ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles2D::get_spread);
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles2D::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles2D::get_param);
+ ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &CPUParticles2D::set_param_min);
+ ClassDB::bind_method(D_METHOD("get_param_min", "param"), &CPUParticles2D::get_param_min);
- ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles2D::set_param_randomness);
- ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles2D::get_param_randomness);
+ ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &CPUParticles2D::set_param_max);
+ ClassDB::bind_method(D_METHOD("get_param_max", "param"), &CPUParticles2D::get_param_max);
ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles2D::set_param_curve);
ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles2D::get_param_curve);
@@ -1265,6 +1319,15 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles2D::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles2D::set_gravity);
+ ClassDB::bind_method(D_METHOD("get_split_scale"), &CPUParticles2D::get_split_scale);
+ ClassDB::bind_method(D_METHOD("set_split_scale", "split_scale"), &CPUParticles2D::set_split_scale);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_x"), &CPUParticles2D::get_scale_curve_x);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_x", "scale_curve"), &CPUParticles2D::set_scale_curve_x);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_y"), &CPUParticles2D::get_scale_curve_y);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_y", "scale_curve"), &CPUParticles2D::set_scale_curve_y);
+
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles);
ADD_GROUP("Emission Shape", "emission_");
@@ -1282,54 +1345,58 @@ void CPUParticles2D::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", 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::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", 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::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "split_scale"), "set_split_scale", "get_split_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_x", "get_scale_curve_x");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_y", "get_scale_curve_y");
+
ADD_GROUP("Color", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
ADD_GROUP("Hue Variation", "hue_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
@@ -1368,22 +1435,31 @@ CPUParticles2D::CPUParticles2D() {
set_amount(8);
set_use_local_coordinates(true);
- 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);
- set_param(PARAM_ANGLE, 0);
- set_param(PARAM_SCALE, 1);
- set_param(PARAM_HUE_VARIATION, 0);
- set_param(PARAM_ANIM_SPEED, 0);
- set_param(PARAM_ANIM_OFFSET, 0);
-
- for (int i = 0; i < PARAM_MAX; i++) {
- set_param_randomness(Parameter(i), 0);
- }
+ set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_min(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_min(PARAM_ORBIT_VELOCITY, 0);
+ set_param_min(PARAM_LINEAR_ACCEL, 0);
+ set_param_min(PARAM_RADIAL_ACCEL, 0);
+ set_param_min(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_min(PARAM_DAMPING, 0);
+ set_param_min(PARAM_ANGLE, 0);
+ set_param_min(PARAM_SCALE, 1);
+ set_param_min(PARAM_HUE_VARIATION, 0);
+ set_param_min(PARAM_ANIM_SPEED, 0);
+ set_param_min(PARAM_ANIM_OFFSET, 0);
+
+ set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_max(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_max(PARAM_ORBIT_VELOCITY, 0);
+ set_param_max(PARAM_LINEAR_ACCEL, 0);
+ set_param_max(PARAM_RADIAL_ACCEL, 0);
+ set_param_max(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_max(PARAM_DAMPING, 0);
+ set_param_max(PARAM_ANGLE, 0);
+ set_param_max(PARAM_SCALE, 1);
+ set_param_max(PARAM_HUE_VARIATION, 0);
+ set_param_max(PARAM_ANIM_SPEED, 0);
+ set_param_max(PARAM_ANIM_OFFSET, 0);
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
particle_flags[i] = false;
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 92b8be77cf..4990d443e3 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -31,9 +31,7 @@
#ifndef CPU_PARTICLES_2D_H
#define CPU_PARTICLES_2D_H
-#include "core/templates/rid.h"
#include "scene/2d/node_2d.h"
-#include "scene/resources/texture.h"
class CPUParticles2D : public Node2D {
private:
@@ -83,7 +81,7 @@ private:
struct Particle {
Transform2D transform;
Color color;
- float custom[4] = {};
+ real_t custom[4] = {};
real_t rotation = 0.0;
Vector2 velocity;
bool active = false;
@@ -91,16 +89,16 @@ private:
real_t scale_rand = 0.0;
real_t hue_rot_rand = 0.0;
real_t anim_offset_rand = 0.0;
- float time = 0.0;
- float lifetime = 0.0;
+ double time = 0.0;
+ double lifetime = 0.0;
Color base_color;
uint32_t seed = 0;
};
- float time = 0.0;
- float inactive_time = 0.0;
- float frame_remainder = 0.0;
+ double time = 0.0;
+ double inactive_time = 0.0;
+ double frame_remainder = 0.0;
int cycle = 0;
bool redraw = false;
@@ -131,12 +129,12 @@ private:
bool one_shot = false;
- float lifetime = 1.0;
- float pre_process_time = 0.0;
+ double lifetime = 1.0;
+ double pre_process_time = 0.0;
real_t explosiveness_ratio = 0.0;
real_t randomness_ratio = 0.0;
- real_t lifetime_randomness = 0.0;
- real_t speed_scale = 1.0;
+ double lifetime_randomness = 0.0;
+ double speed_scale = 1.0;
bool local_coords;
int fixed_fps = 0;
bool fractional_delta = true;
@@ -152,8 +150,8 @@ private:
Vector2 direction = Vector2(1, 0);
real_t spread = 45.0;
- real_t parameters[PARAM_MAX];
- real_t randomness[PARAM_MAX];
+ real_t parameters_min[PARAM_MAX];
+ real_t parameters_max[PARAM_MAX];
Ref<Curve> curve_parameters[PARAM_MAX];
Color color;
@@ -169,10 +167,14 @@ private:
Vector<Color> emission_colors;
int emission_point_count = 0;
+ Ref<Curve> scale_curve_x;
+ Ref<Curve> scale_curve_y;
+ bool split_scale = false;
+
Vector2 gravity = Vector2(0, 980);
void _update_internal();
- void _particles_process(float p_delta);
+ void _particles_process(double p_delta);
void _update_particle_data_buffer();
Mutex update_mutex;
@@ -193,27 +195,27 @@ protected:
public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
- void set_lifetime(float p_lifetime);
+ void set_lifetime(double p_lifetime);
void set_one_shot(bool p_one_shot);
- void set_pre_process_time(float p_time);
+ void set_pre_process_time(double p_time);
void set_explosiveness_ratio(real_t p_ratio);
void set_randomness_ratio(real_t p_ratio);
- void set_lifetime_randomness(float p_random);
+ void set_lifetime_randomness(double p_random);
void set_visibility_aabb(const Rect2 &p_aabb);
void set_use_local_coordinates(bool p_enable);
- void set_speed_scale(real_t p_scale);
+ void set_speed_scale(double p_scale);
bool is_emitting() const;
int get_amount() const;
- float get_lifetime() const;
+ double get_lifetime() const;
bool get_one_shot() const;
- float get_pre_process_time() const;
+ double get_pre_process_time() const;
real_t get_explosiveness_ratio() const;
real_t get_randomness_ratio() const;
- float get_lifetime_randomness() const;
+ double get_lifetime_randomness() const;
Rect2 get_visibility_aabb() const;
bool get_use_local_coordinates() const;
- real_t get_speed_scale() const;
+ double get_speed_scale() const;
void set_fixed_fps(int p_count);
int get_fixed_fps() const;
@@ -238,11 +240,11 @@ public:
void set_spread(real_t p_spread);
real_t get_spread() const;
- void set_param(Parameter p_param, real_t p_value);
- real_t get_param(Parameter p_param) const;
+ void set_param_min(Parameter p_param, real_t p_value);
+ real_t get_param_min(Parameter p_param) const;
- void set_param_randomness(Parameter p_param, real_t p_value);
- real_t get_param_randomness(Parameter p_param) const;
+ void set_param_max(Parameter p_param, real_t p_value);
+ real_t get_param_max(Parameter p_param) const;
void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
Ref<Curve> get_param_curve(Parameter p_param) const;
@@ -263,6 +265,9 @@ public:
void set_emission_normals(const Vector<Vector2> &p_normals);
void set_emission_colors(const Vector<Color> &p_colors);
void set_emission_point_count(int p_count);
+ void set_scale_curve_x(Ref<Curve> p_scale_curve);
+ void set_scale_curve_y(Ref<Curve> p_scale_curve);
+ void set_split_scale(bool p_split_scale);
EmissionShape get_emission_shape() const;
real_t get_emission_sphere_radius() const;
@@ -271,6 +276,9 @@ public:
Vector<Vector2> get_emission_normals() const;
Vector<Color> get_emission_colors() const;
int get_emission_point_count() const;
+ Ref<Curve> get_scale_curve_x() const;
+ Ref<Curve> get_scale_curve_y() const;
+ bool get_split_scale();
void set_gravity(const Vector2 &p_gravity);
Vector2 get_gravity() const;
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index adfb94d574..5bce705dd5 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -30,9 +30,7 @@
#include "gpu_particles_2d.h"
-#include "core/os/os.h"
#include "scene/resources/particles_material.h"
-#include "scene/scene_string_names.h"
#ifdef TOOLS_ENABLED
#include "core/config/engine.h"
@@ -54,7 +52,7 @@ void GPUParticles2D::set_amount(int p_amount) {
RS::get_singleton()->particles_set_amount(particles, amount);
}
-void GPUParticles2D::set_lifetime(float p_lifetime) {
+void GPUParticles2D::set_lifetime(double p_lifetime) {
ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0.");
lifetime = p_lifetime;
RS::get_singleton()->particles_set_lifetime(particles, lifetime);
@@ -76,17 +74,17 @@ void GPUParticles2D::set_one_shot(bool p_enable) {
}
}
-void GPUParticles2D::set_pre_process_time(float p_time) {
+void GPUParticles2D::set_pre_process_time(double p_time) {
pre_process_time = p_time;
RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
}
-void GPUParticles2D::set_explosiveness_ratio(float p_ratio) {
+void GPUParticles2D::set_explosiveness_ratio(real_t p_ratio) {
explosiveness_ratio = p_ratio;
RS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
}
-void GPUParticles2D::set_randomness_ratio(float p_ratio) {
+void GPUParticles2D::set_randomness_ratio(real_t p_ratio) {
randomness_ratio = p_ratio;
RS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
}
@@ -148,7 +146,8 @@ void GPUParticles2D::set_trail_enabled(bool p_enabled) {
RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED);
}
-void GPUParticles2D::set_trail_length(float p_seconds) {
+
+void GPUParticles2D::set_trail_length(double p_seconds) {
ERR_FAIL_COND(p_seconds < 0.001);
trail_length = p_seconds;
RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length);
@@ -162,6 +161,7 @@ void GPUParticles2D::set_trail_sections(int p_sections) {
trail_sections = p_sections;
update();
}
+
void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
ERR_FAIL_COND(trail_section_subdivisions < 1);
ERR_FAIL_COND(trail_section_subdivisions > 1024);
@@ -173,12 +173,13 @@ void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) {
bool GPUParticles2D::is_trail_enabled() const {
return trail_enabled;
}
-float GPUParticles2D::get_trail_length() const {
+
+double GPUParticles2D::get_trail_length() const {
return trail_length;
}
void GPUParticles2D::_update_collision_size() {
- float csize = collision_base_size;
+ real_t csize = collision_base_size;
if (texture.is_valid()) {
csize *= (texture->get_width() + texture->get_height()) / 4.0; //half size since its a radius
@@ -187,16 +188,16 @@ void GPUParticles2D::_update_collision_size() {
RS::get_singleton()->particles_set_collision_base_size(particles, csize);
}
-void GPUParticles2D::set_collision_base_size(float p_size) {
+void GPUParticles2D::set_collision_base_size(real_t p_size) {
collision_base_size = p_size;
_update_collision_size();
}
-float GPUParticles2D::get_collision_base_size() const {
+real_t GPUParticles2D::get_collision_base_size() const {
return collision_base_size;
}
-void GPUParticles2D::set_speed_scale(float p_scale) {
+void GPUParticles2D::set_speed_scale(double p_scale) {
speed_scale = p_scale;
RS::get_singleton()->particles_set_speed_scale(particles, p_scale);
}
@@ -209,7 +210,7 @@ int GPUParticles2D::get_amount() const {
return amount;
}
-float GPUParticles2D::get_lifetime() const {
+double GPUParticles2D::get_lifetime() const {
return lifetime;
}
@@ -224,15 +225,15 @@ bool GPUParticles2D::get_one_shot() const {
return one_shot;
}
-float GPUParticles2D::get_pre_process_time() const {
+double GPUParticles2D::get_pre_process_time() const {
return pre_process_time;
}
-float GPUParticles2D::get_explosiveness_ratio() const {
+real_t GPUParticles2D::get_explosiveness_ratio() const {
return explosiveness_ratio;
}
-float GPUParticles2D::get_randomness_ratio() const {
+real_t GPUParticles2D::get_randomness_ratio() const {
return randomness_ratio;
}
@@ -248,7 +249,7 @@ Ref<Material> GPUParticles2D::get_process_material() const {
return process_material;
}
-float GPUParticles2D::get_speed_scale() const {
+double GPUParticles2D::get_speed_scale() const {
return speed_scale;
}
@@ -294,7 +295,7 @@ TypedArray<String> GPUParticles2D::get_configuration_warnings() const {
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
if (process &&
- (process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+ (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
@@ -352,19 +353,19 @@ void GPUParticles2D::_notification(int p_what) {
PackedInt32Array indices;
int total_segments = trail_sections * trail_section_subdivisions;
- float depth = size.height * trail_sections;
+ real_t depth = size.height * trail_sections;
for (int j = 0; j <= total_segments; j++) {
- float v = j;
+ real_t v = j;
v /= total_segments;
- float y = depth * v;
+ real_t y = depth * v;
y = (depth * 0.5) - y;
int bone = j / trail_section_subdivisions;
- float blend = 1.0 - float(j % trail_section_subdivisions) / float(trail_section_subdivisions);
+ real_t blend = 1.0 - real_t(j % trail_section_subdivisions) / real_t(trail_section_subdivisions);
- float s = size.width;
+ real_t s = size.width;
points.push_back(Vector2(-s * 0.5, 0));
points.push_back(Vector2(+s * 0.5, 0));
@@ -410,7 +411,7 @@ void GPUParticles2D::_notification(int p_what) {
for (int i = 0; i <= trail_sections; i++) {
Transform3D xform;
/*
- xform.origin.y = depth / 2.0 - size.height * float(i);
+ xform.origin.y = depth / 2.0 - size.height * real_t(i);
xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */
xforms.push_back(xform);
}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 9d8e61daf7..d7eee461b4 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -31,9 +31,7 @@
#ifndef PARTICLES_2D_H
#define PARTICLES_2D_H
-#include "core/templates/rid.h"
#include "scene/2d/node_2d.h"
-#include "scene/resources/texture.h"
class GPUParticles2D : public Node2D {
private:
@@ -51,11 +49,11 @@ private:
bool one_shot;
int amount;
- float lifetime;
- float pre_process_time;
- float explosiveness_ratio;
- float randomness_ratio;
- float speed_scale;
+ double lifetime;
+ double pre_process_time;
+ real_t explosiveness_ratio;
+ real_t randomness_ratio;
+ double speed_scale;
Rect2 visibility_rect;
bool local_coords;
int fixed_fps;
@@ -70,10 +68,10 @@ private:
void _update_particle_emission_transform();
NodePath sub_emitter;
- float collision_base_size = 1.0;
+ real_t collision_base_size = 1.0;
bool trail_enabled = false;
- float trail_length = 0.3;
+ double trail_length = 0.3;
int trail_sections = 8;
int trail_section_subdivisions = 4;
@@ -89,36 +87,36 @@ protected:
public:
void set_emitting(bool p_emitting);
void set_amount(int p_amount);
- void set_lifetime(float p_lifetime);
+ void set_lifetime(double p_lifetime);
void set_one_shot(bool p_enable);
- void set_pre_process_time(float p_time);
- void set_explosiveness_ratio(float p_ratio);
- void set_randomness_ratio(float p_ratio);
+ void set_pre_process_time(double p_time);
+ void set_explosiveness_ratio(real_t p_ratio);
+ void set_randomness_ratio(real_t p_ratio);
void set_visibility_rect(const Rect2 &p_visibility_rect);
void set_use_local_coordinates(bool p_enable);
void set_process_material(const Ref<Material> &p_material);
- void set_speed_scale(float p_scale);
- void set_collision_base_size(float p_ratio);
+ void set_speed_scale(double p_scale);
+ void set_collision_base_size(real_t p_ratio);
void set_trail_enabled(bool p_enabled);
- void set_trail_length(float p_seconds);
+ void set_trail_length(double p_seconds);
void set_trail_sections(int p_sections);
void set_trail_section_subdivisions(int p_subdivisions);
bool is_emitting() const;
int get_amount() const;
- float get_lifetime() const;
+ double get_lifetime() const;
bool get_one_shot() const;
- float get_pre_process_time() const;
- float get_explosiveness_ratio() const;
- float get_randomness_ratio() const;
+ double get_pre_process_time() const;
+ real_t get_explosiveness_ratio() const;
+ real_t get_randomness_ratio() const;
Rect2 get_visibility_rect() const;
bool get_use_local_coordinates() const;
Ref<Material> get_process_material() const;
- float get_speed_scale() const;
+ double get_speed_scale() const;
- float get_collision_base_size() const;
+ real_t get_collision_base_size() const;
bool is_trail_enabled() const;
- float get_trail_length() const;
+ double get_trail_length() const;
int get_trail_sections() const;
int get_trail_section_subdivisions() const;
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index dbba6917b5..4a6606256e 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -30,10 +30,8 @@
#include "joints_2d.h"
-#include "core/config/engine.h"
#include "physics_body_2d.h"
#include "scene/scene_string_names.h"
-#include "servers/physics_server_2d.h"
void Joint2D::_disconnect_signals() {
Node *node_a = get_node_or_null(a);
@@ -254,7 +252,7 @@ void PinJoint2D::_notification(int p_what) {
}
void PinJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) {
- PhysicsServer2D::get_singleton()->joint_make_pin(p_joint, get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID());
+ PhysicsServer2D::get_singleton()->joint_make_pin(p_joint, get_global_position(), body_a->get_rid(), body_b ? body_b->get_rid() : RID());
PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_SOFTNESS, softness);
}
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index ce57895341..1853b3428c 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -30,9 +30,6 @@
#include "light_2d.h"
-#include "core/config/engine.h"
-#include "servers/rendering_server.h"
-
void Light2D::_update_light_visibility() {
if (!is_inside_tree()) {
return;
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index c478f03356..a8a2639ccf 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -62,14 +62,6 @@ static SegmentIntersectionResult segment_intersection(
return SEGMENT_PARALLEL;
}
-// TODO I'm pretty sure there is an even faster way to swap things
-template <typename T>
-static inline void swap(T &a, T &b) {
- T tmp = a;
- a = b;
- b = tmp;
-}
-
static float calculate_total_distance(const Vector<Vector2> &points) {
float d = 0.f;
for (int i = 1; i < points.size(); ++i) {
diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h
index 654e61422b..16c88d00e9 100644
--- a/scene/2d/line_builder.h
+++ b/scene/2d/line_builder.h
@@ -31,10 +31,7 @@
#ifndef LINE_BUILDER_H
#define LINE_BUILDER_H
-#include "core/math/color.h"
-#include "core/math/vector2.h"
#include "line_2d.h"
-#include "scene/resources/gradient.h"
class LineBuilder {
public:
diff --git a/scene/2d/listener_2d.cpp b/scene/2d/listener_2d.cpp
new file mode 100644
index 0000000000..444f05f2b1
--- /dev/null
+++ b/scene/2d/listener_2d.cpp
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* listener_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "listener_2d.h"
+
+bool Listener2D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "current") {
+ if (p_value.operator bool()) {
+ make_current();
+ } else {
+ clear_current();
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+bool Listener2D::_get(const StringName &p_name, Variant &r_ret) const {
+ if (p_name == "current") {
+ if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
+ r_ret = current;
+ } else {
+ r_ret = is_current();
+ }
+ } else {
+ return false;
+ }
+ return true;
+}
+
+void Listener2D::_get_property_list(List<PropertyInfo> *p_list) const {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
+}
+
+void Listener2D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (!get_tree()->is_node_being_edited(this) && current) {
+ make_current();
+ }
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (!get_tree()->is_node_being_edited(this)) {
+ if (is_current()) {
+ clear_current();
+ current = true; // Keep it true.
+ } else {
+ current = false;
+ }
+ }
+ } break;
+ }
+}
+
+void Listener2D::make_current() {
+ current = true;
+ if (!is_inside_tree()) {
+ return;
+ }
+ get_viewport()->_listener_2d_set(this);
+}
+
+void Listener2D::clear_current() {
+ current = false;
+ if (!is_inside_tree()) {
+ return;
+ }
+ get_viewport()->_listener_2d_remove(this);
+}
+
+bool Listener2D::is_current() const {
+ if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
+ return get_viewport()->get_listener_2d() == this;
+ } else {
+ return current;
+ }
+ return false;
+}
+
+void Listener2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("make_current"), &Listener2D::make_current);
+ ClassDB::bind_method(D_METHOD("clear_current"), &Listener2D::clear_current);
+ ClassDB::bind_method(D_METHOD("is_current"), &Listener2D::is_current);
+}
diff --git a/scene/2d/listener_2d.h b/scene/2d/listener_2d.h
new file mode 100644
index 0000000000..0289a8087d
--- /dev/null
+++ b/scene/2d/listener_2d.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* listener_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 LISTENER_2D_H
+#define LISTENER_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/main/window.h"
+
+class Listener2D : public Node2D {
+ GDCLASS(Listener2D, Node2D);
+
+private:
+ bool current = false;
+
+ friend class Viewport;
+
+protected:
+ void _update_listener();
+
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_ret) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _notification(int p_what);
+
+ static void _bind_methods();
+
+public:
+ void make_current();
+ void clear_current();
+ bool is_current() const;
+};
+
+#endif
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index e9a95b680c..2f00978123 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -30,7 +30,6 @@
#include "navigation_agent_2d.h"
-#include "core/config/engine.h"
#include "core/math/geometry_2d.h"
#include "servers/navigation_server_2d.h"
@@ -103,7 +102,7 @@ void NavigationAgent2D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
- NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().get_origin());
+ NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
_check_distance_to_target();
}
} break;
@@ -186,7 +185,7 @@ Vector2 NavigationAgent2D::get_next_location() {
update_navigation();
if (navigation_path.size() == 0) {
ERR_FAIL_COND_V(agent_parent == nullptr, Vector2());
- return agent_parent->get_global_transform().get_origin();
+ return agent_parent->get_global_position();
} else {
return navigation_path[nav_path_index];
}
@@ -194,7 +193,7 @@ Vector2 NavigationAgent2D::get_next_location() {
real_t NavigationAgent2D::distance_to_target() const {
ERR_FAIL_COND_V(agent_parent == nullptr, 0.0);
- return agent_parent->get_global_transform().get_origin().distance_to(target_location);
+ return agent_parent->get_global_position().distance_to(target_location);
}
bool NavigationAgent2D::is_target_reached() const {
@@ -261,7 +260,7 @@ void NavigationAgent2D::update_navigation() {
update_frame_id = Engine::get_singleton()->get_physics_frames();
- Vector2 o = agent_parent->get_global_transform().get_origin();
+ Vector2 o = agent_parent->get_global_position();
bool reload_path = false;
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 234cad333f..052cd78a56 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -31,7 +31,6 @@
#ifndef NAVIGATION_AGENT_2D_H
#define NAVIGATION_AGENT_2D_H
-#include "core/templates/vector.h"
#include "scene/main/node.h"
class Node2D;
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index a06f7a9fd0..0a105826c0 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -31,7 +31,6 @@
#include "navigation_obstacle_2d.h"
#include "scene/2d/collision_shape_2d.h"
-#include "scene/2d/physics_body_2d.h"
#include "servers/navigation_server_2d.h"
void NavigationObstacle2D::_bind_methods() {
@@ -54,7 +53,7 @@ void NavigationObstacle2D::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (parent_node2d) {
- NavigationServer2D::get_singleton()->agent_set_position(agent, parent_node2d->get_global_transform().get_origin());
+ NavigationServer2D::get_singleton()->agent_set_position(agent, parent_node2d->get_global_position());
}
} break;
}
@@ -93,13 +92,13 @@ void NavigationObstacle2D::update_agent_shape() {
// and add the enclosing shape radius
r += cs->get_shape()->get_enclosing_radius();
}
- Size2 s = cs->get_global_transform().get_scale();
+ Size2 s = cs->get_global_scale();
r *= MAX(s.x, s.y);
// Takes the biggest radius
radius = MAX(radius, r);
}
}
- Vector2 s = parent_node2d->get_global_transform().get_scale();
+ Vector2 s = parent_node2d->get_global_scale();
radius *= MAX(s.x, s.y);
if (radius == 0.0) {
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index ea639ae3a3..72ea6541e3 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -30,7 +30,6 @@
#include "navigation_region_2d.h"
-#include "core/config/engine.h"
#include "core/core_string_names.h"
#include "core/math/geometry_2d.h"
#include "core/os/mutex.h"
@@ -455,7 +454,7 @@ void NavigationRegion2D::_notification(int p_what) {
// Draw the region
Transform2D xform = get_global_transform();
const NavigationServer2D *ns = NavigationServer2D::get_singleton();
- float radius = ns->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0;
+ real_t radius = ns->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0;
for (int i = 0; i < ns->region_get_connections_count(region); i++) {
// Two main points
Vector2 a = ns->region_get_connection_pathway_start(region, i);
@@ -465,7 +464,7 @@ void NavigationRegion2D::_notification(int p_what) {
draw_line(a, b, doors_color);
// Draw a circle to illustrate the margins.
- float angle = (b - a).angle();
+ real_t angle = (b - a).angle();
draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, doors_color);
draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color);
}
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 6fd383ddab..6a8788ee6e 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -30,11 +30,6 @@
#include "node_2d.h"
-#include "core/object/message_queue.h"
-#include "scene/gui/control.h"
-#include "scene/main/window.h"
-#include "servers/rendering_server.h"
-
#ifdef TOOLS_ENABLED
Dictionary Node2D::_edit_get_state() const {
Dictionary state;
@@ -170,10 +165,10 @@ void Node2D::set_scale(const Size2 &p_scale) {
}
_scale = p_scale;
// Avoid having 0 scale values, can lead to errors in physics and rendering.
- if (_scale.x == 0) {
+ if (Math::is_zero_approx(_scale.x)) {
_scale.x = CMP_EPSILON;
}
- if (_scale.y == 0) {
+ if (Math::is_zero_approx(_scale.y)) {
_scale.y = CMP_EPSILON;
}
_update_transform();
diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h
index 27134dab29..3745c5b587 100644
--- a/scene/2d/parallax_background.h
+++ b/scene/2d/parallax_background.h
@@ -31,8 +31,6 @@
#ifndef PARALLAX_BACKGROUND_H
#define PARALLAX_BACKGROUND_H
-#include "scene/2d/camera_2d.h"
-#include "scene/2d/node_2d.h"
#include "scene/main/canvas_layer.h"
class ParallaxBackground : public CanvasLayer {
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 228020d383..1fe6a4a4b8 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -30,7 +30,6 @@
#include "parallax_layer.h"
-#include "core/config/engine.h"
#include "parallax_background.h"
void ParallaxLayer::set_motion_scale(const Size2 &p_scale) {
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 9912612c4f..ed30e871d7 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -30,9 +30,7 @@
#include "path_2d.h"
-#include "core/config/engine.h"
#include "core/math/geometry_2d.h"
-#include "scene/scene_string_names.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_scale.h"
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index a382fb2f1e..30f012c7aa 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -30,17 +30,12 @@
#include "physics_body_2d.h"
-#include "core/config/engine.h"
#include "core/core_string_names.h"
-#include "core/math/math_funcs.h"
-#include "core/object/class_db.h"
-#include "core/templates/list.h"
-#include "core/templates/rid.h"
#include "scene/scene_string_names.h"
void PhysicsBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.08));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08));
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08));
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -59,29 +54,28 @@ PhysicsBody2D::~PhysicsBody2D() {
}
}
-Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) {
+Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) {
PhysicsServer2D::MotionResult result;
- if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) {
+ if (move_and_collide(p_motion, result, p_margin, p_test_only)) {
if (motion_cache.is_null()) {
motion_cache.instantiate();
motion_cache->owner = this;
}
motion_cache->result = result;
-
return motion_cache;
}
return Ref<KinematicCollision2D>();
}
-bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
+bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only, bool p_cancel_sliding, bool p_collide_separation_ray, const Set<RID> &p_exclude) {
if (is_only_update_transform_changes_enabled()) {
ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation.");
}
Transform2D gt = get_global_transform();
- bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes, p_exclude);
+ bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_collide_separation_ray, p_exclude);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
@@ -108,28 +102,28 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_in
}
// Check depth of recovery.
- real_t projected_length = r_result.motion.dot(motion_normal);
- Vector2 recovery = r_result.motion - motion_normal * projected_length;
+ real_t projected_length = r_result.travel.dot(motion_normal);
+ Vector2 recovery = r_result.travel - motion_normal * projected_length;
real_t recovery_length = recovery.length();
// Fixes cases where canceling slide causes the motion to go too deep into the ground,
// because we're only taking rest information into account and not general recovery.
if (recovery_length < (real_t)p_margin + precision) {
// Apply adjustment to motion.
- r_result.motion = motion_normal * projected_length;
- r_result.remainder = p_motion - r_result.motion;
+ r_result.travel = motion_normal * projected_length;
+ r_result.remainder = p_motion - r_result.travel;
}
}
}
if (!p_test_only) {
- gt.elements[2] += r_result.motion;
+ gt.elements[2] += r_result.travel;
set_global_transform(gt);
}
return colliding;
}
-bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
+bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer2D::MotionResult *r = nullptr;
@@ -138,7 +132,7 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion
r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
}
- return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes);
+ return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r);
}
TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
@@ -171,21 +165,13 @@ void PhysicsBody2D::remove_collision_exception_with(Node *p_node) {
void StaticBody2D::set_constant_linear_velocity(const Vector2 &p_vel) {
constant_linear_velocity = p_vel;
- if (kinematic_motion) {
- _update_kinematic_motion();
- } else {
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
- }
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity);
}
void StaticBody2D::set_constant_angular_velocity(real_t p_vel) {
constant_angular_velocity = p_vel;
- if (kinematic_motion) {
- _update_kinematic_motion();
- } else {
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
- }
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity);
}
Vector2 StaticBody2D::get_constant_linear_velocity() const {
@@ -215,81 +201,83 @@ Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const {
return physics_material_override;
}
-void StaticBody2D::set_kinematic_motion_enabled(bool p_enabled) {
- if (p_enabled == kinematic_motion) {
- return;
- }
-
- kinematic_motion = p_enabled;
+void StaticBody2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity);
- if (kinematic_motion) {
- set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC);
- } else {
- set_body_mode(PhysicsServer2D::BODY_MODE_STATIC);
- }
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override);
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
- return;
- }
-#endif
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
+}
- _update_kinematic_motion();
+StaticBody2D::StaticBody2D(PhysicsServer2D::BodyMode p_mode) :
+ PhysicsBody2D(p_mode) {
}
-bool StaticBody2D::is_kinematic_motion_enabled() const {
- return kinematic_motion;
+void StaticBody2D::_reload_physics_characteristics() {
+ if (physics_material_override.is_null()) {
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
+ }
}
-void StaticBody2D::set_sync_to_physics(bool p_enable) {
+void AnimatableBody2D::set_sync_to_physics(bool p_enable) {
if (sync_to_physics == p_enable) {
return;
}
sync_to_physics = p_enable;
+ _update_kinematic_motion();
+}
+
+bool AnimatableBody2D::is_sync_to_physics_enabled() const {
+ return sync_to_physics;
+}
+
+void AnimatableBody2D::_update_kinematic_motion() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
- update_configuration_warnings();
return;
}
#endif
- if (kinematic_motion) {
- _update_kinematic_motion();
+ if (sync_to_physics) {
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
+ set_only_update_transform_changes(true);
+ set_notify_local_transform(true);
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
+ set_only_update_transform_changes(false);
+ set_notify_local_transform(false);
}
}
-bool StaticBody2D::is_sync_to_physics_enabled() const {
- return sync_to_physics;
+void AnimatableBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
+ AnimatableBody2D *body = (AnimatableBody2D *)p_instance;
+ body->_body_state_changed(p_state);
}
-void StaticBody2D::_direct_state_changed(Object *p_state) {
+void AnimatableBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
if (!sync_to_physics) {
return;
}
- PhysicsDirectBodyState2D *state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
-
- last_valid_transform = state->get_transform();
+ last_valid_transform = p_state->get_transform();
set_notify_local_transform(false);
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
}
-TypedArray<String> StaticBody2D::get_configuration_warnings() const {
- TypedArray<String> warnings = PhysicsBody2D::get_configuration_warnings();
-
- if (sync_to_physics && !kinematic_motion) {
- warnings.push_back(TTR("Sync to physics works only when kinematic motion is enabled."));
- }
-
- return warnings;
-}
-
-void StaticBody2D::_notification(int p_what) {
+void AnimatableBody2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
last_valid_transform = get_global_transform();
@@ -299,10 +287,6 @@ void StaticBody2D::_notification(int p_what) {
// Used by sync to physics, send the new transform to the physics...
Transform2D new_transform = get_global_transform();
- real_t delta_time = get_physics_process_delta_time();
- new_transform.translate(constant_linear_velocity * delta_time);
- new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);
-
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
// ... but then revert changes.
@@ -310,98 +294,19 @@ void StaticBody2D::_notification(int p_what) {
set_global_transform(last_valid_transform);
set_notify_local_transform(true);
} break;
-
- case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
- }
-#endif
-
- ERR_FAIL_COND(!kinematic_motion);
-
- Transform2D new_transform = get_global_transform();
-
- real_t delta_time = get_physics_process_delta_time();
- new_transform.translate(constant_linear_velocity * delta_time);
- new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time);
-
- if (sync_to_physics) {
- // Propagate transform change to node.
- set_global_transform(new_transform);
- } else {
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform);
-
- // Propagate transform change to node.
- set_block_transform_notify(true);
- set_global_transform(new_transform);
- set_block_transform_notify(false);
- }
- } break;
}
}
-void StaticBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity);
-
- ClassDB::bind_method(D_METHOD("set_kinematic_motion_enabled", "enabled"), &StaticBody2D::set_kinematic_motion_enabled);
- ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody2D::is_kinematic_motion_enabled);
-
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override);
-
- ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &StaticBody2D::set_sync_to_physics);
- ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &StaticBody2D::is_sync_to_physics_enabled);
+void AnimatableBody2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &AnimatableBody2D::set_sync_to_physics);
+ ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &AnimatableBody2D::is_sync_to_physics_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled");
}
-StaticBody2D::StaticBody2D() :
- PhysicsBody2D(PhysicsServer2D::BODY_MODE_STATIC) {
-}
-
-void StaticBody2D::_reload_physics_characteristics() {
- if (physics_material_override.is_null()) {
- PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
- PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1);
- } else {
- PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce());
- PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, physics_material_override->computed_friction());
- }
-}
-
-void StaticBody2D::_update_kinematic_motion() {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- return;
- }
-#endif
-
- if (kinematic_motion && sync_to_physics) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &StaticBody2D::_direct_state_changed));
- set_only_update_transform_changes(true);
- set_notify_local_transform(true);
- } else {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable());
- set_only_update_transform_changes(false);
- set_notify_local_transform(false);
- }
-
- bool needs_physics_process = false;
- if (kinematic_motion) {
- if (!Math::is_zero_approx(constant_angular_velocity) || !constant_linear_velocity.is_equal_approx(Vector2())) {
- needs_physics_process = true;
- }
- }
-
- set_physics_process_internal(needs_physics_process);
+AnimatableBody2D::AnimatableBody2D() :
+ StaticBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ _update_kinematic_motion();
}
void RigidBody2D::_body_enter_tree(ObjectID p_id) {
@@ -517,27 +422,27 @@ struct _RigidBody2DInOut {
int local_shape = 0;
};
-void RigidBody2D::_direct_state_changed(Object *p_state) {
-#ifdef DEBUG_ENABLED
- state = Object::cast_to<PhysicsDirectBodyState2D>(p_state);
- ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState2D object as argument");
-#else
- state = (PhysicsDirectBodyState2D *)p_state; //trust it
-#endif
+void RigidBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
+ RigidBody2D *body = (RigidBody2D *)p_instance;
+ body->_body_state_changed(p_state);
+}
+void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
set_block_transform_notify(true); // don't want notify (would feedback loop)
if (mode != MODE_KINEMATIC) {
- set_global_transform(state->get_transform());
+ set_global_transform(p_state->get_transform());
}
- linear_velocity = state->get_linear_velocity();
- angular_velocity = state->get_angular_velocity();
- if (sleeping != state->is_sleeping()) {
- sleeping = state->is_sleeping();
+
+ linear_velocity = p_state->get_linear_velocity();
+ angular_velocity = p_state->get_angular_velocity();
+
+ if (sleeping != p_state->is_sleeping()) {
+ sleeping = p_state->is_sleeping();
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
}
- if (get_script_instance()) {
- get_script_instance()->call("_integrate_forces", state);
- }
+
+ GDVIRTUAL_CALL(_integrate_forces, p_state);
+
set_block_transform_notify(false); // want it back
if (contact_monitor) {
@@ -552,20 +457,18 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
}
}
- _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(state->get_contact_count() * sizeof(_RigidBody2DInOut));
+ _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBody2DInOut));
int toadd_count = 0; //state->get_contact_count();
RigidBody2D_RemoveAction *toremove = (RigidBody2D_RemoveAction *)alloca(rc * sizeof(RigidBody2D_RemoveAction));
int toremove_count = 0;
//put the ones to add
- for (int i = 0; i < state->get_contact_count(); i++) {
- RID rid = state->get_contact_collider(i);
- ObjectID obj = state->get_contact_collider_id(i);
- int local_shape = state->get_contact_local_shape(i);
- int shape = state->get_contact_collider_shape(i);
-
- //bool found=false;
+ for (int i = 0; i < p_state->get_contact_count(); i++) {
+ RID rid = p_state->get_contact_collider(i);
+ ObjectID obj = p_state->get_contact_collider_id(i);
+ int local_shape = p_state->get_contact_local_shape(i);
+ int shape = p_state->get_contact_collider_shape(i);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(obj);
if (!E) {
@@ -618,8 +521,6 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
contact_monitor->locked = false;
}
-
- state = nullptr;
}
void RigidBody2D::set_mode(Mode p_mode) {
@@ -659,11 +560,53 @@ real_t RigidBody2D::get_mass() const {
void RigidBody2D::set_inertia(real_t p_inertia) {
ERR_FAIL_COND(p_inertia < 0);
- PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, p_inertia);
+ inertia = p_inertia;
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia);
}
real_t RigidBody2D::get_inertia() const {
- return PhysicsServer2D::get_singleton()->body_get_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA);
+ return inertia;
+}
+
+void RigidBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
+ if (center_of_mass_mode == p_mode) {
+ return;
+ }
+
+ center_of_mass_mode = p_mode;
+
+ switch (center_of_mass_mode) {
+ case CENTER_OF_MASS_MODE_AUTO: {
+ center_of_mass = Vector2();
+ PhysicsServer2D::get_singleton()->body_reset_mass_properties(get_rid());
+ if (inertia != 0.0) {
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia);
+ }
+ } break;
+
+ case CENTER_OF_MASS_MODE_CUSTOM: {
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
+ } break;
+ }
+}
+
+RigidBody2D::CenterOfMassMode RigidBody2D::get_center_of_mass_mode() const {
+ return center_of_mass_mode;
+}
+
+void RigidBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) {
+ if (center_of_mass == p_center_of_mass) {
+ return;
+ }
+
+ ERR_FAIL_COND(center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM);
+ center_of_mass = p_center_of_mass;
+
+ PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
+}
+
+const Vector2 &RigidBody2D::get_center_of_mass() const {
+ return center_of_mass;
}
void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
@@ -715,25 +658,15 @@ real_t RigidBody2D::get_angular_damp() const {
}
void RigidBody2D::set_axis_velocity(const Vector2 &p_axis) {
- Vector2 v = state ? state->get_linear_velocity() : linear_velocity;
Vector2 axis = p_axis.normalized();
- v -= axis * axis.dot(v);
- v += p_axis;
- if (state) {
- set_linear_velocity(v);
- } else {
- PhysicsServer2D::get_singleton()->body_set_axis_velocity(get_rid(), p_axis);
- linear_velocity = v;
- }
+ linear_velocity -= axis * axis.dot(linear_velocity);
+ linear_velocity += p_axis;
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
void RigidBody2D::set_linear_velocity(const Vector2 &p_velocity) {
linear_velocity = p_velocity;
- if (state) {
- state->set_linear_velocity(linear_velocity);
- } else {
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
- }
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
Vector2 RigidBody2D::get_linear_velocity() const {
@@ -742,11 +675,7 @@ Vector2 RigidBody2D::get_linear_velocity() const {
void RigidBody2D::set_angular_velocity(real_t p_velocity) {
angular_velocity = p_velocity;
- if (state) {
- state->set_angular_velocity(angular_velocity);
- } else {
- PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
- }
+ PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
real_t RigidBody2D::get_angular_velocity() const {
@@ -931,6 +860,12 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody2D::get_inertia);
ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody2D::set_inertia);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody2D::set_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody2D::get_center_of_mass_mode);
+
+ ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody2D::set_center_of_mass);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody2D::get_center_of_mass);
+
ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override);
ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override);
@@ -984,11 +919,14 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies);
- BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D")));
+ GDVIRTUAL_BIND(_integrate_forces, "state");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp", PROPERTY_USAGE_NONE), "set_inertia", "get_inertia");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,exp"), "set_inertia", "get_inertia");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater"), "set_center_of_mass", "get_center_of_mass");
+ ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
@@ -1018,14 +956,25 @@ void RigidBody2D::_bind_methods() {
BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED);
BIND_ENUM_CONSTANT(MODE_KINEMATIC);
+ BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_AUTO);
+ BIND_ENUM_CONSTANT(CENTER_OF_MASS_MODE_CUSTOM);
+
BIND_ENUM_CONSTANT(CCD_MODE_DISABLED);
BIND_ENUM_CONSTANT(CCD_MODE_CAST_RAY);
BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE);
}
+void RigidBody2D::_validate_property(PropertyInfo &property) const {
+ if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
+ if (property.name == "center_of_mass") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+ }
+}
+
RigidBody2D::RigidBody2D() :
PhysicsBody2D(PhysicsServer2D::BODY_MODE_DYNAMIC) {
- PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody2D::_direct_state_changed));
+ PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
RigidBody2D::~RigidBody2D() {
@@ -1046,199 +995,321 @@ void RigidBody2D::_reload_physics_characteristics() {
//////////////////////////
-//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
+// So, if you pass 45 as limit, avoid numerical precision errors when angle is 45.
#define FLOOR_ANGLE_THRESHOLD 0.01
-void CharacterBody2D::move_and_slide() {
- Vector2 body_velocity_normal = linear_velocity.normalized();
- bool was_on_floor = on_floor;
-
- // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
- float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+bool CharacterBody2D::move_and_slide() {
+ // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky.
+ double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
- Vector2 current_floor_velocity = floor_velocity;
+ Vector2 current_platform_velocity = platform_velocity;
- if ((on_floor || on_wall) && on_floor_body.is_valid()) {
- //this approach makes sure there is less delay between the actual body velocity and the one we saved
- PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(on_floor_body);
- if (bs) {
- current_floor_velocity = bs->get_linear_velocity();
+ if ((on_floor || on_wall) && platform_rid.is_valid()) {
+ bool excluded = false;
+ if (on_floor) {
+ excluded = (moving_platform_floor_layers & platform_layer) == 0;
+ } else if (on_wall) {
+ excluded = (moving_platform_wall_layers & platform_layer) == 0;
+ }
+ if (!excluded) {
+ //this approach makes sure there is less delay between the actual body velocity and the one we saved
+ PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(platform_rid);
+ if (bs) {
+ Transform2D gt = get_global_transform();
+ Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2];
+ current_platform_velocity = bs->get_velocity_at_local_position(local_position);
+ }
+ } else {
+ current_platform_velocity = Vector2();
}
}
motion_results.clear();
+
+ bool was_on_floor = on_floor;
on_floor = false;
on_ceiling = false;
on_wall = false;
- floor_normal = Vector2();
- floor_velocity = Vector2();
- if (current_floor_velocity != Vector2()) {
+ if (!current_platform_velocity.is_equal_approx(Vector2())) {
PhysicsServer2D::MotionResult floor_result;
Set<RID> exclude;
- exclude.insert(on_floor_body);
- if (move_and_collide(current_floor_velocity * delta, infinite_inertia, floor_result, true, false, false, false, exclude)) {
+ exclude.insert(platform_rid);
+ if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, false, false, exclude)) {
motion_results.push_back(floor_result);
_set_collision_direction(floor_result);
}
}
- on_floor_body = RID();
- Vector2 motion = linear_velocity * delta;
+ if (motion_mode == MOTION_MODE_GROUNDED) {
+ _move_and_slide_grounded(delta, was_on_floor, current_platform_velocity);
+ } else {
+ _move_and_slide_free(delta);
+ }
+
+ if (!on_floor && !on_wall) {
+ // Add last platform velocity when just left a moving platform.
+ linear_velocity += current_platform_velocity;
+ }
+
+ return motion_results.size() > 0;
+}
+
+void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity) {
+ Vector2 motion = linear_velocity * p_delta;
+ Vector2 motion_slide_up = motion.slide(up_direction);
+
+ Vector2 prev_floor_normal = floor_normal;
+ RID prev_platform_rid = platform_rid;
+ int prev_platform_layer = platform_layer;
+
+ platform_rid = RID();
+ floor_normal = Vector2();
+ platform_velocity = Vector2();
// No sliding on first attempt to keep floor motion stable when possible,
- // when stop on slope is enabled.
- bool sliding_enabled = !stop_on_slope;
+ // When stop on slope is enabled or when there is no up direction.
+ bool sliding_enabled = !floor_stop_on_slope;
+ // Constant speed can be applied only the first time sliding is enabled.
+ bool can_apply_constant_speed = sliding_enabled;
+ bool first_slide = true;
+ bool vel_dir_facing_up = linear_velocity.dot(up_direction) > 0;
+ Vector2 last_travel;
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionResult result;
- bool found_collision = false;
-
- for (int i = 0; i < 2; ++i) {
- bool collided;
- if (i == 0) { //collide
- collided = move_and_collide(motion, infinite_inertia, result, margin, true, false, !sliding_enabled);
- if (!collided) {
- motion = Vector2(); //clear because no collision happened and motion completed
- }
- } else { //separate raycasts (if any)
- collided = separate_raycast_shapes(result);
- if (collided) {
- result.remainder = motion; //keep
- result.motion = Vector2();
+
+ Vector2 prev_position = get_global_transform().elements[2];
+
+ bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
+
+ if (collided) {
+ motion_results.push_back(result);
+ _set_collision_direction(result);
+
+ if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
+ Transform2D gt = get_global_transform();
+ if (result.travel.length() > margin) {
+ gt.elements[2] -= result.travel.slide(up_direction);
+ } else {
+ gt.elements[2] -= result.travel;
}
+ set_global_transform(gt);
+ linear_velocity = Vector2();
+ motion = Vector2();
+ break;
}
- if (collided) {
- found_collision = true;
-
- motion_results.push_back(result);
- _set_collision_direction(result);
+ if (result.remainder.is_equal_approx(Vector2())) {
+ motion = Vector2();
+ break;
+ }
- if (on_floor && stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01) {
+ // Move on floor only checks.
+ if (floor_block_on_wall && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) {
+ // Avoid to move forward on a wall if floor_block_on_wall is true.
+ if (p_was_on_floor && !on_floor && !vel_dir_facing_up) {
+ // If the movement is large the body can be prevented from reaching the walls.
+ if (result.travel.length() <= margin) {
+ // Cancels the motion.
Transform2D gt = get_global_transform();
- if (result.motion.length() > margin) {
- gt.elements[2] -= result.motion.slide(up_direction);
- } else {
- gt.elements[2] -= result.motion;
- }
+ gt.elements[2] -= result.travel;
set_global_transform(gt);
- linear_velocity = Vector2();
- return;
}
+ on_floor = true;
+ platform_rid = prev_platform_rid;
+ platform_layer = prev_platform_layer;
+ platform_velocity = p_prev_platform_velocity;
+ floor_normal = prev_floor_normal;
+ linear_velocity = Vector2();
+ motion = Vector2();
+ break;
}
-
- if (sliding_enabled || !on_floor) {
- motion = result.remainder.slide(result.collision_normal);
- linear_velocity = linear_velocity.slide(result.collision_normal);
+ // Prevents the body from being able to climb a slope when it moves forward against the wall.
+ else if (!on_floor) {
+ motion = up_direction * up_direction.dot(result.remainder);
+ motion = motion.slide(result.collision_normal);
} else {
motion = result.remainder;
}
}
+ // Constant Speed when the slope is upward.
+ else if (floor_constant_speed && is_on_floor_only() && can_apply_constant_speed && p_was_on_floor && motion.dot(result.collision_normal) < 0) {
+ can_apply_constant_speed = false;
+ Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized();
+ motion = motion_slide_norm * (motion_slide_up.length() - result.travel.slide(up_direction).length() - last_travel.slide(up_direction).length());
+ }
+ // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling.
+ else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up)) {
+ Vector2 slide_motion = result.remainder.slide(result.collision_normal);
+ if (slide_motion.dot(linear_velocity) > 0.0) {
+ motion = slide_motion;
+ } else {
+ motion = Vector2();
+ }
+ if (slide_on_ceiling && on_ceiling) {
+ // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall.
+ if (vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(result.collision_normal);
+ } else {
+ // Avoid acceleration in slope when falling.
+ linear_velocity = up_direction * up_direction.dot(linear_velocity);
+ }
+ }
+ }
+ // No sliding on first attempt to keep floor motion stable when possible.
+ else {
+ motion = result.remainder;
+ if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ motion = motion.slide(up_direction);
+ }
+ }
+ last_travel = result.travel;
+ }
+ // When you move forward in a downward slope you don’t collide because you will be in the air.
+ // This test ensures that constant speed is applied, only if the player is still on the ground after the snap is applied.
+ else if (floor_constant_speed && first_slide && _on_floor_if_snapped(p_was_on_floor, vel_dir_facing_up)) {
+ can_apply_constant_speed = false;
sliding_enabled = true;
+ Transform2D gt = get_global_transform();
+ gt.elements[2] = prev_position;
+ set_global_transform(gt);
+
+ Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized();
+ motion = motion_slide_norm * (motion_slide_up.length());
+ collided = true;
}
- if (!found_collision || motion == Vector2()) {
+ can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
+ sliding_enabled = true;
+ first_slide = false;
+
+ if (!collided || motion.is_equal_approx(Vector2())) {
break;
}
}
- if (!on_floor && !on_wall) {
- // Add last platform velocity when just left a moving platform.
- linear_velocity += current_floor_velocity;
+ _snap_on_floor(p_was_on_floor, vel_dir_facing_up);
+
+ // Reset the gravity accumulation when touching the ground.
+ if (on_floor && !vel_dir_facing_up) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ }
+}
+
+void CharacterBody2D::_move_and_slide_free(double p_delta) {
+ Vector2 motion = linear_velocity * p_delta;
+
+ platform_rid = RID();
+ floor_normal = Vector2();
+ platform_velocity = Vector2();
+
+ bool first_slide = true;
+ for (int iteration = 0; iteration < max_slides; ++iteration) {
+ PhysicsServer2D::MotionResult result;
+
+ bool collided = move_and_collide(motion, result, margin, false, false);
+
+ if (collided) {
+ motion_results.push_back(result);
+ _set_collision_direction(result);
+
+ if (free_mode_min_slide_angle != 0 && result.get_angle(-linear_velocity.normalized()) < free_mode_min_slide_angle + FLOOR_ANGLE_THRESHOLD) {
+ motion = Vector2();
+ } else if (first_slide) {
+ Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized();
+ motion = motion_slide_norm * (motion.length() - result.travel.length());
+ } else {
+ motion = result.remainder.slide(result.collision_normal);
+ }
+
+ if (motion.dot(linear_velocity) <= 0.0) {
+ motion = Vector2();
+ }
+ }
+
+ first_slide = false;
+
+ if (!collided || motion.is_equal_approx(Vector2())) {
+ break;
+ }
}
+}
- if (!was_on_floor || snap == Vector2()) {
+void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up) {
+ if (Math::is_equal_approx(floor_snap_length, 0) || on_floor || !was_on_floor || vel_dir_facing_up) {
return;
}
- // Apply snap.
Transform2D gt = get_global_transform();
PhysicsServer2D::MotionResult result;
- if (move_and_collide(snap, infinite_inertia, result, margin, false, true, false)) {
+ if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) {
bool apply = true;
- if (up_direction != Vector2()) {
- if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
- on_floor = true;
- floor_normal = result.collision_normal;
- on_floor_body = result.collider;
- floor_velocity = result.collider_velocity;
- if (stop_on_slope) {
- // move and collide may stray the object a bit because of pre un-stucking,
- // so only ensure that motion happens on floor direction in this case.
- if (result.motion.length() > margin) {
- result.motion = up_direction * up_direction.dot(result.motion);
- } else {
- result.motion = Vector2();
- }
+ if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ on_floor = true;
+ floor_normal = result.collision_normal;
+ _set_platform_data(result);
+
+ if (floor_stop_on_slope) {
+ // move and collide may stray the object a bit because of pre un-stucking,
+ // so only ensure that motion happens on floor direction in this case.
+ if (result.travel.length() > margin) {
+ result.travel = up_direction * up_direction.dot(result.travel);
+ } else {
+ result.travel = Vector2();
}
- } else {
- apply = false;
}
+ } else {
+ apply = false;
}
if (apply) {
- gt.elements[2] += result.motion;
+ gt.elements[2] += result.travel;
set_global_transform(gt);
}
}
}
-void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) {
- if (up_direction == Vector2()) {
- //all is a wall
- on_wall = true;
- } else {
- if (Math::acos(p_result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
- on_floor = true;
- floor_normal = p_result.collision_normal;
- on_floor_body = p_result.collider;
- floor_velocity = p_result.collider_velocity;
- } else if (Math::acos(p_result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
- on_ceiling = true;
- } else {
- on_wall = true;
- on_floor_body = p_result.collider;
- floor_velocity = p_result.collider_velocity;
- }
+bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up) {
+ if (Math::is_equal_approx(floor_snap_length, 0) || up_direction == Vector2() || on_floor || !was_on_floor || vel_dir_facing_up) {
+ return false;
}
-}
-bool CharacterBody2D::separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result) {
- PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays
+ PhysicsServer2D::MotionResult result;
+ if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) {
+ if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ return true;
+ }
+ }
- Transform2D gt = get_global_transform();
+ return false;
+}
- Vector2 recover;
- int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin);
- int deepest = -1;
- real_t deepest_depth;
- for (int i = 0; i < hits; i++) {
- if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) {
- deepest = i;
- deepest_depth = sep_res[i].collision_depth;
+void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) {
+ if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
+ on_floor = true;
+ floor_normal = p_result.collision_normal;
+ _set_platform_data(p_result);
+ } else if (motion_mode == MOTION_MODE_GROUNDED && p_result.get_angle(-up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
+ on_ceiling = true;
+ } else {
+ on_wall = true;
+ // Don't apply wall velocity when the collider is a CharacterBody2D.
+ if (Object::cast_to<CharacterBody2D>(ObjectDB::get_instance(p_result.collider_id)) == nullptr) {
+ _set_platform_data(p_result);
}
}
+}
- gt.elements[2] += recover;
- set_global_transform(gt);
-
- if (deepest != -1) {
- r_result.collider_id = sep_res[deepest].collider_id;
- r_result.collider_metadata = sep_res[deepest].collider_metadata;
- r_result.collider_shape = sep_res[deepest].collider_shape;
- r_result.collider_velocity = sep_res[deepest].collider_velocity;
- r_result.collision_point = sep_res[deepest].collision_point;
- r_result.collision_normal = sep_res[deepest].collision_normal;
- r_result.collision_local_shape = sep_res[deepest].collision_local_shape;
- r_result.motion = recover;
- r_result.remainder = Vector2();
-
- return true;
- } else {
- return false;
+void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_result) {
+ platform_rid = p_result.collider;
+ platform_velocity = p_result.collider_velocity;
+ platform_layer = 0;
+ CollisionObject2D *collision_object = Object::cast_to<CollisionObject2D>(ObjectDB::get_instance(p_result.collider_id));
+ if (collision_object) {
+ platform_layer = collision_object->get_collision_layer();
}
}
@@ -1254,23 +1325,40 @@ bool CharacterBody2D::is_on_floor() const {
return on_floor;
}
+bool CharacterBody2D::is_on_floor_only() const {
+ return on_floor && !on_wall && !on_ceiling;
+}
+
bool CharacterBody2D::is_on_wall() const {
return on_wall;
}
+bool CharacterBody2D::is_on_wall_only() const {
+ return on_wall && !on_floor && !on_ceiling;
+}
+
bool CharacterBody2D::is_on_ceiling() const {
return on_ceiling;
}
+bool CharacterBody2D::is_on_ceiling_only() const {
+ return on_ceiling && !on_floor && !on_wall;
+}
+
Vector2 CharacterBody2D::get_floor_normal() const {
return floor_normal;
}
-Vector2 CharacterBody2D::get_floor_velocity() const {
- return floor_velocity;
+real_t CharacterBody2D::get_floor_angle(const Vector2 &p_up_direction) const {
+ ERR_FAIL_COND_V(p_up_direction == Vector2(), 0);
+ return Math::acos(floor_normal.dot(p_up_direction));
}
-int CharacterBody2D::get_slide_count() const {
+Vector2 CharacterBody2D::get_platform_velocity() const {
+ return platform_velocity;
+}
+
+int CharacterBody2D::get_slide_collision_count() const {
return motion_results.size();
}
@@ -1294,6 +1382,13 @@ Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) {
return slide_colliders[p_bounce];
}
+Ref<KinematicCollision2D> CharacterBody2D::_get_last_slide_collision() {
+ if (motion_results.size() == 0) {
+ return Ref<KinematicCollision2D>();
+ }
+ return _get_slide_collision(motion_results.size() - 1);
+}
+
void CharacterBody2D::set_safe_margin(real_t p_margin) {
margin = p_margin;
}
@@ -1302,19 +1397,60 @@ real_t CharacterBody2D::get_safe_margin() const {
return margin;
}
-bool CharacterBody2D::is_stop_on_slope_enabled() const {
- return stop_on_slope;
+bool CharacterBody2D::is_floor_stop_on_slope_enabled() const {
+ return floor_stop_on_slope;
}
-void CharacterBody2D::set_stop_on_slope_enabled(bool p_enabled) {
- stop_on_slope = p_enabled;
+void CharacterBody2D::set_floor_stop_on_slope_enabled(bool p_enabled) {
+ floor_stop_on_slope = p_enabled;
}
-bool CharacterBody2D::is_infinite_inertia_enabled() const {
- return infinite_inertia;
+bool CharacterBody2D::is_floor_constant_speed_enabled() const {
+ return floor_constant_speed;
}
-void CharacterBody2D::set_infinite_inertia_enabled(bool p_enabled) {
- infinite_inertia = p_enabled;
+
+void CharacterBody2D::set_floor_constant_speed_enabled(bool p_enabled) {
+ floor_constant_speed = p_enabled;
+}
+
+bool CharacterBody2D::is_floor_block_on_wall_enabled() const {
+ return floor_block_on_wall;
+}
+
+void CharacterBody2D::set_floor_block_on_wall_enabled(bool p_enabled) {
+ floor_block_on_wall = p_enabled;
+}
+
+bool CharacterBody2D::is_slide_on_ceiling_enabled() const {
+ return slide_on_ceiling;
+}
+
+void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) {
+ slide_on_ceiling = p_enabled;
+}
+
+uint32_t CharacterBody2D::get_moving_platform_floor_layers() const {
+ return moving_platform_floor_layers;
+}
+
+void CharacterBody2D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) {
+ moving_platform_floor_layers = p_exclude_layers;
+}
+
+uint32_t CharacterBody2D::get_moving_platform_wall_layers() const {
+ return moving_platform_wall_layers;
+}
+
+void CharacterBody2D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) {
+ moving_platform_wall_layers = p_exclude_layers;
+}
+
+void CharacterBody2D::set_motion_mode(MotionMode p_mode) {
+ motion_mode = p_mode;
+}
+
+CharacterBody2D::MotionMode CharacterBody2D::get_motion_mode() const {
+ return motion_mode;
}
int CharacterBody2D::get_max_slides() const {
@@ -1334,12 +1470,21 @@ void CharacterBody2D::set_floor_max_angle(real_t p_radians) {
floor_max_angle = p_radians;
}
-const Vector2 &CharacterBody2D::get_snap() const {
- return snap;
+real_t CharacterBody2D::get_floor_snap_length() {
+ return floor_snap_length;
+}
+
+void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) {
+ ERR_FAIL_COND(p_floor_snap_length < 0);
+ floor_snap_length = p_floor_snap_length;
}
-void CharacterBody2D::set_snap(const Vector2 &p_snap) {
- snap = p_snap;
+real_t CharacterBody2D::get_free_mode_min_slide_angle() const {
+ return free_mode_min_slide_angle;
+}
+
+void CharacterBody2D::set_free_mode_min_slide_angle(real_t p_radians) {
+ free_mode_min_slide_angle = p_radians;
}
const Vector2 &CharacterBody2D::get_up_direction() const {
@@ -1347,6 +1492,7 @@ const Vector2 &CharacterBody2D::get_up_direction() const {
}
void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) {
+ ERR_FAIL_COND_MSG(p_up_direction == Vector2(), "up_direction can't be equal to Vector2.ZERO, consider using Free motion mode instead.");
up_direction = p_up_direction.normalized();
}
@@ -1355,11 +1501,11 @@ void CharacterBody2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
// Reset move_and_slide() data.
on_floor = false;
- on_floor_body = RID();
+ platform_rid = RID();
on_ceiling = false;
on_wall = false;
motion_results.clear();
- floor_velocity = Vector2();
+ platform_velocity = Vector2();
} break;
}
}
@@ -1372,36 +1518,78 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin);
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin);
- ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody2D::is_stop_on_slope_enabled);
- ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_stop_on_slope_enabled);
- ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody2D::is_infinite_inertia_enabled);
- ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody2D::set_infinite_inertia_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody2D::is_floor_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_floor_stop_on_slope_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_constant_speed_enabled", "enabled"), &CharacterBody2D::set_floor_constant_speed_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_constant_speed_enabled"), &CharacterBody2D::is_floor_constant_speed_enabled);
+ ClassDB::bind_method(D_METHOD("set_floor_block_on_wall_enabled", "enabled"), &CharacterBody2D::set_floor_block_on_wall_enabled);
+ ClassDB::bind_method(D_METHOD("is_floor_block_on_wall_enabled"), &CharacterBody2D::is_floor_block_on_wall_enabled);
+ ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody2D::set_slide_on_ceiling_enabled);
+ ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody2D::is_slide_on_ceiling_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody2D::get_moving_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody2D::get_moving_platform_wall_layers);
+
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides);
ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody2D::get_floor_max_angle);
ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle);
- ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody2D::get_snap);
- ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody2D::set_snap);
+ ClassDB::bind_method(D_METHOD("get_floor_snap_length"), &CharacterBody2D::get_floor_snap_length);
+ ClassDB::bind_method(D_METHOD("set_floor_snap_length", "floor_snap_length"), &CharacterBody2D::set_floor_snap_length);
+ ClassDB::bind_method(D_METHOD("get_free_mode_min_slide_angle"), &CharacterBody2D::get_free_mode_min_slide_angle);
+ ClassDB::bind_method(D_METHOD("set_free_mode_min_slide_angle", "radians"), &CharacterBody2D::set_free_mode_min_slide_angle);
ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction);
ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction);
+ ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode);
+ ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody2D::get_motion_mode);
ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody2D::is_on_floor_only);
ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody2D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling_only"), &CharacterBody2D::is_on_ceiling_only);
ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody2D::is_on_wall);
+ ClassDB::bind_method(D_METHOD("is_on_wall_only"), &CharacterBody2D::is_on_wall_only);
ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody2D::get_floor_normal);
- ClassDB::bind_method(D_METHOD("get_floor_velocity"), &CharacterBody2D::get_floor_velocity);
- ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody2D::get_slide_count);
+ ClassDB::bind_method(D_METHOD("get_floor_angle", "up_direction"), &CharacterBody2D::get_floor_angle, DEFVAL(Vector2(0.0, -1.0)));
+ ClassDB::bind_method(D_METHOD("get_platform_velocity"), &CharacterBody2D::get_platform_velocity);
+ ClassDB::bind_method(D_METHOD("get_slide_collision_count"), &CharacterBody2D::get_slide_collision_count);
ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision);
+ ClassDB::bind_method(D_METHOD("get_last_slide_collision"), &CharacterBody2D::_get_last_slide_collision);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Free", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_RANGE, "1,8,1,or_greater"), "set_max_slides", "get_max_slides");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_floor_max_angle", "get_floor_max_angle");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap"), "set_snap", "get_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_slides", "get_max_slides");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction");
-
+ ADD_GROUP("Free Mode", "free_mode_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "free_mode_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_free_mode_min_slide_angle", "get_free_mode_min_slide_angle");
+ ADD_GROUP("Floor", "floor_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1000,0.1"), "set_floor_snap_length", "get_floor_snap_length");
+ ADD_GROUP("Moving platform", "moving_platform");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
+
+ BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED);
+ BIND_ENUM_CONSTANT(MOTION_MODE_FREE);
+}
+
+void CharacterBody2D::_validate_property(PropertyInfo &property) const {
+ if (motion_mode == MOTION_MODE_FREE) {
+ if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+ } else {
+ if (property.name == "free_mode_min_slide_angle") {
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+ }
+ }
}
CharacterBody2D::CharacterBody2D() :
@@ -1427,13 +1615,18 @@ Vector2 KinematicCollision2D::get_normal() const {
}
Vector2 KinematicCollision2D::get_travel() const {
- return result.motion;
+ return result.travel;
}
Vector2 KinematicCollision2D::get_remainder() const {
return result.remainder;
}
+real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const {
+ ERR_FAIL_COND_V(p_up_direction == Vector2(), 0);
+ return result.get_angle(p_up_direction);
+}
+
Object *KinematicCollision2D::get_local_shape() const {
if (!owner) {
return nullptr;
@@ -1488,6 +1681,7 @@ void KinematicCollision2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_normal"), &KinematicCollision2D::get_normal);
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder);
+ ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0)));
ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape);
ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 7a319aabc9..1d6437a3ad 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -47,11 +47,11 @@ protected:
Ref<KinematicCollision2D> motion_cache;
- Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.08);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08);
public:
- bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
- bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);
+ bool move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, bool p_cancel_sliding = true, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>());
+ bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);
TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody
@@ -63,20 +63,13 @@ public:
class StaticBody2D : public PhysicsBody2D {
GDCLASS(StaticBody2D, PhysicsBody2D);
+private:
Vector2 constant_linear_velocity;
real_t constant_angular_velocity = 0.0;
Ref<PhysicsMaterial> physics_material_override;
- bool kinematic_motion = false;
- bool sync_to_physics = false;
-
- Transform2D last_valid_transform;
-
- void _direct_state_changed(Object *p_state);
-
protected:
- void _notification(int p_what);
static void _bind_methods();
public:
@@ -89,17 +82,32 @@ public:
Vector2 get_constant_linear_velocity() const;
real_t get_constant_angular_velocity() const;
- virtual TypedArray<String> get_configuration_warnings() const override;
-
- StaticBody2D();
+ StaticBody2D(PhysicsServer2D::BodyMode p_mode = PhysicsServer2D::BODY_MODE_STATIC);
private:
void _reload_physics_characteristics();
+};
- void _update_kinematic_motion();
+class AnimatableBody2D : public StaticBody2D {
+ GDCLASS(AnimatableBody2D, StaticBody2D);
+
+private:
+ bool sync_to_physics = false;
+
+ Transform2D last_valid_transform;
+
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState2D *p_state);
- void set_kinematic_motion_enabled(bool p_enabled);
- bool is_kinematic_motion_enabled() const;
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ AnimatableBody2D();
+
+private:
+ void _update_kinematic_motion();
void set_sync_to_physics(bool p_enable);
bool is_sync_to_physics_enabled() const;
@@ -116,6 +124,11 @@ public:
MODE_KINEMATIC,
};
+ enum CenterOfMassMode {
+ CENTER_OF_MASS_MODE_AUTO,
+ CENTER_OF_MASS_MODE_CUSTOM,
+ };
+
enum CCDMode {
CCD_MODE_DISABLED,
CCD_MODE_CAST_RAY,
@@ -124,10 +137,13 @@ public:
private:
bool can_sleep = true;
- PhysicsDirectBodyState2D *state = nullptr;
Mode mode = MODE_DYNAMIC;
real_t mass = 1.0;
+ real_t inertia = 0.0;
+ CenterOfMassMode center_of_mass_mode = CENTER_OF_MASS_MODE_AUTO;
+ Vector2 center_of_mass;
+
Ref<PhysicsMaterial> physics_material_override;
real_t gravity_scale = 1.0;
real_t linear_damp = -1.0;
@@ -183,12 +199,18 @@ private:
void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape);
- void _direct_state_changed(Object *p_state);
+
+ static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state);
+ void _body_state_changed(PhysicsDirectBodyState2D *p_state);
protected:
void _notification(int p_what);
static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const override;
+
+ GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *)
+
public:
void set_mode(Mode p_mode);
Mode get_mode() const;
@@ -199,6 +221,12 @@ public:
void set_inertia(real_t p_inertia);
real_t get_inertia() const;
+ void set_center_of_mass_mode(CenterOfMassMode p_mode);
+ CenterOfMassMode get_center_of_mass_mode() const;
+
+ void set_center_of_mass(const Vector2 &p_center_of_mass);
+ const Vector2 &get_center_of_mass() const;
+
void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override);
Ref<PhysicsMaterial> get_physics_material_override() const;
@@ -263,26 +291,59 @@ private:
};
VARIANT_ENUM_CAST(RigidBody2D::Mode);
+VARIANT_ENUM_CAST(RigidBody2D::CenterOfMassMode);
VARIANT_ENUM_CAST(RigidBody2D::CCDMode);
class CharacterBody2D : public PhysicsBody2D {
GDCLASS(CharacterBody2D, PhysicsBody2D);
+public:
+ enum MotionMode {
+ MOTION_MODE_GROUNDED,
+ MOTION_MODE_FREE,
+ };
+ bool move_and_slide();
+
+ const Vector2 &get_linear_velocity() const;
+ void set_linear_velocity(const Vector2 &p_velocity);
+
+ bool is_on_floor() const;
+ bool is_on_floor_only() const;
+ bool is_on_wall() const;
+ bool is_on_wall_only() const;
+ bool is_on_ceiling() const;
+ bool is_on_ceiling_only() const;
+ Vector2 get_floor_normal() const;
+ real_t get_floor_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
+ Vector2 get_platform_velocity() const;
+
+ int get_slide_collision_count() const;
+ PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const;
+
+ CharacterBody2D();
+ ~CharacterBody2D();
+
private:
real_t margin = 0.08;
+ MotionMode motion_mode = MOTION_MODE_GROUNDED;
- bool stop_on_slope = false;
- bool infinite_inertia = true;
+ bool floor_stop_on_slope = false;
+ bool floor_constant_speed = false;
+ bool floor_block_on_wall = true;
+ bool slide_on_ceiling = true;
int max_slides = 4;
+ int platform_layer;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
- Vector2 snap;
+ float floor_snap_length = 0;
+ real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0);
Vector2 up_direction = Vector2(0.0, -1.0);
-
+ uint32_t moving_platform_floor_layers = UINT32_MAX;
+ uint32_t moving_platform_wall_layers = 0;
Vector2 linear_velocity;
Vector2 floor_normal;
- Vector2 floor_velocity;
- RID on_floor_body;
+ Vector2 platform_velocity;
+ RID platform_rid;
bool on_floor = false;
bool on_ceiling = false;
bool on_wall = false;
@@ -290,18 +351,20 @@ private:
Vector<PhysicsServer2D::MotionResult> motion_results;
Vector<Ref<KinematicCollision2D>> slide_colliders;
- Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
-
- bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result);
-
void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
- bool is_stop_on_slope_enabled() const;
- void set_stop_on_slope_enabled(bool p_enabled);
+ bool is_floor_stop_on_slope_enabled() const;
+ void set_floor_stop_on_slope_enabled(bool p_enabled);
+
+ bool is_floor_constant_speed_enabled() const;
+ void set_floor_constant_speed_enabled(bool p_enabled);
- bool is_infinite_inertia_enabled() const;
- void set_infinite_inertia_enabled(bool p_enabled);
+ bool is_floor_block_on_wall_enabled() const;
+ void set_floor_block_on_wall_enabled(bool p_enabled);
+
+ bool is_slide_on_ceiling_enabled() const;
+ void set_slide_on_ceiling_enabled(bool p_enabled);
int get_max_slides() const;
void set_max_slides(int p_max_slides);
@@ -309,36 +372,41 @@ private:
real_t get_floor_max_angle() const;
void set_floor_max_angle(real_t p_radians);
- const Vector2 &get_snap() const;
- void set_snap(const Vector2 &p_snap);
+ real_t get_floor_snap_length();
+ void set_floor_snap_length(real_t p_floor_snap_length);
+
+ real_t get_free_mode_min_slide_angle() const;
+ void set_free_mode_min_slide_angle(real_t p_radians);
+
+ uint32_t get_moving_platform_floor_layers() const;
+ void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
+
+ uint32_t get_moving_platform_wall_layers() const;
+ void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
+ void set_motion_mode(MotionMode p_mode);
+ MotionMode get_motion_mode() const;
+
+ void _move_and_slide_free(double p_delta);
+ void _move_and_slide_grounded(double p_delta, bool p_was_on_floor, const Vector2 &p_prev_platform_velocity);
+
+ Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
+ Ref<KinematicCollision2D> _get_last_slide_collision();
const Vector2 &get_up_direction() const;
+ bool _on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up);
void set_up_direction(const Vector2 &p_up_direction);
void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
+ void _set_platform_data(const PhysicsServer2D::MotionResult &p_result);
+ void _snap_on_floor(bool was_on_floor, bool vel_dir_facing_up);
protected:
void _notification(int p_what);
static void _bind_methods();
-
-public:
- void move_and_slide();
-
- const Vector2 &get_linear_velocity() const;
- void set_linear_velocity(const Vector2 &p_velocity);
-
- bool is_on_floor() const;
- bool is_on_wall() const;
- bool is_on_ceiling() const;
- Vector2 get_floor_normal() const;
- Vector2 get_floor_velocity() const;
-
- int get_slide_count() const;
- PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const;
-
- CharacterBody2D();
- ~CharacterBody2D();
+ virtual void _validate_property(PropertyInfo &property) const override;
};
+VARIANT_ENUM_CAST(CharacterBody2D::MotionMode);
+
class KinematicCollision2D : public RefCounted {
GDCLASS(KinematicCollision2D, RefCounted);
@@ -355,6 +423,7 @@ public:
Vector2 get_normal() const;
Vector2 get_travel() const;
Vector2 get_remainder() const;
+ real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
Object *get_local_shape() const;
Object *get_collider() const;
ObjectID get_collider_id() const;
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index 1019f85c8a..4f053ff8b0 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -30,9 +30,6 @@
#include "position_2d.h"
-#include "core/config/engine.h"
-#include "scene/resources/texture.h"
-
const real_t DEFAULT_GIZMO_EXTENTS = 10.0;
void Position2D::_draw_cross() {
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index f6740040c1..3ac2128c2e 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -31,9 +31,6 @@
#include "ray_cast_2d.h"
#include "collision_object_2d.h"
-#include "core/config/engine.h"
-#include "physics_body_2d.h"
-#include "servers/physics_server_2d.h"
void RayCast2D::set_target_position(const Vector2 &p_point) {
target_position = p_point;
@@ -54,20 +51,22 @@ uint32_t RayCast2D::get_collision_mask() const {
return collision_mask;
}
-void RayCast2D::set_collision_mask_bit(int p_bit, bool p_value) {
- ERR_FAIL_INDEX_MSG(p_bit, 32, "Collision mask bit must be between 0 and 31 inclusive.");
+void RayCast2D::set_collision_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
- mask |= 1 << p_bit;
+ mask |= 1 << (p_layer_number - 1);
} else {
- mask &= ~(1 << p_bit);
+ mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
-bool RayCast2D::get_collision_mask_bit(int p_bit) const {
- ERR_FAIL_INDEX_V_MSG(p_bit, 32, false, "Collision mask bit must be between 0 and 31 inclusive.");
- return get_collision_mask() & (1 << p_bit);
+bool RayCast2D::get_collision_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
+ ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
+ return get_collision_mask() & (1 << (p_layer_number - 1));
}
bool RayCast2D::is_colliding() const {
@@ -212,17 +211,17 @@ void RayCast2D::_update_raycast_state() {
void RayCast2D::_draw_debug_shape() {
Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color();
if (!enabled) {
- float g = draw_col.get_v();
+ const float g = draw_col.get_v();
draw_col.r = g;
draw_col.g = g;
draw_col.b = g;
}
// Draw an arrow indicating where the RayCast is pointing to
- const float max_arrow_size = 6;
- const float line_width = 1.4;
+ const real_t max_arrow_size = 6;
+ const real_t line_width = 1.4;
bool no_line = target_position.length() < line_width;
- float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
+ real_t arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
if (no_line) {
arrow_size = target_position.length();
@@ -323,8 +322,8 @@ void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &RayCast2D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &RayCast2D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &RayCast2D::set_collision_mask_bit);
- ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &RayCast2D::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &RayCast2D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &RayCast2D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_exclude_parent_body", "mask"), &RayCast2D::set_exclude_parent_body);
ClassDB::bind_method(D_METHOD("get_exclude_parent_body"), &RayCast2D::get_exclude_parent_body);
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 984c6bda49..65b6e7899b 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -74,8 +74,8 @@ public:
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
- void set_collision_mask_bit(int p_bit, bool p_value);
- bool get_collision_mask_bit(int p_bit) const;
+ void set_collision_mask_value(int p_layer_number, bool p_value);
+ bool get_collision_mask_value(int p_layer_number) const;
void set_exclude_parent_body(bool p_exclude_parent_body);
bool get_exclude_parent_body() const;
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index e7cef965fe..fe3e867424 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -29,7 +29,6 @@
/*************************************************************************/
#include "remote_transform_2d.h"
-#include "scene/scene_string_names.h"
void RemoteTransform2D::_update_cache() {
cache = ObjectID();
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 15cbdf535e..4bbbc3575d 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -30,8 +30,6 @@
#include "skeleton_2d.h"
-#include "scene/resources/skeleton_modification_2d.h"
-
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
@@ -45,7 +43,7 @@ bool Bone2D::_set(const StringName &p_path, const Variant &p_value) {
} else if (path.begins_with("length")) {
set_length(p_value);
} else if (path.begins_with("bone_angle")) {
- set_bone_angle(Math::deg2rad(float(p_value)));
+ set_bone_angle(Math::deg2rad(real_t(p_value)));
} else if (path.begins_with("default_length")) {
set_length(p_value);
}
@@ -327,10 +325,10 @@ bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p
Vector2 rel;
if (p_other_bone) {
- rel = (p_other_bone->get_global_transform().get_origin() - get_global_transform().get_origin());
+ rel = (p_other_bone->get_global_position() - get_global_position());
rel = rel.rotated(-get_global_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation
} else {
- float angle_to_use = get_rotation() + bone_angle;
+ real_t angle_to_use = get_rotation() + bone_angle;
rel = Vector2(cos(angle_to_use), sin(angle_to_use)) * (length * MIN(get_global_scale().x, get_global_scale().y));
rel = rel.rotated(-get_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation
}
@@ -414,12 +412,12 @@ void Bone2D::apply_rest() {
set_transform(rest);
}
-void Bone2D::set_default_length(float p_length) {
+void Bone2D::set_default_length(real_t p_length) {
WARN_DEPRECATED_MSG("set_default_length is deprecated. Please use set_length instead!");
set_length(p_length);
}
-float Bone2D::get_default_length() const {
+real_t Bone2D::get_default_length() const {
WARN_DEPRECATED_MSG("get_default_length is deprecated. Please use get_length instead!");
return get_length();
}
@@ -456,7 +454,7 @@ void Bone2D::calculate_length_and_rotation() {
for (int i = 0; i < child_count; i++) {
Bone2D *child = Object::cast_to<Bone2D>(get_child(i));
if (child) {
- Vector2 child_local_pos = to_local(child->get_global_transform().get_origin());
+ Vector2 child_local_pos = to_local(child->get_global_position());
length = child_local_pos.length();
bone_angle = Math::atan2(child_local_pos.normalized().y, child_local_pos.normalized().x);
calculated = true;
@@ -485,7 +483,7 @@ bool Bone2D::get_autocalculate_length_and_angle() const {
return autocalculate_length_and_angle;
}
-void Bone2D::set_length(float p_length) {
+void Bone2D::set_length(real_t p_length) {
length = p_length;
#ifdef TOOLS_ENABLED
@@ -493,11 +491,11 @@ void Bone2D::set_length(float p_length) {
#endif // TOOLS_ENABLED
}
-float Bone2D::get_length() const {
+real_t Bone2D::get_length() const {
return length;
}
-void Bone2D::set_bone_angle(float p_angle) {
+void Bone2D::set_bone_angle(real_t p_angle) {
bone_angle = p_angle;
#ifdef TOOLS_ENABLED
@@ -505,7 +503,7 @@ void Bone2D::set_bone_angle(float p_angle) {
#endif // TOOLS_ENABLED
}
-float Bone2D::get_bone_angle() const {
+real_t Bone2D::get_bone_angle() const {
return bone_angle;
}
@@ -690,7 +688,7 @@ RID Skeleton2D::get_skeleton() const {
return skeleton;
}
-void Skeleton2D::set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent) {
+void Skeleton2D::set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, real_t p_amount, bool p_persistent) {
ERR_FAIL_INDEX_MSG(p_bone_idx, bones.size(), "Bone index is out of range!");
bones.write[p_bone_idx].local_pose_override = p_override;
bones.write[p_bone_idx].local_pose_override_amount = p_amount;
@@ -728,7 +726,7 @@ Ref<SkeletonModificationStack2D> Skeleton2D::get_modification_stack() const {
return modification_stack;
}
-void Skeleton2D::execute_modifications(float p_delta, int p_execution_mode) {
+void Skeleton2D::execute_modifications(real_t p_delta, int p_execution_mode) {
if (!modification_stack.is_valid()) {
return;
}
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
index 59bd711960..56fd0e8504 100644
--- a/scene/2d/skeleton_2d.h
+++ b/scene/2d/skeleton_2d.h
@@ -49,8 +49,8 @@ class Bone2D : public Node2D {
Transform2D rest;
bool autocalculate_length_and_angle = true;
- float length = 16;
- float bone_angle = 0;
+ real_t length = 16;
+ real_t bone_angle = 0;
int skeleton_index = -1;
@@ -85,10 +85,10 @@ public:
void set_autocalculate_length_and_angle(bool p_autocalculate);
bool get_autocalculate_length_and_angle() const;
- void set_length(float p_length);
- float get_length() const;
- void set_bone_angle(float p_angle);
- float get_bone_angle() const;
+ void set_length(real_t p_length);
+ real_t get_length() const;
+ void set_bone_angle(real_t p_angle);
+ real_t get_bone_angle() const;
int get_index_in_skeleton() const;
@@ -122,7 +122,7 @@ class Skeleton2D : public Node2D {
//Transform2D local_pose_cache;
Transform2D local_pose_override;
- float local_pose_override_amount = 0;
+ real_t local_pose_override_amount = 0;
bool local_pose_override_persistent = false;
};
@@ -153,12 +153,12 @@ public:
RID get_skeleton() const;
- void set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent = true);
+ void set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, real_t p_amount, bool p_persistent = true);
Transform2D get_bone_local_pose_override(int p_bone_idx);
Ref<SkeletonModificationStack2D> get_modification_stack() const;
void set_modification_stack(Ref<SkeletonModificationStack2D> p_stack);
- void execute_modifications(float p_delta, int p_execution_mode);
+ void execute_modifications(real_t p_delta, int p_execution_mode);
Skeleton2D();
~Skeleton2D();
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index 40e0f4523f..5761f19a53 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -31,7 +31,6 @@
#include "sprite_2d.h"
#include "core/core_string_names.h"
-#include "core/os/os.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 6afa0c0779..0eb424b32c 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -31,8 +31,6 @@
#include "tile_map.h"
#include "core/io/marshalls.h"
-#include "core/math/geometry_2d.h"
-#include "core/os/os.h"
#include "servers/navigation_server_2d.h"
@@ -238,6 +236,8 @@ Vector2i TileMap::transform_coords_layout(Vector2i p_coords, TileSet::TileOffset
}
int TileMap::get_effective_quadrant_size(int p_layer) const {
+ ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), 1);
+
// When using YSort, the quadrant size is reduced to 1 to have one CanvasItem per quadrant
if (is_y_sort_enabled() && layers[p_layer].y_sort_enabled) {
return 1;
@@ -316,16 +316,38 @@ int TileMap::get_quadrant_size() const {
return quadrant_size;
}
-void TileMap::set_layers_count(int p_layers_count) {
- ERR_FAIL_COND(p_layers_count < 0);
- _clear_internals();
+int TileMap::get_layers_count() const {
+ return layers.size();
+}
+
+void TileMap::add_layer(int p_to_pos) {
+ if (p_to_pos < 0) {
+ p_to_pos = layers.size();
+ }
+
+ ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
+
+ layers.insert(p_to_pos, TileMapLayer());
+ _recreate_internals();
+ notify_property_list_changed();
+
+ emit_signal(SNAME("changed"));
+
+ update_configuration_warnings();
+}
+
+void TileMap::move_layer(int p_layer, int p_to_pos) {
+ ERR_FAIL_INDEX(p_layer, (int)layers.size());
+ ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
- layers.resize(p_layers_count);
+ TileMapLayer tl = layers[p_layer];
+ layers.insert(p_to_pos, tl);
+ layers.remove(p_to_pos < p_layer ? p_layer + 1 : p_layer);
_recreate_internals();
notify_property_list_changed();
- if (selected_layer >= p_layers_count) {
- selected_layer = -1;
+ if (selected_layer == p_layer) {
+ selected_layer = p_to_pos < p_layer ? p_to_pos - 1 : p_to_pos;
}
emit_signal(SNAME("changed"));
@@ -333,8 +355,20 @@ void TileMap::set_layers_count(int p_layers_count) {
update_configuration_warnings();
}
-int TileMap::get_layers_count() const {
- return layers.size();
+void TileMap::remove_layer(int p_layer) {
+ ERR_FAIL_INDEX(p_layer, (int)layers.size());
+
+ layers.remove(p_layer);
+ _recreate_internals();
+ notify_property_list_changed();
+
+ if (selected_layer >= p_layer) {
+ selected_layer -= 1;
+ }
+
+ emit_signal(SNAME("changed"));
+
+ update_configuration_warnings();
}
void TileMap::set_layer_name(int p_layer, String p_name) {
@@ -783,8 +817,8 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
if (atlas_source) {
// Get the tile data.
TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
- Ref<ShaderMaterial> mat = tile_data->tile_get_material();
- int z_index = layers[q.layer].z_index + tile_data->get_z_index();
+ Ref<ShaderMaterial> mat = tile_data->get_material();
+ int z_index = tile_data->get_z_index();
// Quandrant pos.
Vector2 position = map_to_world(q.coords * get_effective_quadrant_size(q.layer));
@@ -1053,9 +1087,13 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
Vector2 quadrant_pos = map_to_world(q.coords * get_effective_quadrant_size(q.layer));
+ LocalVector<int> body_shape_count;
+ body_shape_count.resize(q.bodies.size());
+
// Clear shapes.
for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
ps->body_clear_shapes(q.bodies[body_index]);
+ body_shape_count[body_index] = 0;
// Position the bodies.
Transform2D xform;
@@ -1080,6 +1118,8 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
+ int &body_shape_index = body_shape_count[body_index];
+
// Add the shapes again.
for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) {
bool one_way_collision = tile_data->is_collision_polygon_one_way(body_index, polygon_index);
@@ -1093,8 +1133,10 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
// Add decomposed convex shapes.
Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(body_index, polygon_index, shape_index);
ps->body_add_shape(q.bodies[body_index], shape->get_rid(), xform);
- ps->body_set_shape_metadata(q.bodies[body_index], shape_index, E_cell->get());
- ps->body_set_shape_as_one_way_collision(q.bodies[body_index], shape_index, one_way_collision, one_way_collision_margin);
+ ps->body_set_shape_metadata(q.bodies[body_index], body_shape_index, E_cell->get());
+ ps->body_set_shape_as_one_way_collision(q.bodies[body_index], body_shape_index, one_way_collision, one_way_collision_margin);
+
+ ++body_shape_index;
}
}
}
@@ -1141,7 +1183,7 @@ void TileMap::_physics_create_quadrant(TileMapQuadrant *p_quadrant) {
PhysicsServer2D::get_singleton()->body_set_space(body, space);
Transform2D xform;
- xform.set_origin(map_to_world(p_quadrant->coords * get_effective_quadrant_size(layer)));
+ xform.set_origin(map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)));
xform = global_transform * xform;
PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform);
}
@@ -1576,7 +1618,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
_make_quadrant_dirty(Q);
}
- used_size_cache_dirty = true;
+ used_rect_cache_dirty = true;
} else {
if (!E) {
// Insert a new cell in the tile map.
@@ -1604,7 +1646,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
c.alternative_tile = alternative_tile;
_make_quadrant_dirty(Q);
- used_size_cache_dirty = true;
+ used_rect_cache_dirty = true;
}
}
@@ -1800,7 +1842,7 @@ void TileMap::clear_layer(int p_layer) {
_clear_layer_internals(p_layer);
layers[p_layer].tile_map.clear();
- used_size_cache_dirty = true;
+ used_rect_cache_dirty = true;
}
void TileMap::clear() {
@@ -1809,7 +1851,7 @@ void TileMap::clear() {
for (unsigned int i = 0; i < layers.size(); i++) {
layers[i].tile_map.clear();
}
- used_size_cache_dirty = true;
+ used_rect_cache_dirty = true;
}
void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) {
@@ -2666,25 +2708,31 @@ TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const {
Rect2 TileMap::get_used_rect() { // Not const because of cache
// Return the rect of the currently used area
- if (used_size_cache_dirty) {
+ if (used_rect_cache_dirty) {
bool first = true;
+ used_rect_cache = Rect2i();
+
for (unsigned int i = 0; i < layers.size(); i++) {
const Map<Vector2i, TileMapCell> &tile_map = layers[i].tile_map;
if (tile_map.size() > 0) {
if (first) {
- used_size_cache = Rect2(tile_map.front()->key().x, tile_map.front()->key().y, 1, 1);
+ used_rect_cache = Rect2i(tile_map.front()->key().x, tile_map.front()->key().y, 0, 0);
first = false;
}
for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) {
- used_size_cache.expand_to(Vector2(E->key().x + 1, E->key().y + 1));
+ used_rect_cache.expand_to(Vector2i(E->key().x, E->key().y));
}
}
}
- used_size_cache_dirty = false;
+
+ if (!first) { // first is true if every layer is empty.
+ used_rect_cache.size += Vector2i(1, 1); // The cache expands to top-left coordinate, so we add one full tile.
+ }
+ used_rect_cache_dirty = false;
}
- return used_size_cache;
+ return used_rect_cache;
}
// --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems ---
@@ -2884,8 +2932,10 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_quadrant_size", "size"), &TileMap::set_quadrant_size);
ClassDB::bind_method(D_METHOD("get_quadrant_size"), &TileMap::get_quadrant_size);
- ClassDB::bind_method(D_METHOD("set_layers_count", "layers_count"), &TileMap::set_layers_count);
ClassDB::bind_method(D_METHOD("get_layers_count"), &TileMap::get_layers_count);
+ ClassDB::bind_method(D_METHOD("add_layer", "to_position"), &TileMap::add_layer);
+ ClassDB::bind_method(D_METHOD("move_layer", "layer", "to_position"), &TileMap::move_layer);
+ ClassDB::bind_method(D_METHOD("remove_layer", "layer"), &TileMap::remove_layer);
ClassDB::bind_method(D_METHOD("set_layer_name", "layer", "name"), &TileMap::set_layer_name);
ClassDB::bind_method(D_METHOD("get_layer_name", "layer"), &TileMap::get_layer_name);
ClassDB::bind_method(D_METHOD("set_layer_enabled", "layer", "enabled"), &TileMap::set_layer_enabled);
@@ -2895,7 +2945,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_y_sort_origin", "layer", "y_sort_origin"), &TileMap::set_layer_y_sort_origin);
ClassDB::bind_method(D_METHOD("get_layer_y_sort_origin", "layer"), &TileMap::get_layer_y_sort_origin);
ClassDB::bind_method(D_METHOD("set_layer_z_index", "layer", "z_index"), &TileMap::set_layer_z_index);
- ClassDB::bind_method(D_METHOD("get_layer_z_indexd", "layer"), &TileMap::get_layer_z_index);
+ ClassDB::bind_method(D_METHOD("get_layer_z_index", "layer"), &TileMap::get_layer_z_index);
ClassDB::bind_method(D_METHOD("set_collision_visibility_mode", "collision_visibility_mode"), &TileMap::set_collision_visibility_mode);
ClassDB::bind_method(D_METHOD("get_collision_visibility_mode"), &TileMap::get_collision_visibility_mode);
@@ -2930,9 +2980,7 @@ void TileMap::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_collision_visibility_mode", "get_collision_visibility_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_navigation_visibility_mode", "get_navigation_visibility_mode");
- ADD_GROUP("Layers", "");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layers_count"), "set_layers_count", "get_layers_count");
- ADD_PROPERTY_DEFAULT("layers_count", 1);
+ ADD_ARRAY("layers", "layer_");
ADD_PROPERTY_DEFAULT("format", FORMAT_1);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 4800780f94..3ac50fc7cc 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -31,8 +31,6 @@
#ifndef TILE_MAP_H
#define TILE_MAP_H
-#include "core/templates/self_list.h"
-#include "core/templates/vset.h"
#include "scene/2d/node_2d.h"
#include "scene/gui/control.h"
#include "scene/resources/tile_set.h"
@@ -213,8 +211,8 @@ private:
// Rect.
Rect2 rect_cache;
bool rect_cache_dirty = true;
- Rect2 used_size_cache;
- bool used_size_cache_dirty = true;
+ Rect2i used_rect_cache;
+ bool used_rect_cache_dirty = true;
// TileMap layers.
struct TileMapLayer {
@@ -310,8 +308,10 @@ public:
static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0));
// Layers management.
- void set_layers_count(int p_layers_count);
int get_layers_count() const;
+ void add_layer(int p_to_pos);
+ void move_layer(int p_layer, int p_to_pos);
+ void remove_layer(int p_layer);
void set_layer_name(int p_layer, String p_name);
String get_layer_name(int p_layer) const;
void set_layer_enabled(int p_layer, bool p_visible);
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 7c345ad377..8bd7b696f2 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -30,11 +30,8 @@
#include "touch_screen_button.h"
-#include "core/input/input.h"
-#include "core/input/input_map.h"
-#include "core/os/os.h"
#include "scene/main/window.h"
-#
+
void TouchScreenButton::set_texture(const Ref<Texture2D> &p_texture) {
texture = p_texture;
update();
@@ -188,7 +185,7 @@ String TouchScreenButton::get_action() const {
return action;
}
-void TouchScreenButton::_input(const Ref<InputEvent> &p_event) {
+void TouchScreenButton::input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!get_tree()) {
@@ -291,7 +288,7 @@ void TouchScreenButton::_press(int p_finger_pressed) {
iea.instantiate();
iea->set_action(action);
iea->set_pressed(true);
- get_viewport()->input(iea, true);
+ get_viewport()->push_input(iea, true);
}
emit_signal(SNAME("pressed"));
@@ -308,7 +305,7 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
iea.instantiate();
iea->set_action(action);
iea->set_pressed(false);
- get_viewport()->input(iea, true);
+ get_viewport()->push_input(iea, true);
}
}
@@ -387,8 +384,6 @@ void TouchScreenButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_pressed"), &TouchScreenButton::is_pressed);
- ClassDB::bind_method(D_METHOD("_input"), &TouchScreenButton::_input);
-
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_pressed", "get_texture_pressed");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "bitmask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_bitmask", "get_bitmask");
diff --git a/scene/2d/touch_screen_button.h b/scene/2d/touch_screen_button.h
index 10820ad059..1c515149d4 100644
--- a/scene/2d/touch_screen_button.h
+++ b/scene/2d/touch_screen_button.h
@@ -61,7 +61,7 @@ private:
VisibilityMode visibility = VISIBILITY_ALWAYS;
- void _input(const Ref<InputEvent> &p_event);
+ virtual void input(const Ref<InputEvent> &p_event) override;
bool _is_point_inside(const Point2 &p_point);
diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp
index 25237edacf..eb4bedb6a3 100644
--- a/scene/2d/visible_on_screen_notifier_2d.cpp
+++ b/scene/2d/visible_on_screen_notifier_2d.cpp
@@ -30,12 +30,6 @@
#include "visible_on_screen_notifier_2d.h"
-#include "core/config/engine.h"
-#include "gpu_particles_2d.h"
-#include "scene/2d/animated_sprite_2d.h"
-#include "scene/2d/physics_body_2d.h"
-#include "scene/animation/animation_player.h"
-#include "scene/main/window.h"
#include "scene/scene_string_names.h"
#ifdef TOOLS_ENABLED