-Add support for one-way collision in 2D (only works for kinematic body so far)
-Solve drawing order bug introduced in previous commit: solves #1214
This commit is contained in:
parent
a327eee762
commit
9012cd408e
14 changed files with 827 additions and 43 deletions
Binary file not shown.
|
@ -15,6 +15,7 @@ const GRAVITY = 500.0
|
|||
#consider "floor".
|
||||
const FLOOR_ANGLE_TOLERANCE = 40
|
||||
const WALK_FORCE = 600
|
||||
const WALK_MIN_SPEED=10
|
||||
const WALK_MAX_SPEED = 200
|
||||
const STOP_FORCE = 1300
|
||||
const JUMP_SPEED = 200
|
||||
|
@ -40,12 +41,12 @@ func _fixed_process(delta):
|
|||
var stop=true
|
||||
|
||||
if (walk_left):
|
||||
if (velocity.x<=0 and velocity.x > -WALK_MAX_SPEED):
|
||||
if (velocity.x<=WALK_MIN_SPEED and velocity.x > -WALK_MAX_SPEED):
|
||||
force.x-=WALK_FORCE
|
||||
stop=false
|
||||
|
||||
elif (walk_right):
|
||||
if (velocity.x>=0 and velocity.x < WALK_MAX_SPEED):
|
||||
if (velocity.x>=-WALK_MIN_SPEED and velocity.x < WALK_MAX_SPEED):
|
||||
force.x+=WALK_FORCE
|
||||
stop=false
|
||||
|
||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -55,16 +55,32 @@ Vector2 PhysicsBody2D::get_one_way_collision_direction() const{
|
|||
}
|
||||
|
||||
|
||||
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::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody2D::set_layer_mask);
|
||||
ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody2D::get_layer_mask);
|
||||
ObjectTypeDB::bind_method(_MD("set_one_way_collision_direction","dir"),&PhysicsBody2D::set_one_way_collision_direction);
|
||||
ObjectTypeDB::bind_method(_MD("get_one_way_collision_direction"),&PhysicsBody2D::get_one_way_collision_direction);
|
||||
ObjectTypeDB::bind_method(_MD("set_one_way_collision_max_depth","depth"),&PhysicsBody2D::set_one_way_collision_max_depth);
|
||||
ObjectTypeDB::bind_method(_MD("get_one_way_collision_max_depth"),&PhysicsBody2D::get_one_way_collision_max_depth);
|
||||
ObjectTypeDB::bind_method(_MD("add_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::add_collision_exception_with);
|
||||
ObjectTypeDB::bind_method(_MD("remove_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::remove_collision_exception_with);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"one_way_collision/direction"),_SCS("set_one_way_collision_direction"),_SCS("get_one_way_collision_direction"));
|
||||
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"one_way_collision/direction"),_SCS("set_one_way_collision_direction"),_SCS("get_one_way_collision_direction"));
|
||||
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"one_way_collision/max_depth"),_SCS("set_one_way_collision_max_depth"),_SCS("get_one_way_collision_max_depth"));
|
||||
}
|
||||
|
||||
void PhysicsBody2D::set_layer_mask(uint32_t p_mask) {
|
||||
|
@ -81,6 +97,7 @@ uint32_t PhysicsBody2D::get_layer_mask() const {
|
|||
PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D( Physics2DServer::get_singleton()->body_create(p_mode), false) {
|
||||
|
||||
mask=1;
|
||||
set_one_way_collision_max_depth(0);
|
||||
|
||||
}
|
||||
|
||||
|
@ -947,7 +964,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
|
|||
|
||||
//if (d<margin)
|
||||
/// continue;
|
||||
recover_motion+=(b-a)*0.2;
|
||||
recover_motion+=(b-a)*0.4;
|
||||
}
|
||||
|
||||
if (recover_motion==Vector2()) {
|
||||
|
@ -978,6 +995,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
|
|||
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
|
||||
|
@ -1009,9 +1027,11 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) {
|
|||
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;
|
||||
|
|
|
@ -40,6 +40,7 @@ class PhysicsBody2D : public CollisionObject2D {
|
|||
|
||||
uint32_t mask;
|
||||
Vector2 one_way_collision_direction;
|
||||
float one_way_collision_max_depth;
|
||||
protected:
|
||||
|
||||
void _notification(int p_what);
|
||||
|
@ -57,6 +58,9 @@ public:
|
|||
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();
|
||||
|
||||
};
|
||||
|
|
|
@ -647,6 +647,7 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti
|
|||
area_linear_damp=0;
|
||||
contact_count=0;
|
||||
gravity_scale=1.0;
|
||||
one_way_collision_max_depth=0.1;
|
||||
|
||||
still_time=0;
|
||||
continuous_cd_mode=Physics2DServer::CCD_MODE_DISABLED;
|
||||
|
|
|
@ -68,6 +68,7 @@ class Body2DSW : public CollisionObject2DSW {
|
|||
real_t applied_torque;
|
||||
|
||||
Vector2 one_way_collision_direction;
|
||||
float one_way_collision_max_depth;
|
||||
|
||||
|
||||
SelfList<Body2DSW> active_list;
|
||||
|
@ -221,6 +222,9 @@ public:
|
|||
void set_one_way_collision_direction(const Vector2& p_dir) { one_way_collision_direction=p_dir; }
|
||||
Vector2 get_one_way_collision_direction() const { return one_way_collision_direction; }
|
||||
|
||||
void set_one_way_collision_max_depth(float p_depth) { one_way_collision_max_depth=p_depth; }
|
||||
float get_one_way_collision_max_depth() const { return one_way_collision_max_depth; }
|
||||
|
||||
void set_space(Space2DSW *p_space);
|
||||
|
||||
void update_inertias();
|
||||
|
|
|
@ -138,6 +138,21 @@ void Physics2DServerSW::_shape_col_cbk(const Vector2& p_point_A,const Vector2& p
|
|||
if (cbk->max==0)
|
||||
return;
|
||||
|
||||
if (cbk->valid_dir!=Vector2()) {
|
||||
if (p_point_A.distance_squared_to(p_point_B)>cbk->valid_depth*cbk->valid_depth) {
|
||||
return;
|
||||
}
|
||||
if (cbk->valid_dir.dot((p_point_A-p_point_B).normalized())<0.7071) {
|
||||
/* print_line("A: "+p_point_A);
|
||||
print_line("B: "+p_point_B);
|
||||
print_line("discard too angled "+rtos(cbk->valid_dir.dot((p_point_A-p_point_B))));
|
||||
print_line("resnorm: "+(p_point_A-p_point_B).normalized());
|
||||
print_line("distance: "+rtos(p_point_A.distance_to(p_point_B)));
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cbk->amount == cbk->max) {
|
||||
//find least deep
|
||||
float min_depth=1e20;
|
||||
|
@ -875,6 +890,21 @@ Vector2 Physics2DServerSW::body_get_one_way_collision_direction(RID p_body) cons
|
|||
|
||||
}
|
||||
|
||||
void Physics2DServerSW::body_set_one_way_collision_max_depth(RID p_body,float p_max_depth) {
|
||||
|
||||
Body2DSW *body = body_owner.get(p_body);
|
||||
ERR_FAIL_COND(!body);
|
||||
body->set_one_way_collision_max_depth(p_max_depth);
|
||||
|
||||
}
|
||||
|
||||
float 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) {
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ public:
|
|||
|
||||
struct CollCbkData {
|
||||
|
||||
Vector2 valid_dir;
|
||||
float valid_depth;
|
||||
int max;
|
||||
int amount;
|
||||
Vector2 *ptr;
|
||||
|
@ -208,6 +210,10 @@ public:
|
|||
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,float p_max_depth);
|
||||
virtual float 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 bool body_collide_shape(RID p_body, int p_body_shape,RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,Vector2 *r_results,int p_result_max,int &r_result_count);
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ bool Physics2DDirectSpaceStateSW::intersect_ray(const Vector2& p_from, const Vec
|
|||
if (shape->intersect_segment(local_from,local_to,shape_point,shape_normal)) {
|
||||
|
||||
|
||||
//print_line("inters sgment!");
|
||||
|
||||
Matrix32 xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
|
||||
shape_point=xform.xform(shape_point);
|
||||
|
||||
|
@ -217,6 +217,16 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32
|
|||
int shape_idx=space->intersection_query_subindex_results[i];
|
||||
|
||||
|
||||
/*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() && p_motion.dot(body->get_one_way_collision_direction())<=CMP_EPSILON) {
|
||||
print_line("failed in motion dir");
|
||||
continue;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
Matrix32 col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
|
||||
//test initial overlap, does it collide if going all the way?
|
||||
if (!CollisionSolver2DSW::solve(shape,p_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,p_margin)) {
|
||||
|
@ -227,6 +237,14 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32
|
|||
//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 (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;
|
||||
}
|
||||
|
||||
|
@ -253,6 +271,29 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
best_safe=low;
|
||||
best_unsafe=hi;
|
||||
|
@ -311,14 +352,23 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Matrix32& p_s
|
|||
|
||||
if (p_exclude.has( col_obj->get_self() ))
|
||||
continue;
|
||||
if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
|
||||
|
||||
const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
|
||||
cbk.valid_dir=body->get_one_way_collision_direction();
|
||||
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)) {
|
||||
collided=true;
|
||||
collided=p_result_max==0 || cbk.amount>0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
r_result_count=cbk.amount;
|
||||
|
||||
return collided;
|
||||
|
@ -334,6 +384,8 @@ struct _RestCallbackData2D {
|
|||
Vector2 best_contact;
|
||||
Vector2 best_normal;
|
||||
float best_len;
|
||||
Vector2 valid_dir;
|
||||
float valid_depth;
|
||||
};
|
||||
|
||||
static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,void *p_userdata) {
|
||||
|
@ -341,11 +393,23 @@ static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,v
|
|||
|
||||
_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)
|
||||
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;
|
||||
float len = contact_rel.length();
|
||||
if (len <= rd->best_len)
|
||||
return;
|
||||
|
||||
|
||||
rd->best_len=len;
|
||||
rd->best_contact=p_point_B;
|
||||
rd->best_normal=contact_rel/len;
|
||||
|
@ -385,6 +449,17 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape
|
|||
if (p_exclude.has( col_obj->get_self() ))
|
||||
continue;
|
||||
|
||||
if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
|
||||
|
||||
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.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);
|
||||
|
|
|
@ -503,6 +503,9 @@ void Physics2DServer::_bind_methods() {
|
|||
ObjectTypeDB::bind_method(_MD("body_set_one_way_collision_direction","normal"),&Physics2DServer::body_set_one_way_collision_direction);
|
||||
ObjectTypeDB::bind_method(_MD("body_get_one_way_collision_direction"),&Physics2DServer::body_get_one_way_collision_direction);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("body_set_one_way_collision_max_depth","normal"),&Physics2DServer::body_set_one_way_collision_max_depth);
|
||||
ObjectTypeDB::bind_method(_MD("body_get_one_way_collision_max_depth"),&Physics2DServer::body_get_one_way_collision_max_depth);
|
||||
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("body_set_omit_force_integration","body","enable"),&Physics2DServer::body_set_omit_force_integration);
|
||||
ObjectTypeDB::bind_method(_MD("body_is_omitting_force_integration","body"),&Physics2DServer::body_is_omitting_force_integration);
|
||||
|
|
|
@ -445,6 +445,9 @@ public:
|
|||
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
|
||||
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;
|
||||
|
|
|
@ -392,7 +392,7 @@ class VisualServerRaster : public VisualServer {
|
|||
|
||||
CanvasItem() {
|
||||
E=NULL;
|
||||
z=CANVAS_ITEM_Z_MAX/2;
|
||||
z=0;
|
||||
opacity=1;
|
||||
self_opacity=1;
|
||||
sort_y=false;
|
||||
|
|
Loading…
Reference in a new issue