-Trigger shapes removed in 2D, they became obsolete long ago when areas could detect their own overlap

-Added ability to disable individual collisionshape/polygon
-Moved One Way Collision to shape, allowing more flexibility
-Changed internals of CollisionObject, shapes are generated from child nodes on the fly, not stored inside any longer.
-Modifying a CollisionPolygon2D on the fly now works, it can even be animated.

Will port this to 3D once well tested. Have fun!
This commit is contained in:
Juan Linietsky 2017-06-23 23:30:43 -03:00
parent 683f50bef4
commit 6ba1e4677b
21 changed files with 512 additions and 649 deletions

View File

@ -105,13 +105,16 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) {
if (!child2->cast_to<StaticBody2D>()) if (!child2->cast_to<StaticBody2D>())
continue; continue;
StaticBody2D *sb = child2->cast_to<StaticBody2D>(); StaticBody2D *sb = child2->cast_to<StaticBody2D>();
int shape_count = sb->get_shape_count();
if (shape_count == 0) List<uint32_t> shapes;
continue; sb->get_shape_owners(&shapes);
for (int shape_index = 0; shape_index < shape_count; ++shape_index) {
Ref<Shape2D> collision = sb->get_shape(shape_index); for (List<uint32_t>::Element *E = shapes.front(); E; E = E->next()) {
if (collision.is_valid()) {
collisions.push_back(collision); for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) {
Ref<Shape> shape = sb->shape_owner_get_shape(E->get(), k);
collisions.push_back(shape); //uh what about transform?
} }
} }
} }

View File

