diff options
Diffstat (limited to 'scene/2d')
-rw-r--r-- | scene/2d/animated_sprite.cpp | 1 | ||||
-rw-r--r-- | scene/2d/audio_stream_player_2d.cpp | 12 | ||||
-rw-r--r-- | scene/2d/canvas_item.cpp | 214 | ||||
-rw-r--r-- | scene/2d/canvas_item.h | 94 | ||||
-rw-r--r-- | scene/2d/collision_object_2d.cpp | 339 | ||||
-rw-r--r-- | scene/2d/collision_object_2d.h | 62 | ||||
-rw-r--r-- | scene/2d/collision_polygon_2d.cpp | 186 | ||||
-rw-r--r-- | scene/2d/collision_polygon_2d.h | 32 | ||||
-rw-r--r-- | scene/2d/collision_shape_2d.cpp | 176 | ||||
-rw-r--r-- | scene/2d/collision_shape_2d.h | 26 | ||||
-rw-r--r-- | scene/2d/particles_2d.cpp | 1185 | ||||
-rw-r--r-- | scene/2d/particles_2d.h | 247 | ||||
-rw-r--r-- | scene/2d/physics_body_2d.cpp | 452 | ||||
-rw-r--r-- | scene/2d/physics_body_2d.h | 86 |
14 files changed, 1165 insertions, 1947 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 6a3238b64e..a1ab51b3c8 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -30,7 +30,6 @@ #include "animated_sprite.h" #include "os/os.h" #include "scene/scene_string_names.h" -#include "scene/scene_string_names.h" #define NORMAL_SUFFIX "_normal" diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 3d9e64ae79..cef473dcdf 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -61,7 +61,7 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { - target[j] = buffer[j] * vol; + target[j] += buffer[j] * vol; vol += vol_inc; } @@ -76,8 +76,8 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { AudioFrame frame = buffer[j] * vol; - targets[0][j] = frame; - targets[1][j] = frame; + targets[0][j] += frame; + targets[1][j] += frame; vol += vol_inc; } @@ -93,9 +93,9 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { AudioFrame frame = buffer[j] * vol; - targets[0][j] = frame; - targets[1][j] = frame; - targets[2][j] = frame; + targets[0][j] += frame; + targets[1][j] += frame; + targets[2][j] += frame; vol += vol_inc; } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 471f529713..189dd66a26 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -39,6 +39,196 @@ #include "scene/scene_string_names.h" #include "servers/visual_server.h" +Mutex *CanvasItemMaterial::material_mutex = NULL; +SelfList<CanvasItemMaterial>::List CanvasItemMaterial::dirty_materials; +Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map; + +void CanvasItemMaterial::init_shaders() { + +#ifndef NO_THREADS + material_mutex = Mutex::create(); +#endif +} + +void CanvasItemMaterial::finish_shaders() { + +#ifndef NO_THREADS + memdelete(material_mutex); +#endif +} + +void CanvasItemMaterial::_update_shader() { + + dirty_materials.remove(&element); + + MaterialKey mk = _compute_key(); + if (mk.key == current_key.key) + return; //no update required in the end + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + } + + current_key = mk; + + if (shader_map.has(mk)) { + + VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader); + shader_map[mk].users++; + return; + } + + //must create a shader! + + String code = "shader_type canvas_item;\nrender_mode "; + switch (blend_mode) { + case BLEND_MODE_MIX: code += "blend_mix"; break; + case BLEND_MODE_ADD: code += "blend_add"; break; + case BLEND_MODE_SUB: code += "blend_sub"; break; + case BLEND_MODE_MUL: code += "blend_mul"; break; + case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break; + } + + switch (light_mode) { + case LIGHT_MODE_NORMAL: break; + case LIGHT_MODE_UNSHADED: code += "unshaded"; break; + case LIGHT_MODE_LIGHT_ONLY: code += "light_only"; break; + } + code += ";\n"; //thats it. + + ShaderData shader_data; + shader_data.shader = VS::get_singleton()->shader_create(); + shader_data.users = 1; + + VS::get_singleton()->shader_set_code(shader_data.shader, code); + + shader_map[mk] = shader_data; + + VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); +} + +void CanvasItemMaterial::flush_changes() { + + if (material_mutex) + material_mutex->lock(); + + while (dirty_materials.first()) { + + dirty_materials.first()->self()->_update_shader(); + } + + if (material_mutex) + material_mutex->unlock(); +} + +void CanvasItemMaterial::_queue_shader_change() { + + if (material_mutex) + material_mutex->lock(); + + if (!element.in_list()) { + dirty_materials.add(&element); + } + + if (material_mutex) + material_mutex->unlock(); +} + +bool CanvasItemMaterial::_is_shader_dirty() const { + + bool dirty = false; + + if (material_mutex) + material_mutex->lock(); + + dirty = element.in_list(); + + if (material_mutex) + material_mutex->unlock(); + + return dirty; +} +void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) { + + blend_mode = p_blend_mode; + _queue_shader_change(); +} + +CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const { + return blend_mode; +} + +void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) { + + light_mode = p_light_mode; + _queue_shader_change(); +} + +CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const { + + return light_mode; +} + +void CanvasItemMaterial::_validate_property(PropertyInfo &property) const { +} + +void CanvasItemMaterial::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode); + ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode); + + ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode); + ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode"); + + BIND_CONSTANT(BLEND_MODE_MIX); + BIND_CONSTANT(BLEND_MODE_ADD); + BIND_CONSTANT(BLEND_MODE_SUB); + BIND_CONSTANT(BLEND_MODE_MUL); + BIND_CONSTANT(BLEND_MODE_PREMULT_ALPHA); + BIND_CONSTANT(LIGHT_MODE_NORMAL); + BIND_CONSTANT(LIGHT_MODE_UNSHADED); + BIND_CONSTANT(LIGHT_MODE_LIGHT_ONLY); +} + +CanvasItemMaterial::CanvasItemMaterial() + : element(this) { + + blend_mode = BLEND_MODE_MIX; + light_mode = LIGHT_MODE_NORMAL; + + current_key.key = 0; + current_key.invalid_key = 1; + _queue_shader_change(); +} + +CanvasItemMaterial::~CanvasItemMaterial() { + + if (material_mutex) + material_mutex->lock(); + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + + VS::get_singleton()->material_set_shader(_get_material(), RID()); + } + + if (material_mutex) + material_mutex->unlock(); +} + /////////////////////////////////////////////////////////////////// bool CanvasItem::is_visible_in_tree() const { @@ -417,14 +607,22 @@ void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased); } -void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color) { +void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) { if (!drawing) { ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL(); } - VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color); + if (p_filled) { + + VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color); + } else { + VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(p_rect.size.width, 0), p_color); + VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(0, p_rect.size.height), p_color); + VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(0, p_rect.size.height), p_rect.position + p_rect.size, p_color); + VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(p_rect.size.width, 0), p_rect.position + p_rect.size, p_color); + } } void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) { @@ -657,7 +855,7 @@ bool CanvasItem::is_draw_behind_parent_enabled() const { return behind; } -void CanvasItem::set_material(const Ref<ShaderMaterial> &p_material) { +void CanvasItem::set_material(const Ref<Material> &p_material) { material = p_material; RID rid; @@ -678,7 +876,7 @@ bool CanvasItem::get_use_parent_material() const { return use_parent_material; } -Ref<ShaderMaterial> CanvasItem::get_material() const { +Ref<Material> CanvasItem::get_material() const { return material; } @@ -754,7 +952,7 @@ void CanvasItem::_bind_methods() { //ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform); ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color"), &CanvasItem::draw_rect); + ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true)); ClassDB::bind_method(D_METHOD("draw_circle", "pos", "radius", "color"), &CanvasItem::draw_circle); ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate", "normal_map:Texture"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture:Texture", "rect", "tile", "modulate", "transpose", "normal_map:Texture"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant())); @@ -780,8 +978,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d); //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport); - ClassDB::bind_method(D_METHOD("set_material", "material:ShaderMaterial"), &CanvasItem::set_material); - ClassDB::bind_method(D_METHOD("get_material:ShaderMaterial"), &CanvasItem::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &CanvasItem::set_material); + ClassDB::bind_method(D_METHOD("get_material:Material"), &CanvasItem::get_material); ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material); ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material); @@ -807,7 +1005,7 @@ void CanvasItem::_bind_methods() { ADD_PROPERTYNO(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); ADD_GROUP("Material", ""); - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material"); //exporting these two things doesn't really make much sense i think //ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), "set_as_toplevel","is_set_as_toplevel") ; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 595dd03057..bffc171fc1 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -42,6 +42,92 @@ class Font; class StyleBox; +class CanvasItemMaterial : public Material { + + GDCLASS(CanvasItemMaterial, Material) + +public: + enum BlendMode { + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_PREMULT_ALPHA + }; + + enum LightMode { + LIGHT_MODE_NORMAL, + LIGHT_MODE_UNSHADED, + LIGHT_MODE_LIGHT_ONLY + }; + +private: + union MaterialKey { + + struct { + uint32_t blend_mode : 4; + uint32_t light_mode : 4; + uint32_t invalid_key : 1; + }; + + uint32_t key; + + bool operator<(const MaterialKey &p_key) const { + return key < p_key.key; + } + }; + + struct ShaderData { + RID shader; + int users; + }; + + static Map<MaterialKey, ShaderData> shader_map; + + MaterialKey current_key; + + _FORCE_INLINE_ MaterialKey _compute_key() const { + + MaterialKey mk; + mk.key = 0; + mk.blend_mode = blend_mode; + mk.light_mode = light_mode; + return mk; + } + + static Mutex *material_mutex; + static SelfList<CanvasItemMaterial>::List dirty_materials; + SelfList<CanvasItemMaterial> element; + + void _update_shader(); + _FORCE_INLINE_ void _queue_shader_change(); + _FORCE_INLINE_ bool _is_shader_dirty() const; + + BlendMode blend_mode; + LightMode light_mode; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; + +public: + void set_blend_mode(BlendMode p_blend_mode); + BlendMode get_blend_mode() const; + + void set_light_mode(LightMode p_light_mode); + LightMode get_light_mode() const; + + static void init_shaders(); + static void finish_shaders(); + static void flush_changes(); + + CanvasItemMaterial(); + virtual ~CanvasItemMaterial(); +}; + +VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode) +VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode) + class CanvasItem : public Node { GDCLASS(CanvasItem, Node); @@ -83,7 +169,7 @@ private: bool notify_local_transform; bool notify_transform; - Ref<ShaderMaterial> material; + Ref<Material> material; mutable Transform2D global_transform; mutable bool global_invalid; @@ -156,7 +242,7 @@ public: /* DRAWING API */ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); - void draw_rect(const Rect2 &p_rect, const Color &p_color); + void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true); void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color); void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>()); void draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()); @@ -203,8 +289,8 @@ public: RID get_canvas() const; Ref<World2D> get_world_2d() const; - void set_material(const Ref<ShaderMaterial> &p_material); - Ref<ShaderMaterial> get_material() const; + void set_material(const Ref<Material> &p_material); + Ref<Material> get_material() const; void set_use_parent_material(bool p_use_parent_material); bool get_use_parent_material() const; diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index caf9cf201a..c5c274e225 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -31,18 +31,6 @@ #include "scene/scene_string_names.h" #include "servers/physics_2d_server.h" -void CollisionObject2D::_update_shapes_from_children() { - - shapes.clear(); - for (int i = 0; i < get_child_count(); i++) { - - Node *n = get_child(i); - n->call("_add_to_collision_object", this); - } - - _update_shapes(); -} - void CollisionObject2D::_notification(int p_what) { switch (p_what) { @@ -88,82 +76,197 @@ void CollisionObject2D::_notification(int p_what) { } } -void CollisionObject2D::_update_shapes() { +uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) { - if (!rid.is_valid()) - return; + ShapeData sd; + uint32_t id; + + if (shapes.size() == 0) { + id = 1; + } else { + id = shapes.back()->key() + 1; + } + + sd.owner = p_owner; + + shapes[id] = sd; + + return id; +} + +void CollisionObject2D::remove_shape_owner(uint32_t owner) { + + ERR_FAIL_COND(!shapes.has(owner)); + + shape_owner_clear_shapes(owner); + + shapes.erase(owner); +} + +void CollisionObject2D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled) { + ERR_FAIL_COND(!shapes.has(p_owner)); + + ShapeData &sd = shapes[p_owner]; + sd.disabled = p_disabled; + for (int i = 0; i < sd.shapes.size(); i++) { + if (area) { + Physics2DServer::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); + } else { + Physics2DServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); + } + } +} + +bool CollisionObject2D::is_shape_owner_disabled(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), false); + + return shapes[p_owner].disabled; +} + +void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable) { if (area) - Physics2DServer::get_singleton()->area_clear_shapes(rid); - else - Physics2DServer::get_singleton()->body_clear_shapes(rid); - - for (int i = 0; i < shapes.size(); i++) { - - if (shapes[i].shape.is_null()) - continue; - if (area) - Physics2DServer::get_singleton()->area_add_shape(rid, shapes[i].shape->get_rid(), shapes[i].xform); - else { - Physics2DServer::get_singleton()->body_add_shape(rid, shapes[i].shape->get_rid(), shapes[i].xform); - if (shapes[i].trigger) - Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid, i, shapes[i].trigger); + return; //not for areas + + ERR_FAIL_COND(!shapes.has(p_owner)); + + ShapeData &sd = shapes[p_owner]; + sd.one_way_collision = p_enable; + for (int i = 0; i < sd.shapes.size(); i++) { + Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, p_enable); + } +} + +bool CollisionObject2D::is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), false); + + return shapes[p_owner].one_way_collision; +} + +void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) { + + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + r_owners->push_back(E->key()); + } +} + +void CollisionObject2D::shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform) { + + ERR_FAIL_COND(!shapes.has(p_owner)); + + ShapeData &sd = shapes[p_owner]; + sd.xform = p_transform; + for (int i = 0; i < sd.shapes.size(); i++) { + if (area) { + Physics2DServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, p_transform); + } else { + Physics2DServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform); } } } +Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const { -bool CollisionObject2D::_set(const StringName &p_name, const Variant &p_value) { - String name = p_name; + ERR_FAIL_COND_V(!shapes.has(p_owner), Transform2D()); - if (name.begins_with("shapes/")) { + return shapes[p_owner].xform; +} - int idx = name.get_slicec('/', 1).to_int(); - String what = name.get_slicec('/', 2); - if (what == "shape") { - if (idx >= shapes.size()) - add_shape(RefPtr(p_value)); - else - set_shape(idx, RefPtr(p_value)); - } else if (what == "transform") - set_shape_transform(idx, p_value); - else if (what == "trigger") - set_shape_as_trigger(idx, p_value); - } else - return false; - - return true; +Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), NULL); + + return shapes[p_owner].owner; +} + +void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) { + + ERR_FAIL_COND(!shapes.has(p_owner)); + ERR_FAIL_COND(p_shape.is_null()); + + ShapeData &sd = shapes[p_owner]; + ShapeData::Shape s; + s.index = total_subshapes; + s.shape = p_shape; + if (area) { + Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform); + } else { + Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform); + } + sd.shapes.push_back(s); + + total_subshapes++; +} +int CollisionObject2D::shape_owner_get_shape_count(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), 0); + + return shapes[p_owner].shapes.size(); +} +Ref<Shape> CollisionObject2D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape>()); + ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape>()); + + return shapes[p_owner].shapes[p_shape].shape; +} +int CollisionObject2D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), -1); + ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1); + + return shapes[p_owner].shapes[p_shape].index; } -bool CollisionObject2D::_get(const StringName &p_name, Variant &r_ret) const { +void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { + + ERR_FAIL_COND(!shapes.has(p_owner)); + ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size()); + + int index_to_remove = shapes[p_owner].shapes[p_shape].index; + if (area) { + Physics2DServer::get_singleton()->area_remove_shape(rid, index_to_remove); + } else { + Physics2DServer::get_singleton()->body_remove_shape(rid, index_to_remove); + } + + shapes[p_owner].shapes.remove(p_shape); + + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + for (int i = 0; i < E->get().shapes.size(); i++) { + if (E->get().shapes[i].index > index_to_remove) { + E->get().shapes[i].index -= 1; + } + } + } - String name = p_name; + total_subshapes--; +} - if (name.begins_with("shapes/")) { +void CollisionObject2D::shape_owner_clear_shapes(uint32_t p_owner) { - int idx = name.get_slicec('/', 1).to_int(); - String what = name.get_slicec('/', 2); - if (what == "shape") - r_ret = get_shape(idx); - else if (what == "transform") - r_ret = get_shape_transform(idx); - else if (what == "trigger") - r_ret = is_shape_set_as_trigger(idx); - } else - return false; + ERR_FAIL_COND(!shapes.has(p_owner)); - return true; + while (shape_owner_get_shape_count(p_owner) > 0) { + shape_owner_remove_shape(p_owner, 0); + } } -void CollisionObject2D::_get_property_list(List<PropertyInfo> *p_list) const { +uint32_t CollisionObject2D::shape_find_owner(int p_shape_index) const { - //p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); + ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0); - for (int i = 0; i < shapes.size(); i++) { - String path = "shapes/" + itos(i) + "/"; - p_list->push_back(PropertyInfo(Variant::OBJECT, path + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE)); - p_list->push_back(PropertyInfo(Variant::TRANSFORM, path + "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE)); - p_list->push_back(PropertyInfo(Variant::BOOL, path + "trigger", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE)); + for (const Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + for (int i = 0; i < E->get().shapes.size(); i++) { + if (E->get().shapes[i].index == p_shape_index) { + return E->key(); + } + } } + + //in theory it should be unreachable + return 0; } void CollisionObject2D::set_pickable(bool p_enabled) { @@ -216,16 +319,6 @@ void CollisionObject2D::_update_pickable() { void CollisionObject2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_shape", "shape:Shape2D", "transform"), &CollisionObject2D::add_shape, DEFVAL(Transform2D())); - ClassDB::bind_method(D_METHOD("get_shape_count"), &CollisionObject2D::get_shape_count); - ClassDB::bind_method(D_METHOD("set_shape", "shape_idx", "shape:Shape"), &CollisionObject2D::set_shape); - ClassDB::bind_method(D_METHOD("set_shape_transform", "shape_idx", "transform"), &CollisionObject2D::set_shape_transform); - ClassDB::bind_method(D_METHOD("set_shape_as_trigger", "shape_idx", "enable"), &CollisionObject2D::set_shape_as_trigger); - ClassDB::bind_method(D_METHOD("get_shape:Shape2D", "shape_idx"), &CollisionObject2D::get_shape); - ClassDB::bind_method(D_METHOD("get_shape_transform", "shape_idx"), &CollisionObject2D::get_shape_transform); - ClassDB::bind_method(D_METHOD("is_shape_set_as_trigger", "shape_idx"), &CollisionObject2D::is_shape_set_as_trigger); - ClassDB::bind_method(D_METHOD("remove_shape", "shape_idx"), &CollisionObject2D::remove_shape); - ClassDB::bind_method(D_METHOD("clear_shapes"), &CollisionObject2D::clear_shapes); ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject2D::get_rid); ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable); @@ -242,100 +335,13 @@ void CollisionObject2D::_bind_methods() { ADD_GROUP("", ""); } -void CollisionObject2D::add_shape(const Ref<Shape2D> &p_shape, const Transform2D &p_transform) { - - ERR_FAIL_COND(p_shape.is_null()); - - ShapeData sdata; - sdata.shape = p_shape; - sdata.xform = p_transform; - sdata.trigger = false; - - if (area) - Physics2DServer::get_singleton()->area_add_shape(get_rid(), p_shape->get_rid(), p_transform); - else - Physics2DServer::get_singleton()->body_add_shape(get_rid(), p_shape->get_rid(), p_transform); - - shapes.push_back(sdata); -} -int CollisionObject2D::get_shape_count() const { - - return shapes.size(); -} -void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D> &p_shape) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - ERR_FAIL_COND(p_shape.is_null()); - - shapes[p_shape_idx].shape = p_shape; - if (area) - Physics2DServer::get_singleton()->area_set_shape(get_rid(), p_shape_idx, p_shape->get_rid()); - else - Physics2DServer::get_singleton()->body_set_shape(get_rid(), p_shape_idx, p_shape->get_rid()); - - //_update_shapes(); -} - -void CollisionObject2D::set_shape_transform(int p_shape_idx, const Transform2D &p_transform) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - shapes[p_shape_idx].xform = p_transform; - - if (area) - Physics2DServer::get_singleton()->area_set_shape_transform(get_rid(), p_shape_idx, p_transform); - else - Physics2DServer::get_singleton()->body_set_shape_transform(get_rid(), p_shape_idx, p_transform); - - //_update_shapes(); -} - -Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const { - - ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), Ref<Shape2D>()); - return shapes[p_shape_idx].shape; -} -Transform2D CollisionObject2D::get_shape_transform(int p_shape_idx) const { - - ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), Transform2D()); - return shapes[p_shape_idx].xform; -} -void CollisionObject2D::remove_shape(int p_shape_idx) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - shapes.remove(p_shape_idx); - - _update_shapes(); -} - -void CollisionObject2D::set_shape_as_trigger(int p_shape_idx, bool p_trigger) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - shapes[p_shape_idx].trigger = p_trigger; - if (!area && rid.is_valid()) { - - Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid, p_shape_idx, p_trigger); - } -} - -bool CollisionObject2D::is_shape_set_as_trigger(int p_shape_idx) const { - - ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), false); - return shapes[p_shape_idx].trigger; -} - -void CollisionObject2D::clear_shapes() { - - shapes.clear(); - - _update_shapes(); -} - CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { rid = p_rid; area = p_area; pickable = true; set_notify_transform(true); + total_subshapes = 0; if (p_area) { @@ -348,6 +354,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { CollisionObject2D::CollisionObject2D() { //owner= + set_notify_transform(true); } diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 4d4611afd1..deffe8a002 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -35,37 +35,40 @@ class CollisionObject2D : public Node2D { - GDCLASS(CollisionObject2D, Node2D); + GDCLASS(CollisionObject2D, Node2D) bool area; RID rid; bool pickable; struct ShapeData { + + Object *owner; Transform2D xform; - Ref<Shape2D> shape; - bool trigger; + struct Shape { + Ref<Shape2D> shape; + int index; + }; + + Vector<Shape> shapes; + bool disabled; + bool one_way_collision; ShapeData() { - trigger = false; + disabled = false; + one_way_collision = false; + owner = NULL; } }; - Vector<ShapeData> shapes; - - void _update_shapes(); + int total_subshapes; - friend class CollisionShape2D; - friend class CollisionPolygon2D; - void _update_shapes_from_children(); + Map<uint32_t, ShapeData> shapes; protected: CollisionObject2D(RID p_rid, bool p_area); void _notification(int p_what); - 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; static void _bind_methods(); void _update_pickable(); @@ -75,16 +78,29 @@ protected: void _mouse_exit(); public: - void add_shape(const Ref<Shape2D> &p_shape, const Transform2D &p_transform = Transform2D()); - int get_shape_count() const; - void set_shape(int p_shape_idx, const Ref<Shape2D> &p_shape); - void set_shape_transform(int p_shape_idx, const Transform2D &p_transform); - Ref<Shape2D> get_shape(int p_shape_idx) const; - Transform2D get_shape_transform(int p_shape_idx) const; - void set_shape_as_trigger(int p_shape_idx, bool p_trigger); - bool is_shape_set_as_trigger(int p_shape_idx) const; - void remove_shape(int p_shape_idx); - void clear_shapes(); + uint32_t create_shape_owner(Object *p_owner); + void remove_shape_owner(uint32_t owner); + void get_shape_owners(List<uint32_t> *r_owners); + + void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform); + Transform2D shape_owner_get_transform(uint32_t p_owner) const; + Object *shape_owner_get_owner(uint32_t p_owner) const; + + void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled); + bool is_shape_owner_disabled(uint32_t p_owner) const; + + void shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable); + bool is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const; + + void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape); + int shape_owner_get_shape_count(uint32_t p_owner) const; + Ref<Shape> shape_owner_get_shape(uint32_t p_owner, int p_shape) const; + int shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const; + + void shape_owner_remove_shape(uint32_t p_owner, int p_shape); + void shape_owner_clear_shapes(uint32_t p_owner); + + uint32_t shape_find_owner(int p_shape_index) const; void set_pickable(bool p_enabled); bool is_pickable() const; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 6b603c6473..bd669eb4c8 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -35,13 +35,9 @@ #include "thirdparty/misc/triangulator.h" -void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { +void CollisionPolygon2D::_build_polygon() { - if (unparenting || !can_update_body) - return; - - CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); - ERR_FAIL_COND(!co); + parent->shape_owner_clear_shapes(owner_id); if (polygon.size() == 0) return; @@ -53,18 +49,10 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { //here comes the sun, lalalala //decompose concave into multiple convex polygons and add them Vector<Vector<Vector2> > decomp = _decompose_in_convex(); - shape_from = co->get_shape_count(); for (int i = 0; i < decomp.size(); i++) { Ref<ConvexPolygonShape2D> convex = memnew(ConvexPolygonShape2D); convex->set_points(decomp[i]); - co->add_shape(convex, get_transform()); - if (trigger) - co->set_shape_as_trigger(co->get_shape_count() - 1, true); - } - shape_to = co->get_shape_count() - 1; - if (shape_to < shape_from) { - shape_from = -1; - shape_to = -1; + parent->shape_owner_add_shape(owner_id, convex); } } else { @@ -83,28 +71,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { w = PoolVector<Vector2>::Write(); concave->set_segments(segments); - co->add_shape(concave, get_transform()); - if (trigger) - co->set_shape_as_trigger(co->get_shape_count() - 1, true); - - shape_from = co->get_shape_count() - 1; - shape_to = co->get_shape_count() - 1; + parent->shape_owner_add_shape(owner_id, concave); } - - //co->add_shape(shape,get_transform()); -} - -void CollisionPolygon2D::_update_parent() { - - if (!can_update_body) - return; - Node *parent = get_parent(); - if (!parent) - return; - CollisionObject2D *co = parent->cast_to<CollisionObject2D>(); - if (!co) - return; - co->_update_shapes_from_children(); } Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() { @@ -155,33 +123,38 @@ Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() { void CollisionPolygon2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - unparenting = false; - can_update_body = get_tree()->is_editor_hint(); - if (!get_tree()->is_editor_hint()) { + case NOTIFICATION_PARENTED: { + + parent = get_parent()->cast_to<CollisionObject2D>(); + if (parent) { + owner_id = parent->create_shape_owner(this); + _build_polygon(); + parent->shape_owner_set_transform(owner_id, get_transform()); + parent->shape_owner_set_disabled(owner_id, disabled); + parent->shape_owner_set_one_way_collision(owner_id, one_way_collision); + } + + /*if (get_tree()->is_editor_hint()) { //display above all else set_z_as_relative(false); set_z(VS::CANVAS_ITEM_Z_MAX - 1); - } + }*/ } break; - case NOTIFICATION_EXIT_TREE: { - can_update_body = false; - } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (!is_inside_tree()) - break; - if (can_update_body) { - _update_parent(); - } else if (shape_from >= 0 && shape_to >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - for (int i = shape_from; i <= shape_to; i++) { - co->set_shape_transform(i, get_transform()); - } + if (parent) { + parent->shape_owner_set_transform(owner_id, get_transform()); } } break; + case NOTIFICATION_UNPARENTED: { + if (parent) { + parent->remove_shape_owner(owner_id); + } + owner_id = 0; + parent = NULL; + } break; case NOTIFICATION_DRAW: { @@ -210,10 +183,22 @@ void CollisionPolygon2D::_notification(int p_what) { draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color()); #endif - } break; - case NOTIFICATION_UNPARENTED: { - unparenting = true; - _update_parent(); + if (one_way_collision) { + Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4); + dcol.a = 1.0; + Vector2 line_to(0, 20); + draw_line(Vector2(), line_to, dcol, 3); + Vector<Vector2> pts; + float tsize = 8; + pts.push_back(line_to + (Vector2(0, tsize))); + pts.push_back(line_to + (Vector2(0.707 * tsize, 0))); + pts.push_back(line_to + (Vector2(-0.707 * tsize, 0))); + Vector<Color> cols; + for (int i = 0; i < 3; i++) + cols.push_back(dcol); + + draw_primitive(pts, cols, Vector<Vector2>()); //small arrow + } } break; } } @@ -222,7 +207,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) { polygon = p_polygon; - if (can_update_body) { + { for (int i = 0; i < polygon.size(); i++) { if (i == 0) aabb = Rect2(polygon[i], Size2()); @@ -236,7 +221,10 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) { aabb.position -= aabb.size * 0.3; aabb.size += aabb.size * 0.6; } - _update_parent(); + } + + if (parent) { + _build_polygon(); } update(); update_configuration_warning(); @@ -251,7 +239,9 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) { ERR_FAIL_INDEX(p_mode, 2); build_mode = p_mode; - _update_parent(); + if (parent) { + _build_polygon(); + } } CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { @@ -264,79 +254,69 @@ Rect2 CollisionPolygon2D::get_item_rect() const { return aabb; } -void CollisionPolygon2D::set_trigger(bool p_trigger) { +String CollisionPolygon2D::get_configuration_warning() const { - trigger = p_trigger; - _update_parent(); - if (!can_update_body && is_inside_tree() && shape_from >= 0 && shape_to >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - for (int i = shape_from; i <= shape_to; i++) { - co->set_shape_as_trigger(i, p_trigger); - } + if (!get_parent()->cast_to<CollisionObject2D>()) { + return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); } -} -bool CollisionPolygon2D::is_trigger() const { + if (polygon.empty()) { + return TTR("An empty CollisionPolygon2D has no effect on collision."); + } - return trigger; + return String(); } -void CollisionPolygon2D::_set_shape_range(const Vector2 &p_range) { - - shape_from = p_range.x; - shape_to = p_range.y; +void CollisionPolygon2D::set_disabled(bool p_disabled) { + disabled = p_disabled; + update(); + if (parent) { + parent->shape_owner_set_disabled(owner_id, p_disabled); + } } -Vector2 CollisionPolygon2D::_get_shape_range() const { - - return Vector2(shape_from, shape_to); +bool CollisionPolygon2D::is_disabled() const { + return disabled; } -String CollisionPolygon2D::get_configuration_warning() const { - - if (!get_parent()->cast_to<CollisionObject2D>()) { - return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); +void CollisionPolygon2D::set_one_way_collision(bool p_enable) { + one_way_collision = p_enable; + update(); + if (parent) { + parent->shape_owner_set_one_way_collision(owner_id, p_enable); } +} - if (polygon.empty()) { - return TTR("An empty CollisionPolygon2D has no effect on collision."); - } +bool CollisionPolygon2D::is_one_way_collision_enabled() const { - return String(); + return one_way_collision; } void CollisionPolygon2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("_add_to_collision_object"), &CollisionPolygon2D::_add_to_collision_object); ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon2D::set_polygon); ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon2D::get_polygon); ClassDB::bind_method(D_METHOD("set_build_mode", "build_mode"), &CollisionPolygon2D::set_build_mode); ClassDB::bind_method(D_METHOD("get_build_mode"), &CollisionPolygon2D::get_build_mode); - - ClassDB::bind_method(D_METHOD("set_trigger", "trigger"), &CollisionPolygon2D::set_trigger); - ClassDB::bind_method(D_METHOD("is_trigger"), &CollisionPolygon2D::is_trigger); - - ClassDB::bind_method(D_METHOD("_set_shape_range", "shape_range"), &CollisionPolygon2D::_set_shape_range); - ClassDB::bind_method(D_METHOD("_get_shape_range"), &CollisionPolygon2D::_get_shape_range); - - ClassDB::bind_method(D_METHOD("get_collision_object_first_shape"), &CollisionPolygon2D::get_collision_object_first_shape); - ClassDB::bind_method(D_METHOD("get_collision_object_last_shape"), &CollisionPolygon2D::get_collision_object_last_shape); + ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon2D::set_disabled); + ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon2D::is_disabled); + ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionPolygon2D::set_one_way_collision); + ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionPolygon2D::is_one_way_collision_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "build_mode", PROPERTY_HINT_ENUM, "Solids,Segments"), "set_build_mode", "get_build_mode"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shape_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_shape_range", "_get_shape_range"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trigger"), "set_trigger", "is_trigger"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled"); } CollisionPolygon2D::CollisionPolygon2D() { aabb = Rect2(-10, -10, 20, 20); build_mode = BUILD_SOLIDS; - trigger = false; - unparenting = false; - shape_from = -1; - shape_to = -1; - can_update_body = false; set_notify_local_transform(true); + parent = NULL; + owner_id = 0; + disabled = false; + one_way_collision = false; } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index b1a4a4822d..f0666ba9de 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -33,6 +33,8 @@ #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" +class CollisionObject2D; + class CollisionPolygon2D : public Node2D { GDCLASS(CollisionPolygon2D, Node2D); @@ -47,29 +49,20 @@ protected: Rect2 aabb; BuildMode build_mode; Vector<Point2> polygon; - bool trigger; - bool unparenting; - - void _add_to_collision_object(Object *p_obj); - void _update_parent(); - - bool can_update_body; - int shape_from; - int shape_to; - - void _set_shape_range(const Vector2 &p_range); - Vector2 _get_shape_range() const; + uint32_t owner_id; + CollisionObject2D *parent; + bool disabled; + bool one_way_collision; Vector<Vector<Vector2> > _decompose_in_convex(); + void _build_polygon(); + protected: void _notification(int p_what); static void _bind_methods(); public: - void set_trigger(bool p_trigger); - bool is_trigger() const; - void set_build_mode(BuildMode p_mode); BuildMode get_build_mode() const; @@ -78,11 +71,14 @@ public: virtual Rect2 get_item_rect() const; - int get_collision_object_first_shape() const { return shape_from; } - int get_collision_object_last_shape() const { return shape_to; } - virtual String get_configuration_warning() const; + void set_disabled(bool p_disabled); + bool is_disabled() const; + + void set_one_way_collision(bool p_enable); + bool is_one_way_collision_enabled() const; + CollisionPolygon2D(); }; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 1687a898db..ff4aa245ec 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -37,68 +37,48 @@ #include "scene/resources/segment_shape_2d.h" #include "scene/resources/shape_line_2d.h" -void CollisionShape2D::_add_to_collision_object(Object *p_obj) { - - if (unparenting) - return; - - CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); - ERR_FAIL_COND(!co); - update_shape_index = co->get_shape_count(); - co->add_shape(shape, get_transform()); - if (trigger) - co->set_shape_as_trigger(co->get_shape_count() - 1, true); -} - void CollisionShape2D::_shape_changed() { update(); - _update_parent(); -} - -void CollisionShape2D::_update_parent() { - - Node *parent = get_parent(); - if (!parent) - return; - CollisionObject2D *co = parent->cast_to<CollisionObject2D>(); - if (!co) - return; - co->_update_shapes_from_children(); } void CollisionShape2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - unparenting = false; - can_update_body = get_tree()->is_editor_hint(); - if (!get_tree()->is_editor_hint()) { + case NOTIFICATION_PARENTED: { + + parent = get_parent()->cast_to<CollisionObject2D>(); + if (parent) { + owner_id = parent->create_shape_owner(this); + if (shape.is_valid()) { + parent->shape_owner_add_shape(owner_id, shape); + } + parent->shape_owner_set_transform(owner_id, get_transform()); + parent->shape_owner_set_disabled(owner_id, disabled); + parent->shape_owner_set_one_way_collision(owner_id, one_way_collision); + } + + /*if (get_tree()->is_editor_hint()) { //display above all else set_z_as_relative(false); set_z(VS::CANVAS_ITEM_Z_MAX - 1); - } + }*/ } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (!is_inside_tree()) - break; - if (can_update_body) { - _update_parent(); - } else if (update_shape_index >= 0) { - - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - if (co) { - co->set_shape_transform(update_shape_index, get_transform()); - } + if (parent) { + parent->shape_owner_set_transform(owner_id, get_transform()); } } break; - case NOTIFICATION_EXIT_TREE: { - can_update_body = false; - + case NOTIFICATION_UNPARENTED: { + if (parent) { + parent->remove_shape_owner(owner_id); + } + owner_id = 0; + parent = NULL; } break; /* case NOTIFICATION_TRANSFORM_CHANGED: { @@ -121,15 +101,33 @@ void CollisionShape2D::_notification(int p_what) { rect = Rect2(); Color draw_col = get_tree()->get_debug_collisions_color(); + if (disabled) { + float g = draw_col.gray(); + draw_col.r = g; + draw_col.g = g; + draw_col.b = g; + } shape->draw(get_canvas_item(), draw_col); rect = shape->get_rect(); rect = rect.grow(3); - } break; - case NOTIFICATION_UNPARENTED: { - unparenting = true; - _update_parent(); + if (one_way_collision) { + Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4); + dcol.a = 1.0; + Vector2 line_to(0, 20); + draw_line(Vector2(), line_to, dcol, 3); + Vector<Vector2> pts; + float tsize = 8; + pts.push_back(line_to + (Vector2(0, tsize))); + pts.push_back(line_to + (Vector2(0.707 * tsize, 0))); + pts.push_back(line_to + (Vector2(-0.707 * tsize, 0))); + Vector<Color> cols; + for (int i = 0; i < 3; i++) + cols.push_back(dcol); + + draw_primitive(pts, cols, Vector<Vector2>()); //small arrow + } } break; } } @@ -140,14 +138,13 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) { shape->disconnect("changed", this, "_shape_changed"); shape = p_shape; update(); - if (is_inside_tree() && can_update_body) - _update_parent(); - if (is_inside_tree() && !can_update_body && update_shape_index >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - if (co) { - co->set_shape(update_shape_index, p_shape); + if (parent) { + parent->shape_owner_clear_shapes(owner_id); + if (shape.is_valid()) { + parent->shape_owner_add_shape(owner_id, shape); } } + if (shape.is_valid()) shape->connect("changed", this, "_shape_changed"); @@ -164,72 +161,65 @@ Rect2 CollisionShape2D::get_item_rect() const { return rect; } -void CollisionShape2D::set_trigger(bool p_trigger) { +String CollisionShape2D::get_configuration_warning() const { - trigger = p_trigger; - if (can_update_body) { - _update_parent(); - } else if (is_inside_tree() && update_shape_index >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - if (co) { - co->set_shape_as_trigger(update_shape_index, p_trigger); - } + if (!get_parent()->cast_to<CollisionObject2D>()) { + return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); } -} -bool CollisionShape2D::is_trigger() const { + if (!shape.is_valid()) { + return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"); + } - return trigger; + return String(); } -void CollisionShape2D::_set_update_shape_index(int p_index) { - - update_shape_index = p_index; +void CollisionShape2D::set_disabled(bool p_disabled) { + disabled = p_disabled; + update(); + if (parent) { + parent->shape_owner_set_disabled(owner_id, p_disabled); + } } -int CollisionShape2D::_get_update_shape_index() const { - - return update_shape_index; +bool CollisionShape2D::is_disabled() const { + return disabled; } -String CollisionShape2D::get_configuration_warning() const { - - if (!get_parent()->cast_to<CollisionObject2D>()) { - return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); +void CollisionShape2D::set_one_way_collision(bool p_enable) { + one_way_collision = p_enable; + update(); + if (parent) { + parent->shape_owner_set_one_way_collision(owner_id, p_enable); } +} - if (!shape.is_valid()) { - return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"); - } +bool CollisionShape2D::is_one_way_collision_enabled() const { - return String(); + return one_way_collision; } void CollisionShape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape2D::set_shape); ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape2D::get_shape); + ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionShape2D::set_disabled); + ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape2D::is_disabled); + ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionShape2D::set_one_way_collision); + ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionShape2D::is_one_way_collision_enabled); ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape2D::_shape_changed); - ClassDB::bind_method(D_METHOD("_add_to_collision_object"), &CollisionShape2D::_add_to_collision_object); - ClassDB::bind_method(D_METHOD("set_trigger", "enable"), &CollisionShape2D::set_trigger); - ClassDB::bind_method(D_METHOD("is_trigger"), &CollisionShape2D::is_trigger); - - ClassDB::bind_method(D_METHOD("_set_update_shape_index", "index"), &CollisionShape2D::_set_update_shape_index); - ClassDB::bind_method(D_METHOD("_get_update_shape_index"), &CollisionShape2D::_get_update_shape_index); - - ClassDB::bind_method(D_METHOD("get_collision_object_shape_index"), &CollisionShape2D::get_collision_object_shape_index); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trigger"), "set_trigger", "is_trigger"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_update_shape_index", "_get_update_shape_index"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled"); } CollisionShape2D::CollisionShape2D() { rect = Rect2(-Point2(10, 10), Point2(20, 20)); set_notify_local_transform(true); - trigger = false; - unparenting = false; - can_update_body = false; - update_shape_index = -1; + owner_id = 0; + parent = NULL; + disabled = false; + one_way_collision = false; } diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index 3e63981010..1f2b96b91f 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -33,35 +33,33 @@ #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" +class CollisionObject2D; + class CollisionShape2D : public Node2D { - GDCLASS(CollisionShape2D, Node2D); + GDCLASS(CollisionShape2D, Node2D) Ref<Shape2D> shape; Rect2 rect; - bool trigger; - bool unparenting; - bool can_update_body; + uint32_t owner_id; + CollisionObject2D *parent; void _shape_changed(); - int update_shape_index; - - void _set_update_shape_index(int p_index); - int _get_update_shape_index() const; + bool disabled; + bool one_way_collision; protected: - void _update_parent(); void _notification(int p_what); static void _bind_methods(); - void _add_to_collision_object(Object *p_obj); - public: void set_shape(const Ref<Shape2D> &p_shape); Ref<Shape2D> get_shape() const; virtual Rect2 get_item_rect() const; - void set_trigger(bool p_trigger); - bool is_trigger() const; - int get_collision_object_shape_index() const { return _get_update_shape_index(); } + void set_disabled(bool p_disabled); + bool is_disabled() const; + + void set_one_way_collision(bool p_enable); + bool is_one_way_collision_enabled() const; virtual String get_configuration_warning() const; diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 21d64c5d64..beff247264 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -28,903 +28,235 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "particles_2d.h" -#include "scene/scene_string_names.h" - -void ParticleAttractor2D::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_ENTER_TREE: { - - _update_owner(); - } break; - case NOTIFICATION_DRAW: { - - if (!get_tree()->is_editor_hint()) - return; - - Vector2 pv; - float dr = MIN(disable_radius, radius); - for (int i = 0; i <= 32; i++) { - Vector2 v(Math::sin(i / 32.0 * Math_PI * 2), Math::cos(i / 32.0 * Math_PI * 2)); - if (i > 0) { - draw_line(pv * radius, v * radius, Color(0, 0, 0.5, 0.9)); - if (dr > 0) { - draw_line(pv * dr, v * dr, Color(0.5, 0, 0.0, 0.9)); - } - } - pv = v; - } +#include "scene/3d/particles.h" +#include "scene/scene_string_names.h" - } break; - case NOTIFICATION_EXIT_TREE: { - if (owner) { - _set_owner(NULL); - } +void Particles2D::set_emitting(bool p_emitting) { - } break; - } + emitting = p_emitting; + VS::get_singleton()->particles_set_emitting(particles, emitting); } -void ParticleAttractor2D::_owner_exited() { +void Particles2D::set_amount(int p_amount) { - ERR_FAIL_COND(!owner); - owner->attractors.erase(this); - owner = NULL; + ERR_FAIL_COND(p_amount < 1); + amount = p_amount; + VS::get_singleton()->particles_set_amount(particles, amount); } +void Particles2D::set_lifetime(float p_lifetime) { -void ParticleAttractor2D::_update_owner() { - - if (!is_inside_tree() || !has_node(path)) { - _set_owner(NULL); - return; - } - - Node *n = get_node(path); - ERR_FAIL_COND(!n); - Particles2D *pn = n->cast_to<Particles2D>(); - if (!pn) { - _set_owner(NULL); - return; - } - - _set_owner(pn); + ERR_FAIL_COND(p_lifetime <= 0); + lifetime = p_lifetime; + VS::get_singleton()->particles_set_lifetime(particles, lifetime); } +void Particles2D::set_pre_process_time(float p_time) { -void ParticleAttractor2D::_set_owner(Particles2D *p_owner) { - - if (owner == p_owner) - return; - - if (owner) { - owner->disconnect("tree_exited", this, "_owner_exited"); - owner->attractors.erase(this); - owner = NULL; - } - owner = p_owner; - - if (owner) { - - owner->connect("tree_exited", this, "_owner_exited", varray(), CONNECT_ONESHOT); - owner->attractors.insert(this); - } + pre_process_time = p_time; + VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time); } +void Particles2D::set_explosiveness_ratio(float p_ratio) { -void ParticleAttractor2D::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &ParticleAttractor2D::set_enabled); - ClassDB::bind_method(D_METHOD("is_enabled"), &ParticleAttractor2D::is_enabled); - - ClassDB::bind_method(D_METHOD("set_radius", "radius"), &ParticleAttractor2D::set_radius); - ClassDB::bind_method(D_METHOD("get_radius"), &ParticleAttractor2D::get_radius); - - ClassDB::bind_method(D_METHOD("set_disable_radius", "radius"), &ParticleAttractor2D::set_disable_radius); - ClassDB::bind_method(D_METHOD("get_disable_radius"), &ParticleAttractor2D::get_disable_radius); - - ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &ParticleAttractor2D::set_gravity); - ClassDB::bind_method(D_METHOD("get_gravity"), &ParticleAttractor2D::get_gravity); - - ClassDB::bind_method(D_METHOD("set_absorption", "absorption"), &ParticleAttractor2D::set_absorption); - ClassDB::bind_method(D_METHOD("get_absorption"), &ParticleAttractor2D::get_absorption); - - ClassDB::bind_method(D_METHOD("set_particles_path", "path"), &ParticleAttractor2D::set_particles_path); - ClassDB::bind_method(D_METHOD("get_particles_path"), &ParticleAttractor2D::get_particles_path); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,16000,0.1"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "disable_radius", PROPERTY_HINT_RANGE, "0.1,16000,0.1"), "set_disable_radius", "get_disable_radius"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-512,512,0.01"), "set_gravity", "get_gravity"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "absorption", PROPERTY_HINT_RANGE, "0,512,0.01"), "set_absorption", "get_absorption"); - ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "particles_path", PROPERTY_HINT_RESOURCE_TYPE, "Particles2D"), "set_particles_path", "get_particles_path"); + explosiveness_ratio = p_ratio; + VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio); } +void Particles2D::set_randomness_ratio(float p_ratio) { -void ParticleAttractor2D::set_enabled(bool p_enabled) { - - enabled = p_enabled; + randomness_ratio = p_ratio; + VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio); } +void Particles2D::set_visibility_rect(const Rect2 &p_aabb) { -bool ParticleAttractor2D::is_enabled() const { + visibility_rect = p_aabb; + Rect3 aabb; + aabb.position.x = p_aabb.position.x; + aabb.position.y = p_aabb.position.y; + aabb.size.x = p_aabb.size.x; + aabb.size.y = p_aabb.size.y; - return enabled; -} - -void ParticleAttractor2D::set_radius(float p_radius) { + VS::get_singleton()->particles_set_custom_aabb(particles, aabb); - radius = p_radius; + _change_notify("visibility_rect"); update(); } +void Particles2D::set_use_local_coordinates(bool p_enable) { -float ParticleAttractor2D::get_radius() const { - - return radius; -} - -void ParticleAttractor2D::set_disable_radius(float p_disable_radius) { - - disable_radius = p_disable_radius; - update(); -} -float ParticleAttractor2D::get_disable_radius() const { - - return disable_radius; -} - -void ParticleAttractor2D::set_gravity(float p_gravity) { - - gravity = p_gravity; -} -float ParticleAttractor2D::get_gravity() const { - - return gravity; -} - -void ParticleAttractor2D::set_absorption(float p_absorption) { - - absorption = p_absorption; -} -float ParticleAttractor2D::get_absorption() const { - - return absorption; -} - -void ParticleAttractor2D::set_particles_path(NodePath p_path) { - - path = p_path; - _update_owner(); - update_configuration_warning(); -} -NodePath ParticleAttractor2D::get_particles_path() const { - - return path; -} - -String ParticleAttractor2D::get_configuration_warning() const { - - if (!has_node(path) || !get_node(path) || !get_node(path)->cast_to<Particles2D>()) { - return TTR("Path property must point to a valid Particles2D node to work."); + local_coords = p_enable; + VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords); + set_notify_transform(!p_enable); + if (!p_enable) { + _update_particle_emission_transform(); } - - return String(); -} - -ParticleAttractor2D::ParticleAttractor2D() { - - owner = NULL; - radius = 50; - disable_radius = 0; - gravity = 100; - absorption = 0; - path = String(".."); - enabled = true; } -/****************************************/ +void Particles2D::_update_particle_emission_transform() { -_FORCE_INLINE_ static float _rand_from_seed(uint64_t *seed) { + Transform2D xf2d = get_global_transform(); + Transform xf; + xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0)); + xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0)); + xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0)); - uint32_t r = Math::rand_from_seed(seed); - return 2.0f * (float)r / (float)Math::RANDOM_MAX - 1.0f; + VS::get_singleton()->particles_set_emission_transform(particles, xf); } -void Particles2D::_process_particles(float p_delta) { - - if (particles.size() == 0 || lifetime == 0) - return; - - p_delta *= time_scale; - - float frame_time = p_delta; - - if (emit_timeout > 0) { - time_to_live -= frame_time; - if (time_to_live < 0) { - - emitting = false; - _change_notify("config/emitting"); - }; - }; - - float next_time = time + frame_time; - - if (next_time > lifetime) - next_time = Math::fmod(next_time, lifetime); - - Particle *pdata = &particles[0]; - int particle_count = particles.size(); - Transform2D xform; - if (!local_space) - xform = get_global_transform(); +void Particles2D::set_process_material(const Ref<Material> &p_material) { - active_count = 0; - - PoolVector<Point2>::Read r; - int emission_point_count = 0; - if (emission_points.size()) { - - emission_point_count = emission_points.size(); - r = emission_points.read(); - } - - int attractor_count = 0; - AttractorCache *attractor_ptr = NULL; - - if (attractors.size()) { - if (attractors.size() != attractor_cache.size()) { - attractor_cache.resize(attractors.size()); - } - - int idx = 0; - Transform2D m; - if (local_space) { - m = get_global_transform().affine_inverse(); - } - for (Set<ParticleAttractor2D *>::Element *E = attractors.front(); E; E = E->next()) { - - attractor_cache[idx].pos = m.xform(E->get()->get_global_position()); - attractor_cache[idx].attractor = E->get(); - idx++; - } - - attractor_ptr = attractor_cache.ptr(); - attractor_count = attractor_cache.size(); - } - - for (int i = 0; i < particle_count; i++) { - - Particle &p = pdata[i]; - - float restart_time = (i * lifetime / particle_count) * explosiveness; - - bool restart = false; - - if (next_time < time) { - - if (restart_time > time || restart_time < next_time) - restart = true; - - } else if (restart_time > time && restart_time < next_time) { - restart = true; - } - - if (restart) { - - if (emitting) { - - p.pos = emissor_offset; - if (emission_point_count) { - - Vector2 ep = r[Math::rand() % emission_point_count]; - if (!local_space) { - p.pos = xform.xform(p.pos + ep * extents); - } else { - p.pos += ep * extents; - } - } else { - if (!local_space) { - p.pos = xform.xform(p.pos + Vector2(Math::random(-extents.x, extents.x), Math::random(-extents.y, extents.y))); - } else { - p.pos += Vector2(Math::random(-extents.x, extents.x), Math::random(-extents.y, extents.y)); - } - } - p.seed = Math::rand() % 12345678; - uint64_t rand_seed = p.seed * (i + 1); - - float angle = Math::deg2rad(param[PARAM_DIRECTION] + _rand_from_seed(&rand_seed) * param[PARAM_SPREAD]); - - p.velocity = Vector2(Math::sin(angle), Math::cos(angle)); - if (!local_space) { - - p.velocity = xform.basis_xform(p.velocity).normalized(); - } - - p.velocity *= param[PARAM_LINEAR_VELOCITY] + param[PARAM_LINEAR_VELOCITY] * _rand_from_seed(&rand_seed) * randomness[PARAM_LINEAR_VELOCITY]; - p.velocity += initial_velocity; - p.active = true; - p.rot = Math::deg2rad(param[PARAM_INITIAL_ANGLE] + param[PARAM_INITIAL_ANGLE] * randomness[PARAM_INITIAL_ANGLE] * _rand_from_seed(&rand_seed)); - active_count++; - - p.frame = Math::fmod(param[PARAM_ANIM_INITIAL_POS] + randomness[PARAM_ANIM_INITIAL_POS] * _rand_from_seed(&rand_seed), 1.0f); - - } else { - - p.active = false; - } - - } else { - - if (!p.active) - continue; - - uint64_t rand_seed = p.seed * (i + 1); - - Vector2 force; - - //apply gravity - float gravity_dir = Math::deg2rad(param[PARAM_GRAVITY_DIRECTION] + 180 * randomness[PARAM_GRAVITY_DIRECTION] * _rand_from_seed(&rand_seed)); - force += Vector2(Math::sin(gravity_dir), Math::cos(gravity_dir)) * (param[PARAM_GRAVITY_STRENGTH] + param[PARAM_GRAVITY_STRENGTH] * randomness[PARAM_GRAVITY_STRENGTH] * _rand_from_seed(&rand_seed)); - //apply radial - Vector2 rvec = (p.pos - emissor_offset).normalized(); - force += rvec * (param[PARAM_RADIAL_ACCEL] + param[PARAM_RADIAL_ACCEL] * randomness[PARAM_RADIAL_ACCEL] * _rand_from_seed(&rand_seed)); - //apply orbit - float orbitvel = (param[PARAM_ORBIT_VELOCITY] + param[PARAM_ORBIT_VELOCITY] * randomness[PARAM_ORBIT_VELOCITY] * _rand_from_seed(&rand_seed)); - if (orbitvel != 0) { - Vector2 rel = p.pos - xform.elements[2]; - Transform2D rot(orbitvel * frame_time, Vector2()); - p.pos = rot.xform(rel) + xform.elements[2]; - } - - Vector2 tvec = rvec.tangent(); - force += tvec * (param[PARAM_TANGENTIAL_ACCEL] + param[PARAM_TANGENTIAL_ACCEL] * randomness[PARAM_TANGENTIAL_ACCEL] * _rand_from_seed(&rand_seed)); - - for (int j = 0; j < attractor_count; j++) { - - Vector2 vec = (attractor_ptr[j].pos - p.pos); - float vl = vec.length(); - - if (!attractor_ptr[j].attractor->enabled || vl == 0 || vl > attractor_ptr[j].attractor->radius) - continue; - - force += vec * attractor_ptr[j].attractor->gravity; - float fvl = p.velocity.length(); - if (fvl && attractor_ptr[j].attractor->absorption) { - Vector2 target = vec.normalized(); - p.velocity = p.velocity.normalized().linear_interpolate(target, MIN(frame_time * attractor_ptr[j].attractor->absorption, 1)) * fvl; - } - - if (attractor_ptr[j].attractor->disable_radius && vl < attractor_ptr[j].attractor->disable_radius) { - p.active = false; - } - } - - p.velocity += force * frame_time; - - if (param[PARAM_DAMPING]) { - float dmp = param[PARAM_DAMPING] + param[PARAM_DAMPING] * randomness[PARAM_DAMPING] * _rand_from_seed(&rand_seed); - float v = p.velocity.length(); - v -= dmp * frame_time; - if (v <= 0) { - p.velocity = Vector2(); - } else { - p.velocity = p.velocity.normalized() * v; - } - } - - p.pos += p.velocity * frame_time; - p.rot += Math::lerp(param[PARAM_SPIN_VELOCITY], param[PARAM_SPIN_VELOCITY] * randomness[PARAM_SPIN_VELOCITY] * _rand_from_seed(&rand_seed), randomness[PARAM_SPIN_VELOCITY]) * frame_time; - float anim_spd = param[PARAM_ANIM_SPEED_SCALE] + param[PARAM_ANIM_SPEED_SCALE] * randomness[PARAM_ANIM_SPEED_SCALE] * _rand_from_seed(&rand_seed); - p.frame = Math::fposmod(p.frame + (frame_time / lifetime) * anim_spd, 1.0f); - - active_count++; - } + process_material = p_material; + Ref<ParticlesMaterial> pm = p_material; + if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) { + //likely a new material, modify it! + pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true); + pm->set_gravity(Vector3(0, 98, 0)); } + RID material_rid; + if (process_material.is_valid()) + material_rid = process_material->get_rid(); + VS::get_singleton()->particles_set_process_material(particles, material_rid); - time = Math::fmod(time + frame_time, lifetime); - if (!emitting && active_count == 0) { - emit_signal(SceneStringNames::get_singleton()->emission_finished); - set_process(false); - set_fixed_process(false); - } - - update(); + update_configuration_warning(); } -void Particles2D::_notification(int p_what) { - - switch (p_what) { - - case NOTIFICATION_PROCESS: { - - _process_particles(get_process_delta_time()); - } break; - - case NOTIFICATION_FIXED_PROCESS: { - - _process_particles(get_fixed_process_delta_time()); - } break; - - case NOTIFICATION_ENTER_TREE: { - - float ppt = preprocess; - while (ppt > 0) { - _process_particles(0.1); - ppt -= 0.1; - } - } break; - case NOTIFICATION_DRAW: { - - if (particles.size() == 0 || lifetime == 0) - return; - - RID ci = get_canvas_item(); - Size2 size(1, 1); - Point2 center; - int total_frames = 1; +void Particles2D::set_speed_scale(float p_scale) { - if (!texture.is_null()) { - size = texture->get_size(); - size.x /= h_frames; - size.y /= v_frames; - total_frames = h_frames * v_frames; - } - - float time_pos = (time / lifetime); - - Particle *pdata = &particles[0]; - int particle_count = particles.size(); - - RID texrid; - - if (texture.is_valid()) - texrid = texture->get_rid(); - - Transform2D invxform; - if (!local_space) - invxform = get_global_transform().affine_inverse(); - - int start_particle = (int)(time * (float)particle_count / lifetime); - - for (int id = 0; id < particle_count; ++id) { - int i = start_particle + id; - if (i >= particle_count) { - i -= particle_count; - } - - Particle &p = pdata[i]; - if (!p.active) - continue; - - float ptime = ((float)i / particle_count) * explosiveness; - - if (ptime < time_pos) - ptime = time_pos - ptime; - else - ptime = (1.0 - ptime) + time_pos; - - uint64_t rand_seed = p.seed * (i + 1); - - Color color; - - if (gradient.is_valid()) { - color = gradient->get_color_at_offset(ptime); - } else { - color = default_color; - } - - { - float huerand = _rand_from_seed(&rand_seed); - float huerot = param[PARAM_HUE_VARIATION] + randomness[PARAM_HUE_VARIATION] * huerand; - - if (Math::abs(huerot) > CMP_EPSILON) { - - float h = color.get_h(); - float s = color.get_s(); - float v = color.get_v(); - float a = color.a; - //float preh=h; - h += huerot; - h = Math::abs(Math::fposmod(h, 1.0f)); - //print_line("rand: "+rtos(randomness[PARAM_HUE_VARIATION])+" rand: "+rtos(huerand)); - //print_line(itos(i)+":hue: "+rtos(preh)+" + "+rtos(huerot)+" = "+rtos(h)); - color.set_hsv(h, s, v); - color.a = a; - } - } - - float initial_size = param[PARAM_INITIAL_SIZE] + param[PARAM_INITIAL_SIZE] * _rand_from_seed(&rand_seed) * randomness[PARAM_INITIAL_SIZE]; - float final_size = param[PARAM_FINAL_SIZE] + param[PARAM_FINAL_SIZE] * _rand_from_seed(&rand_seed) * randomness[PARAM_FINAL_SIZE]; - - float size_mult = initial_size * (1.0 - ptime) + final_size * ptime; - - //Size2 rectsize=size * size_mult; - //rectsize=rectsize.floor(); - - //Rect2 r = Rect2(Vecto,rectsize); - - Transform2D xform; - - if (p.rot) { - - xform.set_rotation(p.rot); - xform.translate(-size * size_mult / 2.0); - xform.elements[2] += p.pos; - } else { - xform.elements[2] = -size * size_mult / 2.0; - xform.elements[2] += p.pos; - } - - if (!local_space) { - xform = invxform * xform; - } - - xform.scale_basis(Size2(size_mult, size_mult)); - - VisualServer::get_singleton()->canvas_item_add_set_transform(ci, xform); - - if (texrid.is_valid()) { - - Rect2 src_rect; - src_rect.size = size; - - if (total_frames > 1) { - int frame = Math::fast_ftoi(Math::floor(p.frame * total_frames)) % total_frames; - src_rect.position.x = size.x * (frame % h_frames); - src_rect.position.y = size.y * (frame / h_frames); - } - Rect2 dst_rect(Point2(), size); - if (flip_h) - dst_rect.size.x = -dst_rect.size.x; - if (flip_v) - dst_rect.size.y = -dst_rect.size.y; - - texture->draw_rect_region(ci, dst_rect, src_rect, color); - //VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color); - } else { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(), size), color); - } - } - - } break; - } -} - -static const char *_particlesframe_property_names[Particles2D::PARAM_MAX] = { - "params/direction", - "params/spread", - "params/linear_velocity", - "params/spin_velocity", - "params/orbit_velocity", - "params/gravity_direction", - "params/gravity_strength", - "params/radial_accel", - "params/tangential_accel", - "params/damping", - "params/initial_angle", - "params/initial_size", - "params/final_size", - "params/hue_variation", - "params/anim_speed_scale", - "params/anim_initial_pos", -}; - -static const char *_particlesframe_property_rnames[Particles2D::PARAM_MAX] = { - "randomness/direction", - "randomness/spread", - "randomness/linear_velocity", - "randomness/spin_velocity", - "randomness/orbit_velocity", - "randomness/gravity_direction", - "randomness/gravity_strength", - "randomness/radial_accel", - "randomness/tangential_accel", - "randomness/damping", - "randomness/initial_angle", - "randomness/initial_size", - "randomness/final_size", - "randomness/hue_variation", - "randomness/anim_speed_scale", - "randomness/anim_initial_pos", -}; - -static const char *_particlesframe_property_ranges[Particles2D::PARAM_MAX] = { - "0,360,0.01", - "0,180,0.01", - "-1024,1024,0.01", - "-1024,1024,0.01", - "-1024,1024,0.01", - "0,360,0.01", - "0,1024,0.01", - "-128,128,0.01", - "-128,128,0.01", - "0,1024,0.001", - "0,360,0.01", - "0,1024,0.01", - "0,1024,0.01", - "0,1,0.01", - "0,128,0.01", - "0,1,0.01", -}; - -void Particles2D::set_emitting(bool p_emitting) { - - if (emitting == p_emitting) - return; - - if (p_emitting) { - - if (active_count == 0) - time = 0; - set_process(process_mode == PROCESS_IDLE); - set_fixed_process(process_mode == PROCESS_FIXED); - time_to_live = emit_timeout; - }; - emitting = p_emitting; - _change_notify("config/emitting"); + speed_scale = p_scale; + VS::get_singleton()->particles_set_speed_scale(particles, p_scale); } bool Particles2D::is_emitting() const { return emitting; } - -void Particles2D::set_process_mode(ProcessMode p_mode) { - - process_mode = p_mode; - const bool should_process = emitting || active_count != 0; - set_process(should_process && process_mode == PROCESS_IDLE); - set_fixed_process(should_process && process_mode == PROCESS_FIXED); -} - -Particles2D::ProcessMode Particles2D::get_process_mode() const { - - return process_mode; -} - -void Particles2D::set_amount(int p_amount) { - - ERR_FAIL_INDEX(p_amount, 1024 + 1); - - particles.resize(p_amount); -} int Particles2D::get_amount() const { - return particles.size(); -} - -void Particles2D::set_emit_timeout(float p_timeout) { - - emit_timeout = p_timeout; - time_to_live = p_timeout; -}; - -float Particles2D::get_emit_timeout() const { - - return emit_timeout; -}; - -void Particles2D::set_lifetime(float p_lifetime) { - - ERR_FAIL_INDEX(p_lifetime, 3600 + 1); - - lifetime = p_lifetime; + return amount; } float Particles2D::get_lifetime() const { return lifetime; } - -void Particles2D::set_time_scale(float p_time_scale) { - - time_scale = p_time_scale; -} -float Particles2D::get_time_scale() const { - - return time_scale; -} - -void Particles2D::set_pre_process_time(float p_pre_process_time) { - - preprocess = p_pre_process_time; -} - float Particles2D::get_pre_process_time() const { - return preprocess; -} - -void Particles2D::set_param(Parameter p_param, float p_value) { - - ERR_FAIL_INDEX(p_param, PARAM_MAX); - param[p_param] = p_value; -} -float Particles2D::get_param(Parameter p_param) const { - - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - return param[p_param]; -} - -void Particles2D::set_randomness(Parameter p_param, float p_value) { - - ERR_FAIL_INDEX(p_param, PARAM_MAX); - randomness[p_param] = p_value; -} -float Particles2D::get_randomness(Parameter p_param) const { - - ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); - return randomness[p_param]; -} - -void Particles2D::set_texture(const Ref<Texture> &p_texture) { - - texture = p_texture; -} - -Ref<Texture> Particles2D::get_texture() const { - - return texture; + return pre_process_time; } +float Particles2D::get_explosiveness_ratio() const { -void Particles2D::set_color(const Color &p_color) { - - default_color = p_color; + return explosiveness_ratio; } +float Particles2D::get_randomness_ratio() const { -Color Particles2D::get_color() const { - - return default_color; + return randomness_ratio; } +Rect2 Particles2D::get_visibility_rect() const { -void Particles2D::set_gradient(const Ref<Gradient> &p_gradient) { - - gradient = p_gradient; + return visibility_rect; } +bool Particles2D::get_use_local_coordinates() const { -Ref<Gradient> Particles2D::get_gradient() const { - - return gradient; + return local_coords; } +Ref<Material> Particles2D::get_process_material() const { -void Particles2D::set_emissor_offset(const Point2 &p_offset) { - - emissor_offset = p_offset; + return process_material; } -Point2 Particles2D::get_emissor_offset() const { +float Particles2D::get_speed_scale() const { - return emissor_offset; + return speed_scale; } -void Particles2D::set_use_local_space(bool p_use) { +void Particles2D::set_draw_order(DrawOrder p_order) { - local_space = p_use; + draw_order = p_order; + VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order)); } -bool Particles2D::is_using_local_space() const { +Particles2D::DrawOrder Particles2D::get_draw_order() const { - return local_space; + return draw_order; } -//Deprecated. Converts color phases to color ramp -void Particles2D::set_color_phases(int p_phases) { - - //Create color ramp if we have 2 or more phases. - //Otherwise first phase phase will be assigned to default color. - if (p_phases > 1 && gradient.is_null()) { - gradient = Ref<Gradient>(memnew(Gradient())); - } - if (gradient.is_valid()) { - gradient->get_points().resize(p_phases); - } +void Particles2D::set_fixed_fps(int p_count) { + fixed_fps = p_count; + VS::get_singleton()->particles_set_fixed_fps(particles, p_count); } -//Deprecated. -int Particles2D::get_color_phases() const { - - if (gradient.is_valid()) { - return gradient->get_points_count(); - } - return 0; +int Particles2D::get_fixed_fps() const { + return fixed_fps; } -//Deprecated. Converts color phases to color ramp -void Particles2D::set_color_phase_color(int p_phase, const Color &p_color) { - - ERR_FAIL_INDEX(p_phase, MAX_COLOR_PHASES); - if (gradient.is_valid()) { - if (gradient->get_points_count() > p_phase) - gradient->set_color(p_phase, p_color); - } else { - if (p_phase == 0) - default_color = p_color; - } +void Particles2D::set_fractional_delta(bool p_enable) { + fractional_delta = p_enable; + VS::get_singleton()->particles_set_fractional_delta(particles, p_enable); } -//Deprecated. -Color Particles2D::get_color_phase_color(int p_phase) const { - - ERR_FAIL_INDEX_V(p_phase, MAX_COLOR_PHASES, Color()); - if (gradient.is_valid()) { - return gradient->get_color(p_phase); - } - return Color(0, 0, 0, 1); +bool Particles2D::get_fractional_delta() const { + return fractional_delta; } -//Deprecated. Converts color phases to color ramp -void Particles2D::set_color_phase_pos(int p_phase, float p_pos) { - ERR_FAIL_INDEX(p_phase, MAX_COLOR_PHASES); - ERR_FAIL_COND(p_pos < 0.0 || p_pos > 1.0); - if (gradient.is_valid() && gradient->get_points_count() > p_phase) { - return gradient->set_offset(p_phase, p_pos); - } -} +String Particles2D::get_configuration_warning() const { -//Deprecated. -float Particles2D::get_color_phase_pos(int p_phase) const { + String warnings; - ERR_FAIL_INDEX_V(p_phase, MAX_COLOR_PHASES, 0); - if (gradient.is_valid()) { - return gradient->get_offset(p_phase); + if (process_material.is_null()) { + if (warnings != String()) + warnings += "\n"; + warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted."); } - return 0; -} - -void Particles2D::set_emission_half_extents(const Vector2 &p_extents) { - extents = p_extents; + return warnings; } -Vector2 Particles2D::get_emission_half_extents() const { +Rect2 Particles2D::capture_rect() const { - return extents; + Rect3 aabb = VS::get_singleton()->particles_get_current_aabb(particles); + Rect2 r; + r.position.x = aabb.position.x; + r.position.y = aabb.position.y; + r.size.x = aabb.size.x; + r.size.y = aabb.size.y; + return r; } -void Particles2D::set_initial_velocity(const Vector2 &p_velocity) { - - initial_velocity = p_velocity; -} -Vector2 Particles2D::get_initial_velocity() const { - - return initial_velocity; +void Particles2D::set_texture(const Ref<Texture> &p_texture) { + texture = p_texture; + update(); } -void Particles2D::pre_process(float p_delta) { - - _process_particles(p_delta); +Ref<Texture> Particles2D::get_texture() const { + return texture; } -void Particles2D::set_explosiveness(float p_value) { +void Particles2D::set_normal_map(const Ref<Texture> &p_normal_map) { - explosiveness = p_value; + normal_map = p_normal_map; + update(); } -float Particles2D::get_explosiveness() const { - - return explosiveness; +Ref<Texture> Particles2D::get_normal_map() const { + return normal_map; } -void Particles2D::set_flip_h(bool p_flip) { - - flip_h = p_flip; +void Particles2D::_validate_property(PropertyInfo &property) const { } -bool Particles2D::is_flipped_h() const { +void Particles2D::set_v_frames(int p_count) { - return flip_h; + ERR_FAIL_COND(p_count < 1); + v_frames = p_count; + update(); } -void Particles2D::set_flip_v(bool p_flip) { - - flip_v = p_flip; -} -bool Particles2D::is_flipped_v() const { +int Particles2D::get_v_frames() const { - return flip_v; + return v_frames; } -void Particles2D::set_h_frames(int p_frames) { +void Particles2D::set_h_frames(int p_count) { - ERR_FAIL_COND(p_frames < 1); - h_frames = p_frames; + ERR_FAIL_COND(p_count < 1); + h_frames = p_count; + update(); } int Particles2D::get_h_frames() const { @@ -932,215 +264,122 @@ int Particles2D::get_h_frames() const { return h_frames; } -void Particles2D::set_v_frames(int p_frames) { - - ERR_FAIL_COND(p_frames < 1); - v_frames = p_frames; -} -int Particles2D::get_v_frames() const { - - return v_frames; -} +void Particles2D::_notification(int p_what) { -void Particles2D::set_emission_points(const PoolVector<Vector2> &p_points) { + if (p_what == NOTIFICATION_DRAW) { - emission_points = p_points; -} + RID texture_rid; + if (texture.is_valid()) + texture_rid = texture->get_rid(); + RID normal_rid; + if (normal_map.is_valid()) + normal_rid = texture->get_rid(); -PoolVector<Vector2> Particles2D::get_emission_points() const { + VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid, h_frames, v_frames); - return emission_points; -} +#ifdef TOOLS_ENABLED + if (get_tree()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) { -void Particles2D::reset() { + draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); + } +#endif + } - for (int i = 0; i < particles.size(); i++) { - particles[i].active = false; + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + _update_particle_emission_transform(); } - time = 0; - active_count = 0; } void Particles2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_emitting", "active"), &Particles2D::set_emitting); - ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting); - - ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Particles2D::set_process_mode); - ClassDB::bind_method(D_METHOD("get_process_mode"), &Particles2D::get_process_mode); - + ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount); - ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount); + ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime); + ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time); + ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio); + ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio); + ClassDB::bind_method(D_METHOD("set_visibility_rect", "aabb"), &Particles2D::set_visibility_rect); + ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles2D::set_use_local_coordinates); + ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles2D::set_fixed_fps); + ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles2D::set_fractional_delta); + ClassDB::bind_method(D_METHOD("set_process_material", "material:Material"), &Particles2D::set_process_material); + ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles2D::set_speed_scale); - ClassDB::bind_method(D_METHOD("set_lifetime", "lifetime"), &Particles2D::set_lifetime); + ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting); + ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount); ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime); - - ClassDB::bind_method(D_METHOD("set_time_scale", "time_scale"), &Particles2D::set_time_scale); - ClassDB::bind_method(D_METHOD("get_time_scale"), &Particles2D::get_time_scale); - - ClassDB::bind_method(D_METHOD("set_pre_process_time", "time"), &Particles2D::set_pre_process_time); ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time); - - ClassDB::bind_method(D_METHOD("set_emit_timeout", "value"), &Particles2D::set_emit_timeout); - ClassDB::bind_method(D_METHOD("get_emit_timeout"), &Particles2D::get_emit_timeout); - - ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &Particles2D::set_param); - ClassDB::bind_method(D_METHOD("get_param", "param"), &Particles2D::get_param); - - ClassDB::bind_method(D_METHOD("set_randomness", "param", "value"), &Particles2D::set_randomness); - ClassDB::bind_method(D_METHOD("get_randomness", "param"), &Particles2D::get_randomness); - - ClassDB::bind_method(D_METHOD("set_texture:Texture", "texture"), &Particles2D::set_texture); + ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio); + ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio); + ClassDB::bind_method(D_METHOD("get_visibility_rect"), &Particles2D::get_visibility_rect); + ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles2D::get_use_local_coordinates); + ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles2D::get_fixed_fps); + ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles2D::get_fractional_delta); + ClassDB::bind_method(D_METHOD("get_process_material:Material"), &Particles2D::get_process_material); + ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles2D::get_speed_scale); + + ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles2D::set_draw_order); + ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles2D::get_draw_order); + + ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &Particles2D::set_texture); ClassDB::bind_method(D_METHOD("get_texture:Texture"), &Particles2D::get_texture); - ClassDB::bind_method(D_METHOD("set_color", "color"), &Particles2D::set_color); - ClassDB::bind_method(D_METHOD("get_color"), &Particles2D::get_color); - - ClassDB::bind_method(D_METHOD("set_gradient:Gradient", "gradient"), &Particles2D::set_gradient); - ClassDB::bind_method(D_METHOD("get_gradient:Gradient"), &Particles2D::get_gradient); - - ClassDB::bind_method(D_METHOD("set_emissor_offset", "offset"), &Particles2D::set_emissor_offset); - ClassDB::bind_method(D_METHOD("get_emissor_offset"), &Particles2D::get_emissor_offset); - - ClassDB::bind_method(D_METHOD("set_flip_h", "enable"), &Particles2D::set_flip_h); - ClassDB::bind_method(D_METHOD("is_flipped_h"), &Particles2D::is_flipped_h); - - ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &Particles2D::set_flip_v); - ClassDB::bind_method(D_METHOD("is_flipped_v"), &Particles2D::is_flipped_v); + ClassDB::bind_method(D_METHOD("set_normal_map", "texture:Texture"), &Particles2D::set_normal_map); + ClassDB::bind_method(D_METHOD("get_normal_map:Texture"), &Particles2D::get_normal_map); - ClassDB::bind_method(D_METHOD("set_h_frames", "enable"), &Particles2D::set_h_frames); - ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames); + ClassDB::bind_method(D_METHOD("capture_rect"), &Particles2D::capture_rect); - ClassDB::bind_method(D_METHOD("set_v_frames", "enable"), &Particles2D::set_v_frames); + ClassDB::bind_method(D_METHOD("set_v_frames", "frames"), &Particles2D::set_v_frames); ClassDB::bind_method(D_METHOD("get_v_frames"), &Particles2D::get_v_frames); - ClassDB::bind_method(D_METHOD("set_emission_half_extents", "extents"), &Particles2D::set_emission_half_extents); - ClassDB::bind_method(D_METHOD("get_emission_half_extents"), &Particles2D::get_emission_half_extents); - - ClassDB::bind_method(D_METHOD("set_color_phases", "phases"), &Particles2D::set_color_phases); - ClassDB::bind_method(D_METHOD("get_color_phases"), &Particles2D::get_color_phases); - - ClassDB::bind_method(D_METHOD("set_color_phase_color", "phase", "color"), &Particles2D::set_color_phase_color); - ClassDB::bind_method(D_METHOD("get_color_phase_color", "phase"), &Particles2D::get_color_phase_color); - - ClassDB::bind_method(D_METHOD("set_color_phase_pos", "phase", "pos"), &Particles2D::set_color_phase_pos); - ClassDB::bind_method(D_METHOD("get_color_phase_pos", "phase"), &Particles2D::get_color_phase_pos); - - ClassDB::bind_method(D_METHOD("pre_process", "time"), &Particles2D::pre_process); - ClassDB::bind_method(D_METHOD("reset"), &Particles2D::reset); - - ClassDB::bind_method(D_METHOD("set_use_local_space", "enable"), &Particles2D::set_use_local_space); - ClassDB::bind_method(D_METHOD("is_using_local_space"), &Particles2D::is_using_local_space); - - ClassDB::bind_method(D_METHOD("set_initial_velocity", "velocity"), &Particles2D::set_initial_velocity); - ClassDB::bind_method(D_METHOD("get_initial_velocity"), &Particles2D::get_initial_velocity); - - ClassDB::bind_method(D_METHOD("set_explosiveness", "amount"), &Particles2D::set_explosiveness); - ClassDB::bind_method(D_METHOD("get_explosiveness"), &Particles2D::get_explosiveness); - - ClassDB::bind_method(D_METHOD("set_emission_points", "points"), &Particles2D::set_emission_points); - ClassDB::bind_method(D_METHOD("get_emission_points"), &Particles2D::get_emission_points); - - ADD_SIGNAL(MethodInfo("emission_finished")); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "config/amount", PROPERTY_HINT_EXP_RANGE, "1,1024"), "set_amount", "get_amount"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "config/lifetime", PROPERTY_HINT_EXP_RANGE, "0.1,3600,0.1"), "set_lifetime", "get_lifetime"); - ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "config/time_scale", PROPERTY_HINT_EXP_RANGE, "0.01,128,0.01"), "set_time_scale", "get_time_scale"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "config/preprocess", PROPERTY_HINT_EXP_RANGE, "0,3600,0.1"), "set_pre_process_time", "get_pre_process_time"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "config/emit_timeout", PROPERTY_HINT_RANGE, "0,3600,0.1"), "set_emit_timeout", "get_emit_timeout"); - ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "config/emitting"), "set_emitting", "is_emitting"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "config/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), "set_process_mode", "get_process_mode"); - ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "config/offset"), "set_emissor_offset", "get_emissor_offset"); - ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "config/half_extents"), "set_emission_half_extents", "get_emission_half_extents"); - ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "config/local_space"), "set_use_local_space", "is_using_local_space"); - ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "config/explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness", "get_explosiveness"); - ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "config/flip_h"), "set_flip_h", "is_flipped_h"); - ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "config/flip_v"), "set_flip_v", "is_flipped_v"); - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "config/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); - ADD_PROPERTYNO(PropertyInfo(Variant::INT, "config/h_frames", PROPERTY_HINT_RANGE, "1,512,1"), "set_h_frames", "get_h_frames"); - ADD_PROPERTYNO(PropertyInfo(Variant::INT, "config/v_frames", PROPERTY_HINT_RANGE, "1,512,1"), "set_v_frames", "get_v_frames"); - - for (int i = 0; i < PARAM_MAX; i++) { - ADD_PROPERTYI(PropertyInfo(Variant::REAL, _particlesframe_property_names[i], PROPERTY_HINT_RANGE, _particlesframe_property_ranges[i]), "set_param", "get_param", i); - } - - for (int i = 0; i < PARAM_MAX; i++) { - ADD_PROPERTYINZ(PropertyInfo(Variant::REAL, _particlesframe_property_rnames[i], PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_randomness", "get_randomness", i); - } - - ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "color_phases/count", PROPERTY_HINT_RANGE, "0,4,1", 0), "set_color_phases", "get_color_phases"); - - //Backward compatibility. They will be converted to color ramp - for (int i = 0; i < MAX_COLOR_PHASES; i++) { - String phase = "phase_" + itos(i) + "/"; - ADD_PROPERTYI(PropertyInfo(Variant::REAL, phase + "pos", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_color_phase_pos", "get_color_phase_pos", i); - ADD_PROPERTYI(PropertyInfo(Variant::COLOR, phase + "color", PROPERTY_HINT_NONE, "", 0), "set_color_phase_color", "get_color_phase_color", i); - } + ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames); + ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames); - ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "color/color"), "set_color", "get_color"); - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "color/color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); - - ADD_PROPERTYNZ(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "emission_points", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_emission_points", "get_emission_points"); - - BIND_CONSTANT(PARAM_DIRECTION); - BIND_CONSTANT(PARAM_SPREAD); - BIND_CONSTANT(PARAM_LINEAR_VELOCITY); - BIND_CONSTANT(PARAM_SPIN_VELOCITY); - BIND_CONSTANT(PARAM_ORBIT_VELOCITY); - BIND_CONSTANT(PARAM_GRAVITY_DIRECTION); - BIND_CONSTANT(PARAM_GRAVITY_STRENGTH); - BIND_CONSTANT(PARAM_RADIAL_ACCEL); - BIND_CONSTANT(PARAM_TANGENTIAL_ACCEL); - BIND_CONSTANT(PARAM_DAMPING); - BIND_CONSTANT(PARAM_INITIAL_ANGLE); - BIND_CONSTANT(PARAM_INITIAL_SIZE); - BIND_CONSTANT(PARAM_FINAL_SIZE); - BIND_CONSTANT(PARAM_HUE_VARIATION); - BIND_CONSTANT(PARAM_ANIM_SPEED_SCALE); - BIND_CONSTANT(PARAM_ANIM_INITIAL_POS); - BIND_CONSTANT(PARAM_MAX); - - BIND_CONSTANT(MAX_COLOR_PHASES); + ADD_GROUP("Parameters", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_rect"), "set_visibility_rect", "get_visibility_rect"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order"); + ADD_GROUP("Process Material", "process_"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); + ADD_GROUP("Textures", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "h_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_h_frames", "get_h_frames"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "v_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_v_frames", "get_v_frames"); + + BIND_CONSTANT(DRAW_ORDER_INDEX); + BIND_CONSTANT(DRAW_ORDER_LIFETIME); } Particles2D::Particles2D() { - for (int i = 0; i < PARAM_MAX; i++) { - - param[i] = 0; - randomness[i] = 0; - } + particles = VS::get_singleton()->particles_create(); - set_param(PARAM_SPREAD, 10); - set_param(PARAM_LINEAR_VELOCITY, 20); - set_param(PARAM_GRAVITY_STRENGTH, 9.8); - set_param(PARAM_RADIAL_ACCEL, 0); - set_param(PARAM_TANGENTIAL_ACCEL, 0); - set_param(PARAM_INITIAL_ANGLE, 0.0); - set_param(PARAM_INITIAL_SIZE, 1.0); - set_param(PARAM_FINAL_SIZE, 1.0); - set_param(PARAM_ANIM_SPEED_SCALE, 1.0); - - set_color(Color(1, 1, 1, 1)); - - time = 0; - lifetime = 2; - emitting = false; - particles.resize(32); - active_count = -1; set_emitting(true); - process_mode = PROCESS_IDLE; - local_space = true; - preprocess = 0; - time_scale = 1.0; - - flip_h = false; - flip_v = false; - - v_frames = 1; + set_amount(8); + set_lifetime(1); + set_fixed_fps(0); + set_fractional_delta(true); + set_pre_process_time(0); + set_explosiveness_ratio(0); + set_randomness_ratio(0); + set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200))); + set_use_local_coordinates(true); + set_speed_scale(1); h_frames = 1; + v_frames = 1; +} + +Particles2D::~Particles2D() { - emit_timeout = 0; - time_to_live = 0; - explosiveness = 1.0; + VS::get_singleton()->free(particles); } diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index 856beaa836..ab7dcb1464 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -34,235 +34,98 @@ #include "scene/resources/color_ramp.h" #include "scene/resources/texture.h" -class Particles2D; -class ParticleAttractor2D : public Node2D { - - GDCLASS(ParticleAttractor2D, Node2D); - - friend class Particles2D; - bool enabled; - float radius; - float disable_radius; - float gravity; - float absorption; - NodePath path; - - Particles2D *owner; - - void _update_owner(); - void _owner_exited(); - void _set_owner(Particles2D *p_owner); - - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_enabled(bool p_enabled); - bool is_enabled() const; - - void set_radius(float p_radius); - float get_radius() const; - - void set_disable_radius(float p_disable_radius); - float get_disable_radius() const; - - void set_gravity(float p_gravity); - float get_gravity() const; - - void set_absorption(float p_absorption); - float get_absorption() const; - - void set_particles_path(NodePath p_path); - NodePath get_particles_path() const; - - virtual String get_configuration_warning() const; - - ParticleAttractor2D(); -}; - class Particles2D : public Node2D { - - GDCLASS(Particles2D, Node2D); +private: + GDCLASS(Particles2D, Node2D) public: - enum Parameter { - PARAM_DIRECTION, - PARAM_SPREAD, - PARAM_LINEAR_VELOCITY, - PARAM_SPIN_VELOCITY, - PARAM_ORBIT_VELOCITY, - PARAM_GRAVITY_DIRECTION, - PARAM_GRAVITY_STRENGTH, - PARAM_RADIAL_ACCEL, - PARAM_TANGENTIAL_ACCEL, - PARAM_DAMPING, - PARAM_INITIAL_ANGLE, - PARAM_INITIAL_SIZE, - PARAM_FINAL_SIZE, - PARAM_HUE_VARIATION, - PARAM_ANIM_SPEED_SCALE, - PARAM_ANIM_INITIAL_POS, - PARAM_MAX - }; - - enum { - MAX_COLOR_PHASES = 4 - }; - - enum ProcessMode { - PROCESS_FIXED, - PROCESS_IDLE, + enum DrawOrder { + DRAW_ORDER_INDEX, + DRAW_ORDER_LIFETIME, }; private: - float param[PARAM_MAX]; - float randomness[PARAM_MAX]; + RID particles; - struct Particle { - bool active; - Point2 pos; - Vector2 velocity; - float rot; - float frame; - uint64_t seed; - Particle() { - active = false; - seed = 123465789; - rot = 0; - frame = 0; - } - }; - - Vector<Particle> particles; - - struct AttractorCache { - - Vector2 pos; - ParticleAttractor2D *attractor; - }; - - Vector<AttractorCache> attractor_cache; - - float explosiveness; - float preprocess; - float lifetime; bool emitting; - bool local_space; - float emit_timeout; - float time_to_live; - float time_scale; - bool flip_h; - bool flip_v; - int h_frames; + int amount; + float lifetime; + float pre_process_time; + float explosiveness_ratio; + float randomness_ratio; + float speed_scale; + Rect2 visibility_rect; + bool local_coords; + int fixed_fps; + bool fractional_delta; int v_frames; - Point2 emissor_offset; - Vector2 initial_velocity; - Vector2 extents; - PoolVector<Vector2> emission_points; + int h_frames; - ProcessMode process_mode; + Ref<Material> process_material; - float time; - int active_count; + DrawOrder draw_order; Ref<Texture> texture; + Ref<Texture> normal_map; - //If no color ramp is set then default color is used. Created as simple alternative to color_ramp. - Color default_color; - Ref<Gradient> gradient; - - void _process_particles(float p_delta); - friend class ParticleAttractor2D; - - Set<ParticleAttractor2D *> attractors; + void _update_particle_emission_transform(); protected: - void _notification(int p_what); static void _bind_methods(); + virtual void _validate_property(PropertyInfo &property) const; + void _notification(int p_what); public: void set_emitting(bool p_emitting); - bool is_emitting() const; - - void set_process_mode(ProcessMode p_mode); - ProcessMode get_process_mode() const; - void set_amount(int p_amount); - int get_amount() const; - void set_lifetime(float p_lifetime); - float get_lifetime() const; - - void set_time_scale(float p_time_scale); - float get_time_scale() const; + void set_pre_process_time(float p_time); + void set_explosiveness_ratio(float p_ratio); + void set_randomness_ratio(float p_ratio); + void set_visibility_rect(const Rect2 &p_aabb); + void set_use_local_coordinates(bool p_enable); + void set_process_material(const Ref<Material> &p_material); + void set_speed_scale(float p_scale); - void set_pre_process_time(float p_pre_process_time); + bool is_emitting() const; + int get_amount() const; + float get_lifetime() const; float get_pre_process_time() const; + float get_explosiveness_ratio() const; + float get_randomness_ratio() const; + Rect2 get_visibility_rect() const; + bool get_use_local_coordinates() const; + Ref<Material> get_process_material() const; + float get_speed_scale() const; - void set_emit_timeout(float p_timeout); - float get_emit_timeout() const; - - void set_emission_half_extents(const Vector2 &p_extents); - Vector2 get_emission_half_extents() const; + void set_fixed_fps(int p_count); + int get_fixed_fps() const; - void set_param(Parameter p_param, float p_value); - float get_param(Parameter p_param) const; + void set_fractional_delta(bool p_enable); + bool get_fractional_delta() const; - void set_randomness(Parameter p_randomness, float p_value); - float get_randomness(Parameter p_randomness) const; - - void set_explosiveness(float p_value); - float get_explosiveness() const; - - void set_flip_h(bool p_flip); - bool is_flipped_h() const; - - void set_flip_v(bool p_flip); - bool is_flipped_v() const; - - void set_h_frames(int p_frames); - int get_h_frames() const; - - void set_v_frames(int p_frames); - int get_v_frames() const; - - void set_color_phases(int p_phases); - int get_color_phases() const; - - void set_color_phase_color(int p_phase, const Color &p_color); - Color get_color_phase_color(int p_phase) const; - - void set_color_phase_pos(int p_phase, float p_pos); - float get_color_phase_pos(int p_phase) const; + void set_draw_order(DrawOrder p_order); + DrawOrder get_draw_order() const; void set_texture(const Ref<Texture> &p_texture); Ref<Texture> get_texture() const; - void set_color(const Color &p_color); - Color get_color() const; - - void set_gradient(const Ref<Gradient> &p_texture); - Ref<Gradient> get_gradient() const; - - void set_emissor_offset(const Point2 &p_offset); - Point2 get_emissor_offset() const; + void set_normal_map(const Ref<Texture> &p_normal_map); + Ref<Texture> get_normal_map() const; - void set_use_local_space(bool p_use); - bool is_using_local_space() const; - - void set_initial_velocity(const Vector2 &p_velocity); - Vector2 get_initial_velocity() const; + virtual String get_configuration_warning() const; - void set_emission_points(const PoolVector<Vector2> &p_points); - PoolVector<Vector2> get_emission_points() const; + void set_v_frames(int p_count); + int get_v_frames() const; - void pre_process(float p_delta); - void reset(); + void set_h_frames(int p_count); + int get_h_frames() const; + Rect2 capture_rect() const; Particles2D(); + ~Particles2D(); }; -VARIANT_ENUM_CAST(Particles2D::ProcessMode); -VARIANT_ENUM_CAST(Particles2D::Parameter); +VARIANT_ENUM_CAST(Particles2D::DrawOrder) #endif // PARTICLES_FRAME_H diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 68270ed771..fd261117e1 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -44,28 +44,6 @@ void PhysicsBody2D::_notification(int p_what) { */ } -void PhysicsBody2D::set_one_way_collision_direction(const Vector2 &p_dir) { - - one_way_collision_direction = p_dir; - Physics2DServer::get_singleton()->body_set_one_way_collision_direction(get_rid(), p_dir); -} - -Vector2 PhysicsBody2D::get_one_way_collision_direction() const { - - return one_way_collision_direction; -} - -void PhysicsBody2D::set_one_way_collision_max_depth(float p_depth) { - - one_way_collision_max_depth = p_depth; - Physics2DServer::get_singleton()->body_set_one_way_collision_max_depth(get_rid(), p_depth); -} - -float PhysicsBody2D::get_one_way_collision_max_depth() const { - - return one_way_collision_max_depth; -} - void PhysicsBody2D::_set_layers(uint32_t p_mask) { set_collision_layer(p_mask); @@ -92,10 +70,6 @@ void PhysicsBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody2D::_set_layers); ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody2D::_get_layers); - ClassDB::bind_method(D_METHOD("set_one_way_collision_direction", "dir"), &PhysicsBody2D::set_one_way_collision_direction); - ClassDB::bind_method(D_METHOD("get_one_way_collision_direction"), &PhysicsBody2D::get_one_way_collision_direction); - ClassDB::bind_method(D_METHOD("set_one_way_collision_max_depth", "depth"), &PhysicsBody2D::set_one_way_collision_max_depth); - ClassDB::bind_method(D_METHOD("get_one_way_collision_max_depth"), &PhysicsBody2D::get_one_way_collision_max_depth); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body:PhysicsBody2D"), &PhysicsBody2D::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body:PhysicsBody2D"), &PhysicsBody2D::remove_collision_exception_with); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", 0), "_set_layers", "_get_layers"); //for backwards compat @@ -103,9 +77,6 @@ void PhysicsBody2D::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); - ADD_GROUP("", ""); - ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "one_way_collision/direction"), "set_one_way_collision_direction", "get_one_way_collision_direction"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "one_way_collision/max_depth"), "set_one_way_collision_max_depth", "get_one_way_collision_max_depth"); } void PhysicsBody2D::set_collision_layer(uint32_t p_layer) { @@ -164,7 +135,6 @@ PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) collision_layer = 1; collision_mask = 1; - set_one_way_collision_max_depth(0); set_pickable(false); } @@ -971,248 +941,105 @@ RigidBody2D::~RigidBody2D() { ////////////////////////// -Variant KinematicBody2D::_get_collider() const { - - ObjectID oid = get_collider(); - if (oid == 0) - return Variant(); - Object *obj = ObjectDB::get_instance(oid); - if (!obj) - return Variant(); - - Reference *ref = obj->cast_to<Reference>(); - if (ref) { - return Ref<Reference>(ref); - } - - return obj; -} - -void KinematicBody2D::revert_motion() { +Dictionary KinematicBody2D::_move(const Vector2 &p_motion) { + + Collision col; + if (move(p_motion, col)) { + Dictionary d; + d["position"] = col.collision; + d["normal"] = col.collision; + d["local_shape"] = col.local_shape; + d["travel"] = col.travel; + d["remainder"] = col.remainder; + d["collider_id"] = col.collider; + if (col.collider) { + d["collider"] = ObjectDB::get_instance(col.collider); + } else { + d["collider"] = Variant(); + } - Transform2D gt = get_global_transform(); - gt.elements[2] -= travel; - travel = Vector2(); - set_global_transform(gt); -} + d["collider_shape_index"] = col.collider_shape; + d["collider_metadata"] = col.collider_metadata; -Vector2 KinematicBody2D::get_travel() const { + return d; - return travel; + } else { + return Dictionary(); + } } -Vector2 KinematicBody2D::move(const Vector2 &p_motion) { - -#if 1 +bool KinematicBody2D::move(const Vector2 &p_motion, Collision &r_collision) { Transform2D gt = get_global_transform(); Physics2DServer::MotionResult result; - colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result); - - collider_metadata = result.collider_metadata; - collider_shape = result.collider_shape; - collider_vel = result.collider_velocity; - collision = result.collision_point; - normal = result.collision_normal; - collider = result.collider_id; - - gt.elements[2] += result.motion; - set_global_transform(gt); - travel = result.motion; - - return result.remainder; - -#else - //give me back regular physics engine logic - //this is madness - //and most people using this function will think - //what it does is simpler than using physics - //this took about a week to get right.. - //but is it right? who knows at this point.. - - colliding = false; - ERR_FAIL_COND_V(!is_inside_tree(), Vector2()); - Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); - ERR_FAIL_COND_V(!dss, Vector2()); - const int max_shapes = 32; - Vector2 sr[max_shapes * 2]; - int res_shapes; - - Set<RID> exclude; - exclude.insert(get_rid()); - - //recover first - int recover_attempts = 4; - - bool collided = false; - uint32_t mask = 0; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; - - //print_line("margin: "+rtos(margin)); - do { - - //motion recover - for (int i = 0; i < get_shape_count(); i++) { - - if (is_shape_set_as_trigger(i)) - continue; - if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), Vector2(), margin, sr, max_shapes, res_shapes, exclude, get_layer_mask(), mask)) - collided = true; - } - - if (!collided) - break; - - Vector2 recover_motion; - - for (int i = 0; i < res_shapes; i++) { - - Vector2 a = sr[i * 2 + 0]; - Vector2 b = sr[i * 2 + 1]; - - float d = a.distance_to(b); - - /* - if (d<margin) - continue; - */ - recover_motion += (b - a) * 0.4; - } - - if (recover_motion == Vector2()) { - collided = false; - break; - } - - Transform2D gt = get_global_transform(); - gt.elements[2] += recover_motion; - set_global_transform(gt); - - recover_attempts--; - - } while (recover_attempts); - - //move second - float safe = 1.0; - float unsafe = 1.0; - int best_shape = -1; - - for (int i = 0; i < get_shape_count(); i++) { - - if (is_shape_set_as_trigger(i)) - continue; - - float lsafe, lunsafe; - bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0, lsafe, lunsafe, exclude, get_layer_mask(), mask); - //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); - if (!valid) { - - safe = 0; - unsafe = 0; - best_shape = i; //sadly it's the best - break; - } - if (lsafe == 1.0) { - continue; - } - if (lsafe < safe) { - - safe = lsafe; - unsafe = lunsafe; - best_shape = i; - } + bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result); + + if (colliding) { + r_collision.collider_metadata = result.collider_metadata; + r_collision.collider_shape = result.collider_shape; + r_collision.collider_vel = result.collider_velocity; + r_collision.collision = result.collision_point; + r_collision.normal = result.collision_normal; + r_collision.collider = result.collider_id; + r_collision.travel = result.motion; + r_collision.remainder = result.remainder; + r_collision.local_shape = result.collision_local_shape; } - //print_line("best shape: "+itos(best_shape)+" motion "+p_motion); - - if (safe >= 1) { - //not collided - colliding = false; - - } else { - - //it collided, let's get the rest info in unsafe advance - Transform2D ugt = get_global_transform(); - ugt.elements[2] += p_motion * unsafe; - Physics2DDirectSpaceState::ShapeRestInfo rest_info; - bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt * get_shape_transform(best_shape), Vector2(), margin, &rest_info, exclude, get_layer_mask(), mask); - if (!c2) { - //should not happen, but floating point precision is so weird.. - - colliding = false; - } else { - - //print_line("Travel: "+rtos(travel)); - colliding = true; - collision = rest_info.point; - normal = rest_info.normal; - collider = rest_info.collider_id; - collider_vel = rest_info.linear_velocity; - collider_shape = rest_info.shape; - collider_metadata = rest_info.metadata; - } - } - - Vector2 motion = p_motion * safe; - Transform2D gt = get_global_transform(); - gt.elements[2] += motion; + gt.elements[2] += result.motion; set_global_transform(gt); - return p_motion - motion; -#endif + return colliding; } Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_bounces, float p_floor_max_angle) { - Vector2 motion = (move_and_slide_floor_velocity + p_linear_velocity) * get_fixed_process_delta_time(); + Vector2 motion = (floor_velocity + p_linear_velocity) * get_fixed_process_delta_time(); Vector2 lv = p_linear_velocity; - move_and_slide_on_floor = false; - move_and_slide_on_ceiling = false; - move_and_slide_on_wall = false; - move_and_slide_colliders.clear(); - move_and_slide_floor_velocity = Vector2(); + on_floor = false; + on_ceiling = false; + on_wall = false; + colliders.clear(); + floor_velocity = Vector2(); while (p_max_bounces) { - motion = move(motion); + Collision collision; + + bool collided = move(motion, collision); - if (is_colliding()) { + if (collided) { + + motion = collision.remainder; if (p_floor_direction == Vector2()) { //all is a wall - move_and_slide_on_wall = true; + on_wall = true; } else { - if (get_collision_normal().dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor + if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor - move_and_slide_on_floor = true; - move_and_slide_floor_velocity = get_collider_velocity(); + on_floor = true; + floor_velocity = collision.collider_vel; - if (get_travel().length() < 1 && ABS((lv.x - move_and_slide_floor_velocity.x)) < p_slope_stop_min_velocity) { - revert_motion(); + if (collision.travel.length() < 1 && ABS((lv.x - floor_velocity.x)) < p_slope_stop_min_velocity) { + Transform2D gt = get_global_transform(); + gt.elements[2] -= collision.travel; + set_global_transform(gt); return Vector2(); } - } else if (get_collision_normal().dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling - move_and_slide_on_ceiling = true; + } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling + on_ceiling = true; } else { - move_and_slide_on_wall = true; + on_wall = true; } } - Vector2 n = get_collision_normal(); + Vector2 n = collision.normal; motion = motion.slide(n); lv = lv.slide(n); - Variant collider = _get_collider(); - if (collider.get_type() != Variant::NIL) { - move_and_slide_colliders.push_back(collider); - } + + colliders.push_back(collision); } else { break; @@ -1226,26 +1053,22 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const return lv; } -bool KinematicBody2D::is_move_and_slide_on_floor() const { +bool KinematicBody2D::is_on_floor() const { - return move_and_slide_on_floor; + return on_floor; } -bool KinematicBody2D::is_move_and_slide_on_wall() const { +bool KinematicBody2D::is_on_wall() const { - return move_and_slide_on_wall; + return on_wall; } -bool KinematicBody2D::is_move_and_slide_on_ceiling() const { +bool KinematicBody2D::is_on_ceiling() const { - return move_and_slide_on_ceiling; + return on_ceiling; } -Array KinematicBody2D::get_move_and_slide_colliders() const { - return move_and_slide_colliders; -} +Vector2 KinematicBody2D::get_floor_velocity() const { -Vector2 KinematicBody2D::move_to(const Vector2 &p_position) { - - return move(p_position - get_global_position()); + return floor_velocity; } bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion) { @@ -1255,98 +1078,123 @@ bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_moti return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, margin); } -Vector2 KinematicBody2D::get_collision_pos() const { +void KinematicBody2D::set_safe_margin(float p_margin) { - ERR_FAIL_COND_V(!colliding, Vector2()); - return collision; + margin = p_margin; } -Vector2 KinematicBody2D::get_collision_normal() const { +float KinematicBody2D::get_safe_margin() const { - ERR_FAIL_COND_V(!colliding, Vector2()); - return normal; + return margin; } -Vector2 KinematicBody2D::get_collider_velocity() const { +int KinematicBody2D::get_collision_count() const { - return collider_vel; + return colliders.size(); } +Vector2 KinematicBody2D::get_collision_position(int p_collision) const { -ObjectID KinematicBody2D::get_collider() const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); - ERR_FAIL_COND_V(!colliding, 0); - return collider; + return colliders[p_collision].collision; } - -int KinematicBody2D::get_collider_shape() const { - - ERR_FAIL_COND_V(!colliding, 0); - return collider_shape; +Vector2 KinematicBody2D::get_collision_normal(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].normal; } -Variant KinematicBody2D::get_collider_metadata() const { - - ERR_FAIL_COND_V(!colliding, 0); - return collider_metadata; +Vector2 KinematicBody2D::get_collision_travel(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].travel; } - -bool KinematicBody2D::is_colliding() const { - - return colliding; +Vector2 KinematicBody2D::get_collision_remainder(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].remainder; } +Object *KinematicBody2D::get_collision_local_shape(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL); + uint32_t owner = shape_find_owner(colliders[p_collision].local_shape); + return shape_owner_get_owner(owner); +} +Object *KinematicBody2D::get_collision_collider(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL); -void KinematicBody2D::set_collision_margin(float p_margin) { + if (colliders[p_collision].collider) { + return ObjectDB::get_instance(colliders[p_collision].collider); + } - margin = p_margin; + return NULL; } +ObjectID KinematicBody2D::get_collision_collider_id(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), 0); -float KinematicBody2D::get_collision_margin() const { + return colliders[p_collision].collider; +} +Object *KinematicBody2D::get_collision_collider_shape(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL); + Object *collider = get_collision_collider(p_collision); + if (collider) { + CollisionObject2D *obj2d = collider->cast_to<CollisionObject2D>(); + if (obj2d) { + uint32_t owner = shape_find_owner(colliders[p_collision].collider_shape); + return obj2d->shape_owner_get_owner(owner); + } + } - return margin; + return NULL; +} +int KinematicBody2D::get_collision_collider_shape_index(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), -1); + return colliders[p_collision].collider_shape; +} +Vector2 KinematicBody2D::get_collision_collider_velocity(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].collider_vel; +} +Variant KinematicBody2D::get_collision_collider_metadata(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Variant()); + return colliders[p_collision].collider_metadata; } void KinematicBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move", "rel_vec"), &KinematicBody2D::move); - ClassDB::bind_method(D_METHOD("move_to", "position"), &KinematicBody2D::move_to); + ClassDB::bind_method(D_METHOD("move", "rel_vec"), &KinematicBody2D::_move); ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody2D::test_move); - ClassDB::bind_method(D_METHOD("get_travel"), &KinematicBody2D::get_travel); - ClassDB::bind_method(D_METHOD("revert_motion"), &KinematicBody2D::revert_motion); - ClassDB::bind_method(D_METHOD("is_colliding"), &KinematicBody2D::is_colliding); + ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor); + ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling); + ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody2D::is_on_wall); + ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody2D::get_floor_velocity); - ClassDB::bind_method(D_METHOD("get_collision_pos"), &KinematicBody2D::get_collision_pos); - ClassDB::bind_method(D_METHOD("get_collision_normal"), &KinematicBody2D::get_collision_normal); - ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicBody2D::get_collider_velocity); - ClassDB::bind_method(D_METHOD("get_collider:Variant"), &KinematicBody2D::_get_collider); - ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicBody2D::get_collider_shape); - ClassDB::bind_method(D_METHOD("get_collider_metadata:Variant"), &KinematicBody2D::get_collider_metadata); - ClassDB::bind_method(D_METHOD("get_move_and_slide_colliders"), &KinematicBody2D::get_move_and_slide_colliders); - ClassDB::bind_method(D_METHOD("is_move_and_slide_on_floor"), &KinematicBody2D::is_move_and_slide_on_floor); - ClassDB::bind_method(D_METHOD("is_move_and_slide_on_ceiling"), &KinematicBody2D::is_move_and_slide_on_ceiling); - ClassDB::bind_method(D_METHOD("is_move_and_slide_on_wall"), &KinematicBody2D::is_move_and_slide_on_wall); + ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody2D::set_safe_margin); + ClassDB::bind_method(D_METHOD("get_safe_margin", "pixels"), &KinematicBody2D::get_safe_margin); - ClassDB::bind_method(D_METHOD("set_collision_margin", "pixels"), &KinematicBody2D::set_collision_margin); - ClassDB::bind_method(D_METHOD("get_collision_margin", "pixels"), &KinematicBody2D::get_collision_margin); + ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicBody2D::get_collision_count); + ClassDB::bind_method(D_METHOD("get_collision_position", "collision"), &KinematicBody2D::get_collision_position); + ClassDB::bind_method(D_METHOD("get_collision_normal", "collision"), &KinematicBody2D::get_collision_normal); + ClassDB::bind_method(D_METHOD("get_collision_travel", "collision"), &KinematicBody2D::get_collision_travel); + ClassDB::bind_method(D_METHOD("get_collision_remainder", "collision"), &KinematicBody2D::get_collision_remainder); + ClassDB::bind_method(D_METHOD("get_collision_local_shape", "collision"), &KinematicBody2D::get_collision_local_shape); + ClassDB::bind_method(D_METHOD("get_collision_collider", "collision"), &KinematicBody2D::get_collision_collider); + ClassDB::bind_method(D_METHOD("get_collision_collider_id", "collision"), &KinematicBody2D::get_collision_collider_id); + ClassDB::bind_method(D_METHOD("get_collision_collider_shape", "collision"), &KinematicBody2D::get_collision_collider_shape); + ClassDB::bind_method(D_METHOD("get_collision_collider_shape_index", "collision"), &KinematicBody2D::get_collision_collider_shape_index); + ClassDB::bind_method(D_METHOD("get_collision_collider_velocity", "collision"), &KinematicBody2D::get_collision_collider_velocity); + ClassDB::bind_method(D_METHOD("get_collision_collider_metadata", "collision"), &KinematicBody2D::get_collision_collider_metadata); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_collision_margin", "get_collision_margin"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); } KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KINEMATIC) { - colliding = false; - collider = 0; - - collider_shape = 0; - margin = 0.08; - move_and_slide_on_floor = false; - move_and_slide_on_ceiling = false; - move_and_slide_on_wall = false; + on_floor = false; + on_ceiling = false; + on_wall = false; } KinematicBody2D::~KinematicBody2D() { } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 50c9865f18..8c8e4ebc77 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -40,8 +40,6 @@ class PhysicsBody2D : public CollisionObject2D { uint32_t collision_layer; uint32_t collision_mask; - Vector2 one_way_collision_direction; - float one_way_collision_max_depth; void _set_layers(uint32_t p_mask); uint32_t _get_layers() const; @@ -68,12 +66,6 @@ public: void add_collision_exception_with(Node *p_node); //must be physicsbody void remove_collision_exception_with(Node *p_node); - void set_one_way_collision_direction(const Vector2 &p_dir); - Vector2 get_one_way_collision_direction() const; - - void set_one_way_collision_max_depth(float p_dir); - float get_one_way_collision_max_depth() const; - PhysicsBody2D(); }; @@ -272,54 +264,60 @@ class KinematicBody2D : public PhysicsBody2D { GDCLASS(KinematicBody2D, PhysicsBody2D); +public: + struct Collision { + Vector2 collision; + Vector2 normal; + Vector2 collider_vel; + ObjectID collider; + int collider_shape; + Variant collider_metadata; + Vector2 remainder; + Vector2 travel; + int local_shape; + }; + +private: float margin; - bool colliding; - Vector2 collision; - Vector2 normal; - Vector2 collider_vel; - ObjectID collider; - int collider_shape; - Variant collider_metadata; - Vector2 travel; - - Vector2 move_and_slide_floor_velocity; - bool move_and_slide_on_floor; - bool move_and_slide_on_ceiling; - bool move_and_slide_on_wall; - Array move_and_slide_colliders; - - Variant _get_collider() const; + + Vector2 floor_velocity; + bool on_floor; + bool on_ceiling; + bool on_wall; + Vector<Collision> colliders; _FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const; + Dictionary _move(const Vector2 &p_motion); + protected: static void _bind_methods(); public: - Vector2 move(const Vector2 &p_motion); - Vector2 move_to(const Vector2 &p_position); - + bool move(const Vector2 &p_motion, Collision &r_collision); bool test_move(const Transform2D &p_from, const Vector2 &p_motion); - bool is_colliding() const; - - Vector2 get_travel() const; - void revert_motion(); - - Vector2 get_collision_pos() const; - Vector2 get_collision_normal() const; - Vector2 get_collider_velocity() const; - ObjectID get_collider() const; - int get_collider_shape() const; - Variant get_collider_metadata() const; - void set_collision_margin(float p_margin); - float get_collision_margin() const; + void set_safe_margin(float p_margin); + float get_safe_margin() const; Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), float p_slope_stop_min_velocity = 5, int p_max_bounces = 4, float p_floor_max_angle = Math::deg2rad((float)45)); - bool is_move_and_slide_on_floor() const; - bool is_move_and_slide_on_wall() const; - bool is_move_and_slide_on_ceiling() const; - Array get_move_and_slide_colliders() const; + bool is_on_floor() const; + bool is_on_wall() const; + bool is_on_ceiling() const; + Vector2 get_floor_velocity() const; + + int get_collision_count() const; + Vector2 get_collision_position(int p_collision) const; + Vector2 get_collision_normal(int p_collision) const; + Vector2 get_collision_travel(int p_collision) const; + Vector2 get_collision_remainder(int p_collision) const; + Object *get_collision_local_shape(int p_collision) const; + Object *get_collision_collider(int p_collision) const; + ObjectID get_collision_collider_id(int p_collision) const; + Object *get_collision_collider_shape(int p_collision) const; + int get_collision_collider_shape_index(int p_collision) const; + Vector2 get_collision_collider_velocity(int p_collision) const; + Variant get_collision_collider_metadata(int p_collision) const; KinematicBody2D(); ~KinematicBody2D(); |