summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/animated_sprite_2d.cpp1
-rw-r--r--scene/2d/animated_sprite_2d.h1
-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.cpp8
-rw-r--r--scene/2d/collision_object_2d.h4
-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.cpp256
-rw-r--r--scene/2d/cpu_particles_2d.h24
-rw-r--r--scene/2d/gpu_particles_2d.cpp4
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/joints_2d.cpp4
-rw-r--r--scene/2d/light_2d.cpp3
-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.cpp1
-rw-r--r--scene/2d/node_2d.cpp5
-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.cpp657
-rw-r--r--scene/2d/physics_body_2d.h154
-rw-r--r--scene/2d/position_2d.cpp3
-rw-r--r--scene/2d/ray_cast_2d.cpp3
-rw-r--r--scene/2d/remote_transform_2d.cpp1
-rw-r--r--scene/2d/skeleton_2d.cpp6
-rw-r--r--scene/2d/sprite_2d.cpp1
-rw-r--r--scene/2d/tile_map.cpp76
-rw-r--r--scene/2d/tile_map.h6
-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
41 files changed, 1094 insertions, 810 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 026f0a85a6..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"
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 0769b19b50..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);
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 60f29ca163..5d3a538f60 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -481,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);
}
@@ -597,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 11e11d1382..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;
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 ced1c5cb81..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) {
@@ -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) {
@@ -697,14 +729,14 @@ void CPUParticles2D::_particles_process(double 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(double 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(double 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(double 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(double 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(double 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, 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(double 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 1a1f35fca5..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:
@@ -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,6 +167,10 @@ 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();
@@ -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 58525c6954..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"
@@ -297,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."));
}
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 67a87f2339..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:
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.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 58b20ccad0..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"
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index a744ef40f6..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;
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 fa19d5c2cf..30f012c7aa 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -30,12 +30,7 @@
#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() {
@@ -75,12 +70,12 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_t
return Ref<KinematicCollision2D>();
}
-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, 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_margin, &r_result, 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,
@@ -107,21 +102,21 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M
}
// 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);
}
@@ -170,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 {
@@ -214,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();
@@ -298,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.
@@ -309,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);
+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);
- 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);
-
- 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) {
@@ -516,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) {
@@ -551,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) {
@@ -617,8 +521,6 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
contact_monitor->locked = false;
}
-
- state = nullptr;
}
void RigidBody2D::set_mode(Mode p_mode) {
@@ -658,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) {
@@ -714,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 {
@@ -741,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 {
@@ -930,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);
@@ -983,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");
@@ -1017,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() {
@@ -1048,16 +998,21 @@ void RigidBody2D::_reload_physics_characteristics() {
// 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() {
+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.
- float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+ double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
Vector2 current_platform_velocity = platform_velocity;
if ((on_floor || on_wall) && platform_rid.is_valid()) {
- bool excluded = (exclude_body_layers & platform_layer) != 0;
+ 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.
+ //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();
@@ -1080,16 +1035,30 @@ void CharacterBody2D::move_and_slide() {
PhysicsServer2D::MotionResult floor_result;
Set<RID> exclude;
exclude.insert(platform_rid);
- if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, false, exclude)) {
+ 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);
}
}
- 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_platform_velocity = current_platform_velocity;
Vector2 prev_floor_normal = floor_normal;
RID prev_platform_rid = platform_rid;
int prev_platform_layer = platform_layer;
@@ -1100,7 +1069,7 @@ void CharacterBody2D::move_and_slide() {
// No sliding on first attempt to keep floor motion stable when possible,
// When stop on slope is enabled or when there is no up direction.
- bool sliding_enabled = !stop_on_slope || up_direction == Vector2();
+ 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;
@@ -1109,23 +1078,21 @@ void CharacterBody2D::move_and_slide() {
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionResult result;
- bool found_collision = false;
Vector2 prev_position = get_global_transform().elements[2];
bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
if (collided) {
- found_collision = true;
motion_results.push_back(result);
_set_collision_direction(result);
- if (on_floor && stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
+ if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
Transform2D gt = get_global_transform();
- if (result.motion.length() > margin) {
- gt.elements[2] -= result.motion.slide(up_direction);
+ if (result.travel.length() > margin) {
+ gt.elements[2] -= result.travel.slide(up_direction);
} else {
- gt.elements[2] -= result.motion;
+ gt.elements[2] -= result.travel;
}
set_global_transform(gt);
linear_velocity = Vector2();
@@ -1139,28 +1106,27 @@ void CharacterBody2D::move_and_slide() {
}
// Move on floor only checks.
- if (move_on_floor_only && on_wall && motion_slide_up.dot(result.collision_normal) <= 0) {
- // Avoid to move forward on a wall if move_on_floor_only is true.
- if (was_on_floor && !is_on_floor_only() && !vel_dir_facing_up) {
+ 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.motion.length() <= margin) {
+ if (result.travel.length() <= margin) {
// Cancels the motion.
Transform2D gt = get_global_transform();
- gt.elements[2] -= result.motion;
+ gt.elements[2] -= result.travel;
set_global_transform(gt);
}
on_floor = true;
platform_rid = prev_platform_rid;
platform_layer = prev_platform_layer;
-
- platform_velocity = prev_platform_velocity;
+ platform_velocity = p_prev_platform_velocity;
floor_normal = prev_floor_normal;
linear_velocity = Vector2();
motion = Vector2();
break;
}
// Prevents the body from being able to climb a slope when it moves forward against the wall.
- else if (!is_on_floor_only()) {
+ else if (!on_floor) {
motion = up_direction * up_direction.dot(result.remainder);
motion = motion.slide(result.collision_normal);
} else {
@@ -1168,12 +1134,10 @@ void CharacterBody2D::move_and_slide() {
}
}
// Constant Speed when the slope is upward.
- else if (constant_speed_on_floor && is_on_floor_only() && can_apply_constant_speed && was_on_floor && motion.dot(result.collision_normal) < 0) {
+ 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();
- if (!motion_slide_norm.is_equal_approx(Vector2())) {
- motion = motion_slide_norm * (motion_slide_up.length() - result.motion.slide(up_direction).length() - last_travel.slide(up_direction).length());
- }
+ 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)) {
@@ -1202,11 +1166,11 @@ void CharacterBody2D::move_and_slide() {
}
}
- last_travel = result.motion;
+ 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 (constant_speed_on_floor && first_slide && _on_floor_if_snapped(was_on_floor, vel_dir_facing_up)) {
+ 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();
@@ -1214,27 +1178,20 @@ void CharacterBody2D::move_and_slide() {
set_global_transform(gt);
Vector2 motion_slide_norm = motion.slide(prev_floor_normal).normalized();
- if (!motion_slide_norm.is_equal_approx(Vector2())) {
- motion = motion_slide_norm * (motion_slide_up.length());
- found_collision = true;
- }
+ motion = motion_slide_norm * (motion_slide_up.length());
+ collided = true;
}
can_apply_constant_speed = !can_apply_constant_speed && !sliding_enabled;
sliding_enabled = true;
first_slide = false;
- if (!found_collision || motion.is_equal_approx(Vector2())) {
+ if (!collided || motion.is_equal_approx(Vector2())) {
break;
}
}
- _snap_on_floor(was_on_floor, vel_dir_facing_up);
-
- if (!on_floor && !on_wall) {
- // Add last platform velocity when just left a moving platform.
- linear_velocity += current_platform_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) {
@@ -1242,29 +1199,66 @@ void CharacterBody2D::move_and_slide() {
}
}
+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;
+ }
+ }
+}
+
void CharacterBody2D::_snap_on_floor(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) {
+ if (Math::is_equal_approx(floor_snap_length, 0) || on_floor || !was_on_floor || vel_dir_facing_up) {
return;
}
Transform2D gt = get_global_transform();
PhysicsServer2D::MotionResult result;
- if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false)) {
+ if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false, true)) {
bool apply = true;
- float collision_angle = Math::acos(result.collision_normal.dot(up_direction));
- if (collision_angle <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
on_floor = true;
floor_normal = result.collision_normal;
- platform_velocity = result.collider_velocity;
_set_platform_data(result);
- if (stop_on_slope) {
+ 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.motion.length() > margin) {
- result.motion = up_direction * up_direction.dot(result.motion);
+ if (result.travel.length() > margin) {
+ result.travel = up_direction * up_direction.dot(result.travel);
} else {
- result.motion = Vector2();
+ result.travel = Vector2();
}
}
} else {
@@ -1272,7 +1266,7 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
}
if (apply) {
- gt.elements[2] += result.motion;
+ gt.elements[2] += result.travel;
set_global_transform(gt);
}
}
@@ -1284,8 +1278,8 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin
}
PhysicsServer2D::MotionResult result;
- if (move_and_collide(up_direction * -floor_snap_length, result, margin, true, false)) {
- if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
+ 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;
}
}
@@ -1294,26 +1288,24 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin
}
void CharacterBody2D::_set_collision_direction(const PhysicsServer2D::MotionResult &p_result) {
- if (up_direction == Vector2()) {
- return;
- }
-
- if (Math::acos(p_result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
+ 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;
- platform_velocity = p_result.collider_velocity;
_set_platform_data(p_result);
- } else if (Math::acos(p_result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
+ } 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;
- platform_velocity = p_result.collider_velocity;
- _set_platform_data(p_result);
+ // 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);
+ }
}
}
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) {
@@ -1357,11 +1349,16 @@ Vector2 CharacterBody2D::get_floor_normal() const {
return floor_normal;
}
+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));
+}
+
Vector2 CharacterBody2D::get_platform_velocity() const {
return platform_velocity;
}
-int CharacterBody2D::get_slide_count() const {
+int CharacterBody2D::get_slide_collision_count() const {
return motion_results.size();
}
@@ -1385,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;
}
@@ -1393,28 +1397,28 @@ 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_constant_speed_on_floor_enabled() const {
- return constant_speed_on_floor;
+bool CharacterBody2D::is_floor_constant_speed_enabled() const {
+ return floor_constant_speed;
}
-void CharacterBody2D::set_constant_speed_on_floor_enabled(bool p_enabled) {
- constant_speed_on_floor = p_enabled;
+void CharacterBody2D::set_floor_constant_speed_enabled(bool p_enabled) {
+ floor_constant_speed = p_enabled;
}
-bool CharacterBody2D::is_move_on_floor_only_enabled() const {
- return move_on_floor_only;
+bool CharacterBody2D::is_floor_block_on_wall_enabled() const {
+ return floor_block_on_wall;
}
-void CharacterBody2D::set_move_on_floor_only_enabled(bool p_enabled) {
- move_on_floor_only = p_enabled;
+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 {
@@ -1425,12 +1429,28 @@ void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) {
slide_on_ceiling = p_enabled;
}
-uint32_t CharacterBody2D::get_exclude_body_layers() const {
- return exclude_body_layers;
+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;
}
-void CharacterBody2D::set_exclude_body_layers(uint32_t p_exclude_layers) {
- exclude_body_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 {
@@ -1459,11 +1479,20 @@ void CharacterBody2D::set_floor_snap_length(real_t p_floor_snap_length) {
floor_snap_length = p_floor_snap_length;
}
+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 {
return up_direction;
}
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();
}
@@ -1489,17 +1518,19 @@ 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("set_constant_speed_on_floor_enabled", "enabled"), &CharacterBody2D::set_constant_speed_on_floor_enabled);
- ClassDB::bind_method(D_METHOD("is_constant_speed_on_floor_enabled"), &CharacterBody2D::is_constant_speed_on_floor_enabled);
- ClassDB::bind_method(D_METHOD("set_move_on_floor_only_enabled", "enabled"), &CharacterBody2D::set_move_on_floor_only_enabled);
- ClassDB::bind_method(D_METHOD("is_move_on_floor_only_enabled"), &CharacterBody2D::is_move_on_floor_only_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_exclude_body_layers", "exclude_layer"), &CharacterBody2D::set_exclude_body_layers);
- ClassDB::bind_method(D_METHOD("get_exclude_body_layers"), &CharacterBody2D::get_exclude_body_layers);
+ 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);
@@ -1507,8 +1538,12 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle);
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);
@@ -1517,22 +1552,44 @@ void CharacterBody2D::_bind_methods() {
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_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_count"), &CharacterBody2D::get_slide_count);
+ 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, "constant_speed_on_floor"), "set_constant_speed_on_floor_enabled", "is_constant_speed_on_floor_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "move_on_floor_only"), "set_move_on_floor_only_enabled", "is_move_on_floor_only_enabled");
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_RANGE, "1,8,1,or_greater"), "set_max_slides", "get_max_slides");
+ 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_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "exclude_body_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_exclude_body_layers", "get_exclude_body_layers");
-
+ 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() :
@@ -1558,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;
@@ -1619,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 3d894416f0..1d6437a3ad 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -50,7 +50,7 @@ protected:
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, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
+ 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();
@@ -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,24 +291,54 @@ 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 constant_speed_on_floor = false;
- bool move_on_floor_only = 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);
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 exclude_body_layers = 0;
+ uint32_t moving_platform_floor_layers = UINT32_MAX;
+ uint32_t moving_platform_wall_layers = 0;
Vector2 linear_velocity;
Vector2 floor_normal;
@@ -296,14 +354,14 @@ private:
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_constant_speed_on_floor_enabled() const;
- void set_constant_speed_on_floor_enabled(bool p_enabled);
+ bool is_floor_constant_speed_enabled() const;
+ void set_floor_constant_speed_enabled(bool p_enabled);
- bool is_move_on_floor_only_enabled() const;
- void set_move_on_floor_only_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);
@@ -317,10 +375,23 @@ private:
real_t get_floor_snap_length();
void set_floor_snap_length(real_t p_floor_snap_length);
- uint32_t get_exclude_body_layers() const;
- void set_exclude_body_layers(const uint32_t p_exclude_layer);
+ 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);
@@ -331,29 +402,11 @@ private:
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_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;
- Vector2 get_platform_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);
@@ -370,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 546536f546..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;
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 85d632af00..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"
@@ -327,7 +325,7 @@ 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 {
real_t angle_to_use = get_rotation() + bone_angle;
@@ -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;
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 e2a415e5aa..e1552b3b60 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"
@@ -316,16 +314,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 +353,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) {
@@ -784,7 +816,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
// 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();
+ 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 +1085,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 +1116,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 +1131,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 +1181,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);
}
@@ -2890,8 +2930,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"), &TileMap::add_layer);
+ ClassDB::bind_method(D_METHOD("move_layer"), &TileMap::move_layer);
+ ClassDB::bind_method(D_METHOD("remove_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);
@@ -2936,9 +2978,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 dce18f7682..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"
@@ -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