@ -31,18 +31,6 @@
#include "scene/scene_string_names.h" #include "scene/scene_string_names.h"
#include "servers/physics_2d_server.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) { void CollisionObject2D::_notification(int p_what) {
switch (p_what) { switch (p_what) {
@ -88,84 +76,199 @@ void CollisionObject2D::_notification(int p_what) {
} }
} }
void CollisionObject2D::_update_shapes() { uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) {
if (!rid.is_valid()) ShapeData sd;
return; uint32_t id;
if (area) if (shapes.size() == 0) {
Physics2DServer::get_singleton()->area_clear_shapes(rid); id = 1;
else } else {
Physics2DServer::get_singleton()->body_clear_shapes(rid); id = shapes.back()->key() + 1;
}
for (int i = 0; i < shapes.size(); i++) { sd.owner = p_owner;
if (shapes[i].shape.is_null()) shapes[id] = sd;
continue;
if (area) return id;
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); void CollisionObject2D::remove_shape_owner(uint32_t owner) {
if (shapes[i].trigger)
Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid, i, shapes[i].trigger); 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::_set(const StringName &p_name, const Variant &p_value) { bool CollisionObject2D::is_shape_owner_disabled(uint32_t p_owner) const {
String name = p_name;
if (name.begins_with("shapes/")) { ERR_FAIL_COND_V(!shapes.has(p_owner), false);
int idx = name.get_slicec('/', 1).to_int(); return shapes[p_owner].disabled;
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;
} }
bool CollisionObject2D::_get(const StringName &p_name, Variant &r_ret) const { void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable) {
String name = p_name; if (area)
return; //not for areas
if (name.begins_with("shapes/")) { ERR_FAIL_COND(!shapes.has(p_owner));
int idx = name.get_slicec('/', 1).to_int(); ShapeData &sd = shapes[p_owner];
String what = name.get_slicec('/', 2); sd.one_way_collision = p_enable;
if (what == "shape") for (int i = 0; i < sd.shapes.size(); i++) {
r_ret = get_shape(idx); Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, p_enable);
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;
return true;
}
void CollisionObject2D::_get_property_list(List<PropertyInfo> *p_list) const {
//p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
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));
} }
} }
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, i, p_transform);
} else {
Physics2DServer::get_singleton()->body_set_shape_transform(rid, i, p_transform);
}
}
}
Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const {
ERR_FAIL_COND_V(!shapes.has(p_owner), Transform2D());
return shapes[p_owner].xform;
}
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;
}
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;
}
}
}
total_subshapes--;
}
void CollisionObject2D::shape_owner_clear_shapes(uint32_t p_owner) {
ERR_FAIL_COND(!shapes.has(p_owner));
while (shape_owner_get_shape_count(p_owner) > 0) {
shape_owner_remove_shape(p_owner, 0);
}
}
uint32_t CollisionObject2D::shape_find_owner(int p_shape_index) const {
ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0);
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) { void CollisionObject2D::set_pickable(bool p_enabled) {
if (pickable == p_enabled) if (pickable == p_enabled)
@ -216,16 +319,6 @@ void CollisionObject2D::_update_pickable() {
void CollisionObject2D::_bind_methods() { 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("get_rid"), &CollisionObject2D::get_rid);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable); ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
@ -242,100 +335,13 @@ void CollisionObject2D::_bind_methods() {
ADD_GROUP("", ""); 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) { CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
rid = p_rid; rid = p_rid;
area = p_area; area = p_area;
pickable = true; pickable = true;
set_notify_transform(true); set_notify_transform(true);
total_subshapes = 0;
if (p_area) { if (p_area) {
@ -348,6 +354,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
CollisionObject2D::CollisionObject2D() { CollisionObject2D::CollisionObject2D() {
//owner= //owner=
set_notify_transform(true); set_notify_transform(true);
} }

View File

@ -35,37 +35,40 @@
class CollisionObject2D : public Node2D { class CollisionObject2D : public Node2D {
GDCLASS(CollisionObject2D, Node2D); GDCLASS(CollisionObject2D, Node2D)
bool area; bool area;
RID rid; RID rid;
bool pickable; bool pickable;
struct ShapeData { struct ShapeData {
Object *owner;
Transform2D xform; Transform2D xform;
Ref<Shape2D> shape; struct Shape {
bool trigger; Ref<Shape2D> shape;
int index;
};
Vector<Shape> shapes;
bool disabled;
bool one_way_collision;
ShapeData() { ShapeData() {
trigger = false; disabled = false;
one_way_collision = false;
owner = NULL;
} }
}; };
Vector<ShapeData> shapes; int total_subshapes;
void _update_shapes(); Map<uint32_t, ShapeData> shapes;
friend class CollisionShape2D;
friend class CollisionPolygon2D;
void _update_shapes_from_children();
protected: protected:
CollisionObject2D(RID p_rid, bool p_area); CollisionObject2D(RID p_rid, bool p_area);
void _notification(int p_what); 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(); static void _bind_methods();
void _update_pickable(); void _update_pickable();
@ -75,16 +78,29 @@ protected:
void _mouse_exit(); void _mouse_exit();
public: public:
void add_shape(const Ref<Shape2D> &p_shape, const Transform2D &p_transform = Transform2D()); uint32_t create_shape_owner(Object *p_owner);
int get_shape_count() const; void remove_shape_owner(uint32_t owner);
void set_shape(int p_shape_idx, const Ref<Shape2D> &p_shape); void get_shape_owners(List<uint32_t> *r_owners);
void set_shape_transform(int p_shape_idx, const Transform2D &p_transform);
Ref<Shape2D> get_shape(int p_shape_idx) const; void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform);
Transform2D get_shape_transform(int p_shape_idx) const; Transform2D shape_owner_get_transform(uint32_t p_owner) const;
void set_shape_as_trigger(int p_shape_idx, bool p_trigger); Object *shape_owner_get_owner(uint32_t p_owner) const;
bool is_shape_set_as_trigger(int p_shape_idx) const;
void remove_shape(int p_shape_idx); void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled);
void clear_shapes(); 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); void set_pickable(bool p_enabled);
bool is_pickable() const; bool is_pickable() const;

View File

@ -35,13 +35,9 @@
#include "thirdparty/misc/triangulator.h" #include "thirdparty/misc/triangulator.h"
void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { void CollisionPolygon2D::_build_polygon() {
if (unparenting || !can_update_body) parent->shape_owner_clear_shapes(owner_id);
return;
CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
ERR_FAIL_COND(!co);
if (polygon.size() == 0) if (polygon.size() == 0)
return; return;
@ -53,18 +49,10 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
//here comes the sun, lalalala //here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them //decompose concave into multiple convex polygons and add them
Vector<Vector<Vector2> > decomp = _decompose_in_convex(); Vector<Vector<Vector2> > decomp = _decompose_in_convex();
shape_from = co->get_shape_count();
for (int i = 0; i < decomp.size(); i++) { for (int i = 0; i < decomp.size(); i++) {
Ref<ConvexPolygonShape2D> convex = memnew(ConvexPolygonShape2D); Ref<ConvexPolygonShape2D> convex = memnew(ConvexPolygonShape2D);
convex->set_points(decomp[i]); convex->set_points(decomp[i]);
co->add_shape(convex, get_transform()); parent->shape_owner_add_shape(owner_id, convex);
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;
} }
} else { } else {
@ -83,28 +71,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
w = PoolVector<Vector2>::Write(); w = PoolVector<Vector2>::Write();
concave->set_segments(segments); concave->set_segments(segments);
co->add_shape(concave, get_transform()); parent->shape_owner_add_shape(owner_id, concave);
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;
} }
//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() { Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
@ -155,33 +123,38 @@ Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
void CollisionPolygon2D::_notification(int p_what) { void CollisionPolygon2D::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_PARENTED: {
unparenting = false;
can_update_body = get_tree()->is_editor_hint(); parent = get_parent()->cast_to<CollisionObject2D>();
if (!get_tree()->is_editor_hint()) { 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 //display above all else
set_z_as_relative(false); set_z_as_relative(false);
set_z(VS::CANVAS_ITEM_Z_MAX - 1); set_z(VS::CANVAS_ITEM_Z_MAX - 1);
} }*/
} break; } break;
case NOTIFICATION_EXIT_TREE: {
can_update_body = false;
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (!is_inside_tree()) if (parent) {
break; parent->shape_owner_set_transform(owner_id, get_transform());
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());
}
} }
} break; } break;
case NOTIFICATION_UNPARENTED: {
if (parent) {
parent->remove_shape_owner(owner_id);
}
owner_id = 0;
parent = NULL;
} break;
case NOTIFICATION_DRAW: { case NOTIFICATION_DRAW: {
@ -210,10 +183,22 @@ void CollisionPolygon2D::_notification(int p_what) {
draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color()); draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color());
#endif #endif
} break; if (one_way_collision) {
case NOTIFICATION_UNPARENTED: { Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4);
unparenting = true; dcol.a = 1.0;
_update_parent(); 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; } break;
} }
} }
@ -222,7 +207,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {
polygon = p_polygon; polygon = p_polygon;
if (can_update_body) { {
for (int i = 0; i < polygon.size(); i++) { for (int i = 0; i < polygon.size(); i++) {
if (i == 0) if (i == 0)
aabb = Rect2(polygon[i], Size2()); 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.position -= aabb.size * 0.3;
aabb.size += aabb.size * 0.6; aabb.size += aabb.size * 0.6;
} }
_update_parent(); }
if (parent) {
_build_polygon();
} }
update(); update();
update_configuration_warning(); update_configuration_warning();
@ -251,7 +239,9 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
ERR_FAIL_INDEX(p_mode, 2); ERR_FAIL_INDEX(p_mode, 2);
build_mode = p_mode; build_mode = p_mode;
_update_parent(); if (parent) {
_build_polygon();
}
} }
CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const {
@ -264,34 +254,6 @@ Rect2 CollisionPolygon2D::get_item_rect() const {
return aabb; return aabb;
} }
void CollisionPolygon2D::set_trigger(bool p_trigger) {
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);
}
}
}
bool CollisionPolygon2D::is_trigger() const {
return trigger;
}
void CollisionPolygon2D::_set_shape_range(const Vector2 &p_range) {
shape_from = p_range.x;
shape_to = p_range.y;
}
Vector2 CollisionPolygon2D::_get_shape_range() const {
return Vector2(shape_from, shape_to);
}
String CollisionPolygon2D::get_configuration_warning() const { String CollisionPolygon2D::get_configuration_warning() const {
if (!get_parent()->cast_to<CollisionObject2D>()) { if (!get_parent()->cast_to<CollisionObject2D>()) {
@ -305,38 +267,56 @@ String CollisionPolygon2D::get_configuration_warning() const {
return String(); return String();
} }
void CollisionPolygon2D::set_disabled(bool p_disabled) {
disabled = p_disabled;
update();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
}
bool CollisionPolygon2D::is_disabled() const {
return disabled;
}
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);
}
}
bool CollisionPolygon2D::is_one_way_collision_enabled() const {
return one_way_collision;
}
void CollisionPolygon2D::_bind_methods() { 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("set_polygon", "polygon"), &CollisionPolygon2D::set_polygon);
ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon2D::get_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("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("get_build_mode"), &CollisionPolygon2D::get_build_mode);
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon2D::set_disabled);
ClassDB::bind_method(D_METHOD("set_trigger", "trigger"), &CollisionPolygon2D::set_trigger); ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon2D::is_disabled);
ClassDB::bind_method(D_METHOD("is_trigger"), &CollisionPolygon2D::is_trigger); 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);
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);
ADD_PROPERTY(PropertyInfo(Variant::INT, "build_mode", PROPERTY_HINT_ENUM, "Solids,Segments"), "set_build_mode", "get_build_mode"); 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::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_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trigger"), "set_trigger", "is_trigger"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
} }
CollisionPolygon2D::CollisionPolygon2D() { CollisionPolygon2D::CollisionPolygon2D() {
aabb = Rect2(-10, -10, 20, 20); aabb = Rect2(-10, -10, 20, 20);
build_mode = BUILD_SOLIDS; build_mode = BUILD_SOLIDS;
trigger = false;
unparenting = false;
shape_from = -1;
shape_to = -1;
can_update_body = false;
set_notify_local_transform(true); set_notify_local_transform(true);
parent = NULL;
owner_id = 0;
disabled = false;
one_way_collision = false;
} }

View File

@ -33,6 +33,8 @@
#include "scene/2d/node_2d.h" #include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h" #include "scene/resources/shape_2d.h"
class CollisionObject2D;
class CollisionPolygon2D : public Node2D { class CollisionPolygon2D : public Node2D {
GDCLASS(CollisionPolygon2D, Node2D); GDCLASS(CollisionPolygon2D, Node2D);
@ -47,29 +49,20 @@ protected:
Rect2 aabb; Rect2 aabb;
BuildMode build_mode; BuildMode build_mode;
Vector<Point2> polygon; Vector<Point2> polygon;
bool trigger; uint32_t owner_id;
bool unparenting; CollisionObject2D *parent;
bool disabled;
void _add_to_collision_object(Object *p_obj); bool one_way_collision;
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;
Vector<Vector<Vector2> > _decompose_in_convex(); Vector<Vector<Vector2> > _decompose_in_convex();
void _build_polygon();
protected: protected:
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods(); static void _bind_methods();
public: public:
void set_trigger(bool p_trigger);
bool is_trigger() const;
void set_build_mode(BuildMode p_mode); void set_build_mode(BuildMode p_mode);
BuildMode get_build_mode() const; BuildMode get_build_mode() const;
@ -78,11 +71,14 @@ public:
virtual Rect2 get_item_rect() const; 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; 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(); CollisionPolygon2D();
}; };

View File

@ -37,68 +37,48 @@
#include "scene/resources/segment_shape_2d.h" #include "scene/resources/segment_shape_2d.h"
#include "scene/resources/shape_line_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() { void CollisionShape2D::_shape_changed() {
update(); 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) { void CollisionShape2D::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_PARENTED: {
unparenting = false;
can_update_body = get_tree()->is_editor_hint(); parent = get_parent()->cast_to<CollisionObject2D>();
if (!get_tree()->is_editor_hint()) { 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 //display above all else
set_z_as_relative(false); set_z_as_relative(false);
set_z(VS::CANVAS_ITEM_Z_MAX - 1); set_z(VS::CANVAS_ITEM_Z_MAX - 1);
} }*/
} break; } break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (!is_inside_tree()) if (parent) {
break; parent->shape_owner_set_transform(owner_id, get_transform());
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());
}
} }
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_UNPARENTED: {
can_update_body = false; if (parent) {
parent->remove_shape_owner(owner_id);
}
owner_id = 0;
parent = NULL;
} break; } break;
/* /*
case NOTIFICATION_TRANSFORM_CHANGED: { case NOTIFICATION_TRANSFORM_CHANGED: {
@ -121,15 +101,33 @@ void CollisionShape2D::_notification(int p_what) {
rect = Rect2(); rect = Rect2();
Color draw_col = get_tree()->get_debug_collisions_color(); 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); shape->draw(get_canvas_item(), draw_col);
rect = shape->get_rect(); rect = shape->get_rect();
rect = rect.grow(3); rect = rect.grow(3);
} break; if (one_way_collision) {
case NOTIFICATION_UNPARENTED: { Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4);
unparenting = true; dcol.a = 1.0;
_update_parent(); 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; } break;
} }
} }
@ -140,14 +138,13 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
shape->disconnect("changed", this, "_shape_changed"); shape->disconnect("changed", this, "_shape_changed");
shape = p_shape; shape = p_shape;
update(); update();
if (is_inside_tree() && can_update_body) if (parent) {
_update_parent(); parent->shape_owner_clear_shapes(owner_id);
if (is_inside_tree() && !can_update_body && update_shape_index >= 0) { if (shape.is_valid()) {
CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); parent->shape_owner_add_shape(owner_id, shape);
if (co) {
co->set_shape(update_shape_index, p_shape);
} }
} }
if (shape.is_valid()) if (shape.is_valid())
shape->connect("changed", this, "_shape_changed"); shape->connect("changed", this, "_shape_changed");
@ -164,34 +161,6 @@ Rect2 CollisionShape2D::get_item_rect() const {
return rect; return rect;
} }
void CollisionShape2D::set_trigger(bool p_trigger) {
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);
}
}
}
bool CollisionShape2D::is_trigger() const {
return trigger;
}
void CollisionShape2D::_set_update_shape_index(int p_index) {
update_shape_index = p_index;
}
int CollisionShape2D::_get_update_shape_index() const {
return update_shape_index;
}
String CollisionShape2D::get_configuration_warning() const { String CollisionShape2D::get_configuration_warning() const {
if (!get_parent()->cast_to<CollisionObject2D>()) { if (!get_parent()->cast_to<CollisionObject2D>()) {
@ -205,31 +174,52 @@ String CollisionShape2D::get_configuration_warning() const {
return String(); return String();
} }
void CollisionShape2D::set_disabled(bool p_disabled) {
disabled = p_disabled;
update();
if (parent) {
parent->shape_owner_set_disabled(owner_id, p_disabled);
}
}
bool CollisionShape2D::is_disabled() const {
return disabled;
}
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);
}
}
bool CollisionShape2D::is_one_way_collision_enabled() const {
return one_way_collision;
}
void CollisionShape2D::_bind_methods() { void CollisionShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape2D::set_shape); 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("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("_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_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_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
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, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
} }
CollisionShape2D::CollisionShape2D() { CollisionShape2D::CollisionShape2D() {
rect = Rect2(-Point2(10, 10), Point2(20, 20)); rect = Rect2(-Point2(10, 10), Point2(20, 20));
set_notify_local_transform(true); set_notify_local_transform(true);
trigger = false; owner_id = 0;
unparenting = false; parent = NULL;
can_update_body = false; disabled = false;
update_shape_index = -1; one_way_collision = false;
} }

View File

@ -33,35 +33,33 @@
#include "scene/2d/node_2d.h" #include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h" #include "scene/resources/shape_2d.h"
class CollisionObject2D;
class CollisionShape2D : public Node2D { class CollisionShape2D : public Node2D {
GDCLASS(CollisionShape2D, Node2D); GDCLASS(CollisionShape2D, Node2D)
Ref<Shape2D> shape; Ref<Shape2D> shape;
Rect2 rect; Rect2 rect;
bool trigger; uint32_t owner_id;
bool unparenting; CollisionObject2D *parent;
bool can_update_body;
void _shape_changed(); void _shape_changed();
int update_shape_index; bool disabled;
bool one_way_collision;
void _set_update_shape_index(int p_index);
int _get_update_shape_index() const;
protected: protected:
void _update_parent();
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods(); static void _bind_methods();
void _add_to_collision_object(Object *p_obj);
public: public:
void set_shape(const Ref<Shape2D> &p_shape); void set_shape(const Ref<Shape2D> &p_shape);
Ref<Shape2D> get_shape() const; Ref<Shape2D> get_shape() const;
virtual Rect2 get_item_rect() 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; virtual String get_configuration_warning() const;

View File

@ -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) { void PhysicsBody2D::_set_layers(uint32_t p_mask) {
set_collision_layer(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("_set_layers", "mask"), &PhysicsBody2D::_set_layers);
ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody2D::_get_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("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); 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 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_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_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_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) { void PhysicsBody2D::set_collision_layer(uint32_t p_layer) {
@ -164,7 +135,6 @@ PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode)
collision_layer = 1; collision_layer = 1;
collision_mask = 1; collision_mask = 1;
set_one_way_collision_max_depth(0);
set_pickable(false); set_pickable(false);
} }

View File

@ -40,8 +40,6 @@ class PhysicsBody2D : public CollisionObject2D {
uint32_t collision_layer; uint32_t collision_layer;
uint32_t collision_mask; uint32_t collision_mask;
Vector2 one_way_collision_direction;
float one_way_collision_max_depth;
void _set_layers(uint32_t p_mask); void _set_layers(uint32_t p_mask);
uint32_t _get_layers() const; uint32_t _get_layers() const;
@ -68,12 +66,6 @@ public:
void add_collision_exception_with(Node *p_node); //must be physicsbody void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node); 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(); PhysicsBody2D();
}; };

View File

@ -32,7 +32,13 @@
bool AreaPair2DSW::setup(real_t p_step) { bool AreaPair2DSW::setup(real_t p_step) {
bool result = area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), NULL, this); bool result = false;
if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) {
result = false;
} else if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), NULL, this)) {
result = true;
}
if (result != colliding) { if (result != colliding) {
@ -90,7 +96,12 @@ AreaPair2DSW::~AreaPair2DSW() {
bool Area2Pair2DSW::setup(real_t p_step) { bool Area2Pair2DSW::setup(real_t p_step) {
bool result = area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), NULL, this); bool result = false;
if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) {
result = false;
} else if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), NULL, this)) {
result = true;
}
if (result != colliding) { if (result != colliding) {

View File

@ -676,8 +676,6 @@ Body2DSW::Body2DSW()
area_linear_damp = 0; area_linear_damp = 0;
contact_count = 0; contact_count = 0;
gravity_scale = 1.0; gravity_scale = 1.0;
using_one_way_cache = false;
one_way_collision_max_depth = 0.1;
first_integration = false; first_integration = false;
still_time = 0; still_time = 0;

View File

@ -67,9 +67,6 @@ class Body2DSW : public CollisionObject2DSW {
Vector2 applied_force; Vector2 applied_force;
real_t applied_torque; real_t applied_torque;
Vector2 one_way_collision_direction;
real_t one_way_collision_max_depth;
SelfList<Body2DSW> active_list; SelfList<Body2DSW> active_list;
SelfList<Body2DSW> inertia_update_list; SelfList<Body2DSW> inertia_update_list;
SelfList<Body2DSW> direct_state_query_list; SelfList<Body2DSW> direct_state_query_list;
@ -81,7 +78,6 @@ class Body2DSW : public CollisionObject2DSW {
bool can_sleep; bool can_sleep;
bool first_time_kinematic; bool first_time_kinematic;
bool first_integration; bool first_integration;
bool using_one_way_cache;
void _update_inertia(); void _update_inertia();
virtual void _shapes_changed(); virtual void _shapes_changed();
Transform2D new_transform; Transform2D new_transform;
@ -246,17 +242,6 @@ public:
_FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode = p_mode; } _FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode = p_mode; }
_FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; } _FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; }
void set_one_way_collision_direction(const Vector2 &p_dir) {
one_way_collision_direction = p_dir;
using_one_way_cache = one_way_collision_direction != Vector2();
}
Vector2 get_one_way_collision_direction() const { return one_way_collision_direction; }
void set_one_way_collision_max_depth(real_t p_depth) { one_way_collision_max_depth = p_depth; }
real_t get_one_way_collision_max_depth() const { return one_way_collision_max_depth; }
_FORCE_INLINE_ bool is_using_one_way_collision() const { return using_one_way_cache; }
void set_space(Space2DSW *p_space); void set_space(Space2DSW *p_space);
void update_inertias(); void update_inertias();

View File

@ -225,6 +225,11 @@ bool BodyPair2DSW::setup(real_t p_step) {
return false; return false;
} }
if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) {
collided = false;
return false;
}
//use local A coordinates to avoid numerical issues on collision detection //use local A coordinates to avoid numerical issues on collision detection
offset_B = B->get_transform().get_origin() - A->get_transform().get_origin(); offset_B = B->get_transform().get_origin() - A->get_transform().get_origin();
@ -280,8 +285,8 @@ bool BodyPair2DSW::setup(real_t p_step) {
//if (!prev_collided) { //if (!prev_collided) {
{ {
if (A->is_using_one_way_collision()) { if (A->is_shape_set_as_one_way_collision(shape_A)) {
Vector2 direction = A->get_one_way_collision_direction(); Vector2 direction = xform_A.get_axis(1).normalized();
bool valid = false; bool valid = false;
if (B->get_linear_velocity().dot(direction) >= 0) { if (B->get_linear_velocity().dot(direction) >= 0) {
for (int i = 0; i < contact_count; i++) { for (int i = 0; i < contact_count; i++) {
@ -303,8 +308,8 @@ bool BodyPair2DSW::setup(real_t p_step) {
} }
} }
if (B->is_using_one_way_collision()) { if (B->is_shape_set_as_one_way_collision(shape_B)) {
Vector2 direction = B->get_one_way_collision_direction(); Vector2 direction = xform_B.get_axis(1).normalized();
bool valid = false; bool valid = false;
if (A->get_linear_velocity().dot(direction) >= 0) { if (A->get_linear_velocity().dot(direction) >= 0) {
for (int i = 0; i < contact_count; i++) { for (int i = 0; i < contact_count; i++) {
@ -390,7 +395,7 @@ bool BodyPair2DSW::setup(real_t p_step) {
} }
} }
if (A->is_shape_set_as_trigger(shape_A) || B->is_shape_set_as_trigger(shape_B) || (A->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC)) { if ((A->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC)) {
c.active = false; c.active = false;
collided = false; collided = false;
continue; continue;

View File

@ -37,7 +37,8 @@ void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_tra
s.xform = p_transform; s.xform = p_transform;
s.xform_inv = s.xform.affine_inverse(); s.xform_inv = s.xform.affine_inverse();
s.bpid = 0; //needs update s.bpid = 0; //needs update
s.trigger = false; s.disabled = false;
s.one_way_collision = false;
shapes.push_back(s); shapes.push_back(s);
p_shape->add_owner(this); p_shape->add_owner(this);
_update_shapes(); _update_shapes();

View File

@ -58,8 +58,12 @@ private:
Rect2 aabb_cache; //for rayqueries Rect2 aabb_cache; //for rayqueries
Shape2DSW *shape; Shape2DSW *shape;
Variant metadata; Variant metadata;
bool trigger; bool disabled;
Shape() { trigger = false; } bool one_way_collision;
Shape() {
disabled = false;
one_way_collision = false;
}
}; };
Vector<Shape> shapes; Vector<Shape> shapes;
@ -116,8 +120,11 @@ public:
_FORCE_INLINE_ Transform2D get_inv_transform() const { return inv_transform; } _FORCE_INLINE_ Transform2D get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ Space2DSW *get_space() const { return space; } _FORCE_INLINE_ Space2DSW *get_space() const { return space; }
_FORCE_INLINE_ void set_shape_as_trigger(int p_idx, bool p_enable) { shapes[p_idx].trigger = p_enable; } _FORCE_INLINE_ void set_shape_as_disabled(int p_idx, bool p_disabled) { shapes[p_idx].disabled = p_disabled; }
_FORCE_INLINE_ bool is_shape_set_as_trigger(int p_idx) const { return shapes[p_idx].trigger; } _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { return shapes[p_idx].disabled; }
_FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision) { shapes[p_idx].one_way_collision = p_one_way_collision; }
_FORCE_INLINE_ bool is_shape_set_as_one_way_collision(int p_idx) const { return shapes[p_idx].one_way_collision; }
void set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; } void set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; }
_FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }

View File

@ -352,6 +352,15 @@ void Physics2DServerSW::area_set_shape_transform(RID p_area, int p_shape_idx, co
area->set_shape_transform(p_shape_idx, p_transform); area->set_shape_transform(p_shape_idx, p_transform);
} }
void Physics2DServerSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) {
Area2DSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
ERR_FAIL_INDEX(p_shape, area->get_shape_count());
area->set_shape_as_disabled(p_shape, p_disabled);
}
int Physics2DServerSW::area_get_shape_count(RID p_area) const { int Physics2DServerSW::area_get_shape_count(RID p_area) const {
Area2DSW *area = area_owner.get(p_area); Area2DSW *area = area_owner.get(p_area);
@ -640,24 +649,23 @@ void Physics2DServerSW::body_clear_shapes(RID p_body) {
body->remove_shape(0); body->remove_shape(0);
} }
void Physics2DServerSW::body_set_shape_as_trigger(RID p_body, int p_shape_idx, bool p_enable) { void Physics2DServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
Body2DSW *body = body_owner.get(p_body); Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body); ERR_FAIL_COND(!body);
ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
body->set_shape_as_trigger(p_shape_idx, p_enable); body->set_shape_as_disabled(p_shape_idx, p_disabled);
} }
void Physics2DServerSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable) {
bool Physics2DServerSW::body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) const { Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
const Body2DSW *body = body_owner.get(p_body); ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count());
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_INDEX_V(p_shape_idx, body->get_shape_count(), false); body->set_shape_as_one_way_collision(p_shape_idx, p_enable);
return body->is_shape_set_as_trigger(p_shape_idx);
} }
void Physics2DServerSW::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) { void Physics2DServerSW::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) {
@ -887,34 +895,6 @@ int Physics2DServerSW::body_get_max_contacts_reported(RID p_body) const {
return body->get_max_contacts_reported(); return body->get_max_contacts_reported();
} }
void Physics2DServerSW::body_set_one_way_collision_direction(RID p_body, const Vector2 &p_direction) {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_one_way_collision_direction(p_direction);
}
Vector2 Physics2DServerSW::body_get_one_way_collision_direction(RID p_body) const {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body, Vector2());
return body->get_one_way_collision_direction();
}
void Physics2DServerSW::body_set_one_way_collision_max_depth(RID p_body, real_t p_max_depth) {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_one_way_collision_max_depth(p_max_depth);
}
real_t Physics2DServerSW::body_get_one_way_collision_max_depth(RID p_body) const {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_one_way_collision_max_depth();
}
void Physics2DServerSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) { void Physics2DServerSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) {
Body2DSW *body = body_owner.get(p_body); Body2DSW *body = body_owner.get(p_body);

View File

@ -123,6 +123,8 @@ public:
virtual RID area_get_shape(RID p_area, int p_shape_idx) const; virtual RID area_get_shape(RID p_area, int p_shape_idx) const;
virtual Transform2D area_get_shape_transform(RID p_area, int p_shape_idx) const; virtual Transform2D area_get_shape_transform(RID p_area, int p_shape_idx) const;
virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled);
virtual void area_remove_shape(RID p_area, int p_shape_idx); virtual void area_remove_shape(RID p_area, int p_shape_idx);
virtual void area_clear_shapes(RID p_area); virtual void area_clear_shapes(RID p_area);
@ -167,8 +169,8 @@ public:
virtual void body_remove_shape(RID p_body, int p_shape_idx); virtual void body_remove_shape(RID p_body, int p_shape_idx);
virtual void body_clear_shapes(RID p_body); virtual void body_clear_shapes(RID p_body);
virtual void body_set_shape_as_trigger(RID p_body, int p_shape_idx, bool p_enable); virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled);
virtual bool body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) const; virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled);
virtual void body_attach_object_instance_ID(RID p_body, uint32_t p_ID); virtual void body_attach_object_instance_ID(RID p_body, uint32_t p_ID);
virtual uint32_t body_get_object_instance_ID(RID p_body) const; virtual uint32_t body_get_object_instance_ID(RID p_body) const;
@ -212,12 +214,6 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts); virtual void body_set_max_contacts_reported(RID p_body, int p_contacts);
virtual int body_get_max_contacts_reported(RID p_body) const; virtual int body_get_max_contacts_reported(RID p_body) const;
virtual void body_set_one_way_collision_direction(RID p_body, const Vector2 &p_direction);
virtual Vector2 body_get_one_way_collision_direction(RID p_body) const;
virtual void body_set_one_way_collision_max_depth(RID p_body, real_t p_max_depth);
virtual real_t body_get_one_way_collision_max_depth(RID p_body) const;
virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()); virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant());
virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count); virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count);

View File

@ -145,6 +145,7 @@ public:
FUNC3(area_add_shape, RID, RID, const Transform2D &); FUNC3(area_add_shape, RID, RID, const Transform2D &);
FUNC3(area_set_shape, RID, int, RID); FUNC3(area_set_shape, RID, int, RID);
FUNC3(area_set_shape_transform, RID, int, const Transform2D &); FUNC3(area_set_shape_transform, RID, int, const Transform2D &);
FUNC3(area_set_shape_disabled, RID, int, bool);
FUNC1RC(int, area_get_shape_count, RID); FUNC1RC(int, area_get_shape_count, RID);
FUNC2RC(RID, area_get_shape, RID, int); FUNC2RC(RID, area_get_shape, RID, int);
@ -191,8 +192,8 @@ public:
FUNC2RC(Variant, body_get_shape_metadata, RID, int); FUNC2RC(Variant, body_get_shape_metadata, RID, int);
FUNC2RC(RID, body_get_shape, RID, int); FUNC2RC(RID, body_get_shape, RID, int);
FUNC3(body_set_shape_as_trigger, RID, int, bool); FUNC3(body_set_shape_disabled, RID, int, bool);
FUNC2RC(bool, body_is_shape_set_as_trigger, RID, int); FUNC3(body_set_shape_as_one_way_collision, RID, int, bool);
FUNC2(body_remove_shape, RID, int); FUNC2(body_remove_shape, RID, int);
FUNC1(body_clear_shapes, RID); FUNC1(body_clear_shapes, RID);
@ -232,12 +233,6 @@ public:
FUNC2(body_set_max_contacts_reported, RID, int); FUNC2(body_set_max_contacts_reported, RID, int);
FUNC1RC(int, body_get_max_contacts_reported, RID); FUNC1RC(int, body_get_max_contacts_reported, RID);
FUNC2(body_set_one_way_collision_direction, RID, const Vector2 &);
FUNC1RC(Vector2, body_get_one_way_collision_direction, RID);
FUNC2(body_set_one_way_collision_max_depth, RID, real_t);
FUNC1RC(real_t, body_get_one_way_collision_max_depth, RID);
FUNC2(body_set_contacts_reported_depth_treshold, RID, real_t); FUNC2(body_set_contacts_reported_depth_treshold, RID, real_t);
FUNC1RC(real_t, body_get_contacts_reported_depth_treshold, RID); FUNC1RC(real_t, body_get_contacts_reported_depth_treshold, RID);

View File

@ -265,14 +265,6 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor
//test initial overlap //test initial overlap
if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, NULL, p_margin)) { if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, NULL, p_margin)) {
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
//if one way collision direction ignore initial overlap
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj);
if (body->get_one_way_collision_direction() != Vector2()) {
continue;
}
}
return false; return false;
} }
@ -297,27 +289,6 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor
} }
} }
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj);
if (body->get_one_way_collision_direction() != Vector2()) {
Vector2 cd[2];
Physics2DServerSW::CollCbkData cbk;
cbk.max = 1;
cbk.amount = 0;
cbk.ptr = cd;
cbk.valid_dir = body->get_one_way_collision_direction();
cbk.valid_depth = body->get_one_way_collision_max_depth();
Vector2 sep = mnormal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(shape, p_xform, p_motion * (hi + space->contact_max_allowed_penetration), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, p_margin);
if (!collided || cbk.amount == 0) {
continue;
}
}
}
if (low < best_safe) { if (low < best_safe) {
best_safe = low; best_safe = low;
best_unsafe = hi; best_unsafe = hi;
@ -369,15 +340,9 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &
if (p_exclude.has(col_obj->get_self())) if (p_exclude.has(col_obj->get_self()))
continue; continue;
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); cbk.valid_dir = Vector2();
cbk.valid_dir = body->get_one_way_collision_direction(); cbk.valid_depth = 0;
cbk.valid_depth = body->get_one_way_collision_max_depth();
} else {
cbk.valid_dir = Vector2();
cbk.valid_depth = 0;
}
if (CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) { if (CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) {
collided = p_result_max == 0 || cbk.amount > 0; collided = p_result_max == 0 || cbk.amount > 0;
@ -407,13 +372,10 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B,
_RestCallbackData2D *rd = (_RestCallbackData2D *)p_userdata; _RestCallbackData2D *rd = (_RestCallbackData2D *)p_userdata;
if (rd->valid_dir != Vector2()) { if (rd->valid_dir != Vector2()) {
if (p_point_A.distance_squared_to(p_point_B) > rd->valid_depth * rd->valid_depth)
if (rd->valid_dir != Vector2()) { return;
if (p_point_A.distance_squared_to(p_point_B) > rd->valid_depth * rd->valid_depth) if (rd->valid_dir.dot((p_point_A - p_point_B).normalized()) < Math_PI * 0.25)
return; return;
if (rd->valid_dir.dot((p_point_A - p_point_B).normalized()) < Math_PI * 0.25)
return;
}
} }
Vector2 contact_rel = p_point_B - p_point_A; Vector2 contact_rel = p_point_B - p_point_A;
@ -455,16 +417,8 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh
if (p_exclude.has(col_obj->get_self())) if (p_exclude.has(col_obj->get_self()))
continue; continue;
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { rcd.valid_dir = Vector2();
rcd.valid_depth = 0;
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj);
rcd.valid_dir = body->get_one_way_collision_direction();
rcd.valid_depth = body->get_one_way_collision_max_depth();
} else {
rcd.valid_dir = Vector2();
rcd.valid_depth = 0;
}
rcd.object = col_obj; rcd.object = col_obj;
rcd.shape = shape_idx; rcd.shape = shape_idx;
bool sc = CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin); bool sc = CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin);
@ -517,7 +471,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) {
keep = false; keep = false;
else if (static_cast<Body2DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) else if (static_cast<Body2DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self()))
keep = false; keep = false;
else if (static_cast<Body2DSW *>(intersection_query_results[i])->is_shape_set_as_trigger(intersection_query_subindex_results[i])) else if (static_cast<Body2DSW *>(intersection_query_results[i])->is_shape_set_as_disabled(intersection_query_subindex_results[i]))
keep = false; keep = false;
if (!keep) { if (!keep) {
@ -589,7 +543,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
int amount = _cull_aabb_for_body(p_body, body_aabb); int amount = _cull_aabb_for_body(p_body, body_aabb);
for (int j = 0; j < p_body->get_shape_count(); j++) { for (int j = 0; j < p_body->get_shape_count(); j++) {
if (p_body->is_shape_set_as_trigger(j)) if (p_body->is_shape_set_as_disabled(j))
continue; continue;
Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j); Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
@ -599,18 +553,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
const CollisionObject2DSW *col_obj = intersection_query_results[i]; const CollisionObject2DSW *col_obj = intersection_query_results[i];
int shape_idx = intersection_query_subindex_results[i]; int shape_idx = intersection_query_subindex_results[i];
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { if (col_obj->is_shape_set_as_one_way_collision(j)) {
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
cbk.valid_depth = p_margin; //only valid depth is the collision margin
Vector2 cdir = body->get_one_way_collision_direction();
/*
if (cdir!=Vector2() && p_motion.dot(cdir)<0)
continue;
*/
cbk.valid_dir = cdir;
cbk.valid_depth = body->get_one_way_collision_max_depth();
} else { } else {
cbk.valid_dir = Vector2(); cbk.valid_dir = Vector2();
cbk.valid_depth = 0; cbk.valid_depth = 0;
@ -678,7 +624,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
for (int j = 0; j < p_body->get_shape_count(); j++) { for (int j = 0; j < p_body->get_shape_count(); j++) {
if (p_body->is_shape_set_as_trigger(j)) if (p_body->is_shape_set_as_disabled(j))
continue; continue;
Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j); Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
@ -703,12 +649,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//test initial overlap //test initial overlap
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) { if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) {
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { if (col_obj->is_shape_set_as_one_way_collision(j)) {
//if one way collision direction ignore initial overlap continue;
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj);
if (body->get_one_way_collision_direction() != Vector2()) {
continue;
}
} }
stuck = true; stuck = true;
@ -720,7 +662,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
real_t hi = 1; real_t hi = 1;
Vector2 mnormal = p_motion.normalized(); Vector2 mnormal = p_motion.normalized();
for (int i = 0; i < 8; i++) { //steps should be customizable.. for (int k = 0; k < 8; k++) { //steps should be customizable..
real_t ofs = (low + hi) * 0.5; real_t ofs = (low + hi) * 0.5;
@ -739,15 +681,16 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); const Body2DSW *body = static_cast<const Body2DSW *>(col_obj);
if (body->get_one_way_collision_direction() != Vector2()) { if (col_obj->is_shape_set_as_one_way_collision(j)) {
Vector2 cd[2]; Vector2 cd[2];
Physics2DServerSW::CollCbkData cbk; Physics2DServerSW::CollCbkData cbk;
cbk.max = 1; cbk.max = 1;
cbk.amount = 0; cbk.amount = 0;
cbk.ptr = cd; cbk.ptr = cd;
cbk.valid_dir = body->get_one_way_collision_direction(); cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
cbk.valid_depth = body->get_one_way_collision_max_depth(); ;
cbk.valid_depth = 10e20;
Vector2 sep = mnormal; //important optimization for this to work fast enough Vector2 sep = mnormal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0); bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0);
@ -816,11 +759,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
const CollisionObject2DSW *col_obj = intersection_query_results[i]; const CollisionObject2DSW *col_obj = intersection_query_results[i];
int shape_idx = intersection_query_subindex_results[i]; int shape_idx = intersection_query_subindex_results[i];
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) {
const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); rcd.valid_dir = body_shape_xform.get_axis(1).normalized();
rcd.valid_dir = body->get_one_way_collision_direction(); rcd.valid_depth = 10e20;
rcd.valid_depth = body->get_one_way_collision_max_depth();
} else { } else {
rcd.valid_dir = Vector2(); rcd.valid_dir = Vector2();
rcd.valid_depth = 0; rcd.valid_depth = 0;

View File

@ -496,6 +496,7 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform"), &Physics2DServer::area_add_shape, DEFVAL(Transform2D())); ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform"), &Physics2DServer::area_add_shape, DEFVAL(Transform2D()));
ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &Physics2DServer::area_set_shape); ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &Physics2DServer::area_set_shape);
ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &Physics2DServer::area_set_shape_transform); ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &Physics2DServer::area_set_shape_transform);
ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disable"), &Physics2DServer::area_set_shape_disabled);
ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &Physics2DServer::area_get_shape_count); ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &Physics2DServer::area_get_shape_count);
ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &Physics2DServer::area_get_shape); ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &Physics2DServer::area_get_shape);
@ -539,8 +540,8 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &Physics2DServer::body_remove_shape); ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &Physics2DServer::body_remove_shape);
ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &Physics2DServer::body_clear_shapes); ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &Physics2DServer::body_clear_shapes);
ClassDB::bind_method(D_METHOD("body_set_shape_as_trigger", "body", "shape_idx", "enable"), &Physics2DServer::body_set_shape_as_trigger); ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disable"), &Physics2DServer::body_set_shape_disabled);
ClassDB::bind_method(D_METHOD("body_is_shape_set_as_trigger", "body", "shape_idx"), &Physics2DServer::body_is_shape_set_as_trigger); ClassDB::bind_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable"), &Physics2DServer::body_set_shape_as_one_way_collision);
ClassDB::bind_method(D_METHOD("body_attach_object_instance_ID", "body", "id"), &Physics2DServer::body_attach_object_instance_ID); ClassDB::bind_method(D_METHOD("body_attach_object_instance_ID", "body", "id"), &Physics2DServer::body_attach_object_instance_ID);
ClassDB::bind_method(D_METHOD("body_get_object_instance_ID", "body"), &Physics2DServer::body_get_object_instance_ID); ClassDB::bind_method(D_METHOD("body_get_object_instance_ID", "body"), &Physics2DServer::body_get_object_instance_ID);
@ -571,12 +572,6 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_max_contacts_reported", "body", "amount"), &Physics2DServer::body_set_max_contacts_reported); ClassDB::bind_method(D_METHOD("body_set_max_contacts_reported", "body", "amount"), &Physics2DServer::body_set_max_contacts_reported);
ClassDB::bind_method(D_METHOD("body_get_max_contacts_reported", "body"), &Physics2DServer::body_get_max_contacts_reported); ClassDB::bind_method(D_METHOD("body_get_max_contacts_reported", "body"), &Physics2DServer::body_get_max_contacts_reported);
ClassDB::bind_method(D_METHOD("body_set_one_way_collision_direction", "body", "normal"), &Physics2DServer::body_set_one_way_collision_direction);
ClassDB::bind_method(D_METHOD("body_get_one_way_collision_direction", "body"), &Physics2DServer::body_get_one_way_collision_direction);
ClassDB::bind_method(D_METHOD("body_set_one_way_collision_max_depth", "body", "depth"), &Physics2DServer::body_set_one_way_collision_max_depth);
ClassDB::bind_method(D_METHOD("body_get_one_way_collision_max_depth", "body"), &Physics2DServer::body_get_one_way_collision_max_depth);
ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &Physics2DServer::body_set_omit_force_integration); ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &Physics2DServer::body_set_omit_force_integration);
ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &Physics2DServer::body_is_omitting_force_integration); ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &Physics2DServer::body_is_omitting_force_integration);

View File

@ -332,6 +332,8 @@ public:
virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0; virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0;
virtual void area_clear_shapes(RID p_area) = 0; virtual void area_clear_shapes(RID p_area) = 0;
virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) = 0;
virtual void area_attach_object_instance_ID(RID p_area, ObjectID p_ID) = 0; virtual void area_attach_object_instance_ID(RID p_area, ObjectID p_ID) = 0;
virtual ObjectID area_get_object_instance_ID(RID p_area) const = 0; virtual ObjectID area_get_object_instance_ID(RID p_area) const = 0;
@ -380,8 +382,8 @@ public:
virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0; virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0;
virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const = 0; virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const = 0;
virtual void body_set_shape_as_trigger(RID p_body, int p_shape_idx, bool p_enable) = 0; virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) = 0;
virtual bool body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) const = 0; virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled) = 0;
virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0; virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0;
virtual void body_clear_shapes(RID p_body) = 0; virtual void body_clear_shapes(RID p_body) = 0;
@ -451,12 +453,6 @@ public:
virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) = 0; virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) = 0;
virtual int body_get_max_contacts_reported(RID p_body) const = 0; virtual int body_get_max_contacts_reported(RID p_body) const = 0;
virtual void body_set_one_way_collision_direction(RID p_body, const Vector2 &p_direction) = 0;
virtual Vector2 body_get_one_way_collision_direction(RID p_body) const = 0;
virtual void body_set_one_way_collision_max_depth(RID p_body, float p_max_depth) = 0;
virtual float body_get_one_way_collision_max_depth(RID p_body) const = 0;
//missing remove //missing remove
virtual void body_set_contacts_reported_depth_treshold(RID p_body, float p_treshold) = 0; virtual void body_set_contacts_reported_depth_treshold(RID p_body, float p_treshold) = 0;
virtual float body_get_contacts_reported_depth_treshold(RID p_body) const = 0; virtual float body_get_contacts_reported_depth_treshold(RID p_body) const = 0;