void VisibilityNotifier2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { //get_world_2d()-> get_world_2d()->_register_notifier(this,get_global_transform().xform(rect)); } break; case NOTIFICATION_TRANSFORM_CHANGED: { //get_world_2d()-> get_world_2d()->_update_notifier(this,get_global_transform().xform(rect)); } break; case NOTIFICATION_DRAW: { if (get_tree()->is_editor_hint()) { draw_rect(rect,Color(1,0.5,1,0.2)); } } break; case NOTIFICATION_EXIT_TREE: { get_world_2d()->_remove_notifier(this); } break; } }
void SoundPlayer2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { //find the sound space source_rid = SpatialSound2DServer::get_singleton()->source_create(get_world_2d()->get_sound_space()); for(int i=0;i<PARAM_MAX;i++) set_param(Param(i),params[i]); SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform()); } break; case NOTIFICATION_TRANSFORM_CHANGED: { SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform()); } break; case NOTIFICATION_EXIT_TREE: { if (source_rid.is_valid()) SpatialSound2DServer::get_singleton()->free(source_rid); } break; } }
void RayCast2D::_update_raycast_state() { Ref<World2D> w2d = get_world_2d(); ERR_FAIL_COND(w2d.is_null()); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(w2d->get_space()); ERR_FAIL_COND(!dss); Transform2D gt = get_global_transform(); Vector2 to = cast_to; if (to == Vector2()) to = Vector2(0, 0.01); Physics2DDirectSpaceState::RayResult rr; if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_layer, type_mask)) { collided = true; against = rr.collider_id; collision_point = rr.position; collision_normal = rr.normal; against_shape = rr.shape; } else { collided = false; } }
void TileMap::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_SCENE: { pending_update=true; _update_dirty_quadrants(); RID space = get_world_2d()->get_space(); _update_quadrant_transform(); _update_quadrant_space(space); } break; case NOTIFICATION_EXIT_SCENE: { _update_quadrant_space(RID()); } break; case NOTIFICATION_TRANSFORM_CHANGED: { //move stuff _update_quadrant_transform(); } break; } }
Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey& p_qk) { Matrix32 xform; //xform.set_origin(Point2(p_qk.x,p_qk.y)*cell_size*quadrant_size); Quadrant q; q.pos = _map_to_world(p_qk.x*_get_quadrant_size(),p_qk.y*_get_quadrant_size()); q.pos+=get_cell_draw_offset(); if (tile_origin==TILE_ORIGIN_CENTER) q.pos+=cell_size/2; else if (tile_origin==TILE_ORIGIN_BOTTOM_LEFT) q.pos.y+=cell_size.y; xform.set_origin( q.pos ); // q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); q.body=Physics2DServer::get_singleton()->body_create(use_kinematic?Physics2DServer::BODY_MODE_KINEMATIC:Physics2DServer::BODY_MODE_STATIC); Physics2DServer::get_singleton()->body_attach_object_instance_ID(q.body,get_instance_ID()); Physics2DServer::get_singleton()->body_set_layer_mask(q.body,collision_layer); Physics2DServer::get_singleton()->body_set_collision_mask(q.body,collision_mask); Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_FRICTION,friction); Physics2DServer::get_singleton()->body_set_param(q.body,Physics2DServer::BODY_PARAM_BOUNCE,bounce); if (is_inside_tree()) { xform = get_global_transform() * xform; RID space = get_world_2d()->get_space(); Physics2DServer::get_singleton()->body_set_space(q.body,space); } Physics2DServer::get_singleton()->body_set_state(q.body,Physics2DServer::BODY_STATE_TRANSFORM,xform); rect_cache_dirty=true; quadrant_order_dirty=true; return quadrant_map.insert(p_qk,q); }
void VisibilityNotifier2D::set_rect(const Rect2& p_rect){ rect=p_rect; if (is_inside_tree()) get_world_2d()->_update_notifier(this,get_global_transform().xform(rect)); _change_notify("rect"); }
void TileMap::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { Node2D *c=this; while(c) { navigation=c->cast_to<Navigation2D>(); if (navigation) { break; } c=c->get_parent()->cast_to<Node2D>(); } pending_update=true; _update_dirty_quadrants(); RID space = get_world_2d()->get_space(); _update_quadrant_transform(); _update_quadrant_space(space); } break; case NOTIFICATION_EXIT_TREE: { _update_quadrant_space(RID()); for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { Quadrant &q=E->get(); if (navigation) { for(Map<PosKey,Quadrant::NavPoly>::Element *E=q.navpoly_ids.front();E;E=E->next()) { navigation->navpoly_remove(E->get().id); } q.navpoly_ids.clear(); } for(Map<PosKey,Quadrant::Occluder>::Element *E=q.occluder_instances.front();E;E=E->next()) { VS::get_singleton()->free(E->get().id); } q.occluder_instances.clear(); } navigation=NULL; } break; case NOTIFICATION_TRANSFORM_CHANGED: { //move stuff _update_quadrant_transform(); } break; } }
void CollisionObject2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { Transform2D global_transform = get_global_transform(); if (area) Physics2DServer::get_singleton()->area_set_transform(rid, global_transform); else Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, global_transform); last_transform = global_transform; RID space = get_world_2d()->get_space(); if (area) { Physics2DServer::get_singleton()->area_set_space(rid, space); } else Physics2DServer::get_singleton()->body_set_space(rid, space); _update_pickable(); //get space } case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); } break; case NOTIFICATION_TRANSFORM_CHANGED: { Transform2D global_transform = get_global_transform(); if (only_update_transform_changes && global_transform == last_transform) { return; } if (area) Physics2DServer::get_singleton()->area_set_transform(rid, global_transform); else Physics2DServer::get_singleton()->body_set_state(rid, Physics2DServer::BODY_STATE_TRANSFORM, global_transform); last_transform = global_transform; } break; case NOTIFICATION_EXIT_TREE: { if (area) { Physics2DServer::get_singleton()->area_set_space(rid, RID()); } else Physics2DServer::get_singleton()->body_set_space(rid, RID()); } break; } }
void VisibilityNotifier2D::set_rect(const Rect2& p_rect){ rect=p_rect; if (is_inside_tree()) { get_world_2d()->_update_notifier(this,get_global_transform().xform(rect)); if (get_tree()->is_editor_hint()) { update(); item_rect_changed(); } } _change_notify("rect"); }
Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey& p_qk) { Matrix32 xform; xform.set_origin(Point2(p_qk.x,p_qk.y)*quadrant_size*cell_size); Quadrant q; q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); VisualServer::get_singleton()->canvas_item_set_parent( q.canvas_item, get_canvas_item() ); VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform ); q.static_body=Physics2DServer::get_singleton()->body_create(Physics2DServer::BODY_MODE_STATIC); if (is_inside_scene()) { xform = get_global_transform() * xform; RID space = get_world_2d()->get_space(); Physics2DServer::get_singleton()->body_set_space(q.static_body,space); } Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform); q.pos=Vector2(p_qk.x,p_qk.y)*quadrant_size*cell_size; rect_cache_dirty=true; return quadrant_map.insert(p_qk,q); }
void CollisionObject2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { if (area) Physics2DServer::get_singleton()->area_set_transform(rid,get_global_transform()); else Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform()); RID space = get_world_2d()->get_space(); if (area) { Physics2DServer::get_singleton()->area_set_space(rid,space); } else Physics2DServer::get_singleton()->body_set_space(rid,space); //get space } case NOTIFICATION_TRANSFORM_CHANGED: { if (area) Physics2DServer::get_singleton()->area_set_transform(rid,get_global_transform()); else Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform()); } break; case NOTIFICATION_EXIT_TREE: { if (area) { Physics2DServer::get_singleton()->area_set_space(rid,RID()); } else Physics2DServer::get_singleton()->body_set_space(rid,RID()); } break; } }
void RayCast2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { if (enabled && !get_tree()->is_editor_hint()) set_fixed_process(true); else set_fixed_process(false); } break; case NOTIFICATION_EXIT_TREE: { if (enabled) set_fixed_process(false); } break; #ifdef TOOLS_ENABLED case NOTIFICATION_DRAW: { if (!get_tree()->is_editor_hint()) break; Matrix32 xf; xf.rotate(cast_to.atan2()); xf.translate(Vector2(0,cast_to.length())); //Vector2 tip = Vector2(0,s->get_length()); Color dcol(0.9,0.2,0.2,0.4); draw_line(Vector2(),cast_to,dcol,3); Vector<Vector2> pts; float tsize=4; pts.push_back(xf.xform(Vector2(0,tsize))); pts.push_back(xf.xform(Vector2(0.707*tsize,0))); pts.push_back(xf.xform(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; #endif case NOTIFICATION_FIXED_PROCESS: { if (!enabled) break; Ref<World2D> w2d = get_world_2d(); ERR_BREAK( w2d.is_null() ); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(w2d->get_space()); ERR_BREAK( !dss ); Matrix32 gt = get_global_transform(); Vector2 to = cast_to; if (to==Vector2()) to=Vector2(0,0.01); Physics2DDirectSpaceState::RayResult rr; if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude,layer_mask)) { collided=true; against=rr.collider_id; collision_point=rr.position; collision_normal=rr.normal; against_shape=rr.shape; } else { collided=false; } } break; } }
bool KinematicBody2D::can_move_to(const Vector2& p_position, bool p_discrete) { ERR_FAIL_COND_V(!is_inside_scene(),false); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); ERR_FAIL_COND_V(!dss,false); uint32_t mask=0; if (collide_static) mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; if (collide_kinematic) mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; if (collide_rigid) mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; if (collide_character) mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; Vector2 motion = p_position-get_global_pos(); Matrix32 xform=get_global_transform(); if (p_discrete) { xform.elements[2]+=motion; motion=Vector2(); } Set<RID> exclude; exclude.insert(get_rid()); //fill exclude list.. for(int i=0;i<get_shape_count();i++) { bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),motion,0,NULL,0,exclude,0,mask); if (col) return false; } return true; }
Vector2 KinematicBody2D::move(const Vector2& p_motion) { //give me back regular physics engine logic //this is madness //and most people using this function will think //what it does is simpler than using physics //this took about a week to get right.. //but is it right? who knows at this point.. colliding=false; ERR_FAIL_COND_V(!is_inside_scene(),Vector2()); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); ERR_FAIL_COND_V(!dss,Vector2()); const int max_shapes=32; Vector2 sr[max_shapes*2]; int res_shapes; Set<RID> exclude; exclude.insert(get_rid()); //recover first int recover_attempts=4; bool collided=false; uint32_t mask=0; if (collide_static) mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; if (collide_kinematic) mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; if (collide_rigid) mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; if (collide_character) mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; // print_line("motion: "+p_motion+" margin: "+rtos(margin)); //print_line("margin: "+rtos(margin)); do { //fill exclude list.. for(int i=0;i<get_shape_count();i++) { if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,0,mask)) collided=true; } if (!collided) break; Vector2 recover_motion; for(int i=0;i<res_shapes;i++) { Vector2 a = sr[i*2+0]; Vector2 b = sr[i*2+1]; float d = a.distance_to(b); //if (d<margin) /// continue; recover_motion+=(b-a)*0.2; } if (recover_motion==Vector2()) { collided=false; break; } Matrix32 gt = get_global_transform(); gt.elements[2]+=recover_motion; set_global_transform(gt); recover_attempts--; } while (recover_attempts); //move second float safe = 1.0; float unsafe = 1.0; int best_shape=-1; for(int i=0;i<get_shape_count();i++) { float lsafe,lunsafe; bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,0,mask); //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); if (!valid) { safe=0; unsafe=0; best_shape=i; //sadly it's the best break; } if (lsafe==1.0) { continue; } if (lsafe < safe) { safe=lsafe; unsafe=lunsafe; best_shape=i; } } //print_line("best shape: "+itos(best_shape)+" motion "+p_motion); if (safe>=1) { //not collided colliding=false; } else { //it collided, let's get the rest info in unsafe advance Matrix32 ugt = get_global_transform(); ugt.elements[2]+=p_motion*unsafe; Physics2DDirectSpaceState::ShapeRestInfo rest_info; bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,0,mask); if (!c2) { //should not happen, but floating point precision is so weird.. colliding=false; } else { //print_line("Travel: "+rtos(travel)); colliding=true; collision=rest_info.point; normal=rest_info.normal; collider=rest_info.collider_id; collider_vel=rest_info.linear_velocity; } } Vector2 motion=p_motion*safe; Matrix32 gt = get_global_transform(); gt.elements[2]+=motion; set_global_transform(gt); return p_motion-motion; }
bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p_margin,Physics2DServer::MotionResult *r_result) { //give me back regular physics engine logic //this is madness //and most people using this function will think //what it does is simpler than using physics //this took about a week to get right.. //but is it right? who knows at this point.. Rect2 body_aabb; for(int i=0; i<p_body->get_shape_count(); i++) { if (i==0) body_aabb=p_body->get_shape_aabb(i); else body_aabb=body_aabb.merge(p_body->get_shape_aabb(i)); } body_aabb=body_aabb.grow(p_margin); Matrix32 body_transform = p_body->get_transform(); { //STEP 1, FREE BODY IF STUCK const int max_results = 32; int recover_attempts=4; Vector2 sr[max_results*2]; do { Physics2DServerSW::CollCbkData cbk; cbk.max=max_results; cbk.amount=0; cbk.ptr=sr; CollisionSolver2DSW::CallbackResult cbkres=NULL; Physics2DServerSW::CollCbkData *cbkptr=NULL; cbkptr=&cbk; cbkres=Physics2DServerSW::_shape_col_cbk; bool collided=false; int amount = _cull_aabb_for_body(p_body,body_aabb); for(int j=0; j<p_body->get_shape_count(); j++) { if (p_body->is_shape_set_as_trigger(j)) continue; Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j); Shape2DSW *body_shape = p_body->get_shape(j); for(int i=0; i<amount; i++) { const CollisionObject2DSW *col_obj=intersection_query_results[i]; int shape_idx=intersection_query_subindex_results[i]; if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) { const Body2DSW *body=static_cast<const Body2DSW*>(col_obj); 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 { cbk.valid_dir=Vector2(); cbk.valid_depth=0; } if (CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),cbkres,cbkptr,NULL,p_margin)) { collided=cbk.amount>0; } } } if (!collided) break; Vector2 recover_motion; for(int i=0; i<cbk.amount; i++) { Vector2 a = sr[i*2+0]; Vector2 b = sr[i*2+1]; // float d = a.distance_to(b); //if (d<margin) /// continue; recover_motion+=(b-a)*0.4; } if (recover_motion==Vector2()) { collided=false; break; } body_transform.elements[2]+=recover_motion; body_aabb.pos+=recover_motion; recover_attempts--; } while (recover_attempts); } float safe = 1.0; float unsafe = 1.0; int best_shape=-1; { // STEP 2 ATTEMPT MOTION Rect2 motion_aabb=body_aabb; motion_aabb.pos+=p_motion; motion_aabb=motion_aabb.merge(body_aabb); int amount = _cull_aabb_for_body(p_body,motion_aabb); for(int j=0; j<p_body->get_shape_count(); j++) { if (p_body->is_shape_set_as_trigger(j)) continue; Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j); Shape2DSW *body_shape = p_body->get_shape(j); bool stuck=false; float best_safe=1; float best_unsafe=1; for(int i=0; i<amount; i++) { const CollisionObject2DSW *col_obj=intersection_query_results[i]; int shape_idx=intersection_query_subindex_results[i]; 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(body_shape,body_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,0)) { continue; } //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 (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; } } stuck=true; break; } //just do kinematic solving float low=0; float hi=1; Vector2 mnormal=p_motion.normalized(); for(int i=0; i<8; i++) { //steps should be customizable.. //Matrix32 xfa = p_xform; float ofs = (low+hi)*0.5; Vector2 sep=mnormal; //important optimization for this to work fast enough bool collided = CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep,0); if (collided) { hi=ofs; } else { low=ofs; } } 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(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); if (!collided || cbk.amount==0) { continue; } } } if (low<best_safe) { best_safe=low; best_unsafe=hi; } } if (stuck) { safe=0; unsafe=0; best_shape=j; //sadly it's the best break; } if (best_safe==1.0) { continue; } if (best_safe < safe) { safe=best_safe; unsafe=best_unsafe; best_shape=j; } } } bool collided=false; if (safe>=1) { //not collided collided=false; if (r_result) { r_result->motion=p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]); r_result->remainder=Vector2(); } } else { //it collided, let's get the rest info in unsafe advance Matrix32 ugt = body_transform; ugt.elements[2]+=p_motion*unsafe; _RestCallbackData2D rcd; rcd.best_len=0; rcd.best_object=NULL; rcd.best_shape=0; Matrix32 body_shape_xform = ugt * p_body->get_shape_transform(best_shape); Shape2DSW *body_shape = p_body->get_shape(best_shape); body_aabb.pos+=p_motion*unsafe; int amount = _cull_aabb_for_body(p_body,body_aabb); for(int i=0; i<amount; i++) { const CollisionObject2DSW *col_obj=intersection_query_results[i]; int shape_idx=intersection_query_subindex_results[i]; 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(body_shape,body_shape_xform,Vector2(),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); if (!sc) continue; } if (rcd.best_len!=0) { if (r_result) { r_result->collider=rcd.best_object->get_self(); r_result->collider_id=rcd.best_object->get_instance_id(); r_result->collider_shape=rcd.best_shape; r_result->collision_normal=rcd.best_normal; r_result->collision_point=rcd.best_contact; r_result->collider_metadata=rcd.best_object->get_shape_metadata(rcd.best_shape); const Body2DSW *body = static_cast<const Body2DSW*>(rcd.best_object); Vector2 rel_vec = r_result->collision_point-body->get_transform().get_origin(); r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); r_result->motion=safe*p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]); r_result->remainder=p_motion - safe * p_motion; } collided=true; } else { if (r_result) { r_result->motion=p_motion+(body_transform.elements[2]-p_body->get_transform().elements[2]); r_result->remainder=Vector2(); } collided=false; } } return collided; #if 0 //give me back regular physics engine logic //this is madness //and most people using this function will think //what it does is simpler than using physics //this took about a week to get right.. //but is it right? who knows at this point.. colliding=false; ERR_FAIL_COND_V(!is_inside_tree(),Vector2()); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); ERR_FAIL_COND_V(!dss,Vector2()); const int max_shapes=32; Vector2 sr[max_shapes*2]; int res_shapes; Set<RID> exclude; exclude.insert(get_rid()); //recover first int recover_attempts=4; bool collided=false; uint32_t mask=0; if (collide_static) mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; if (collide_kinematic) mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; if (collide_rigid) mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; if (collide_character) mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; // print_line("motion: "+p_motion+" margin: "+rtos(margin)); //print_line("margin: "+rtos(margin)); do { //motion recover for(int i=0; i<get_shape_count(); i++) { if (is_shape_set_as_trigger(i)) continue; if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) collided=true; } if (!collided) break; Vector2 recover_motion; for(int i=0; i<res_shapes; i++) { Vector2 a = sr[i*2+0]; Vector2 b = sr[i*2+1]; float d = a.distance_to(b); //if (d<margin) /// continue; recover_motion+=(b-a)*0.4; } if (recover_motion==Vector2()) { collided=false; break; } Matrix32 gt = get_global_transform(); gt.elements[2]+=recover_motion; set_global_transform(gt); recover_attempts--; } while (recover_attempts); //move second float safe = 1.0; float unsafe = 1.0; int best_shape=-1; for(int i=0; i<get_shape_count(); i++) { if (is_shape_set_as_trigger(i)) continue; float lsafe,lunsafe; bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask); //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); if (!valid) { safe=0; unsafe=0; best_shape=i; //sadly it's the best break; } if (lsafe==1.0) { continue; } if (lsafe < safe) { safe=lsafe; unsafe=lunsafe; best_shape=i; } } //print_line("best shape: "+itos(best_shape)+" motion "+p_motion); if (safe>=1) { //not collided colliding=false; } else { //it collided, let's get the rest info in unsafe advance Matrix32 ugt = get_global_transform(); ugt.elements[2]+=p_motion*unsafe; Physics2DDirectSpaceState::ShapeRestInfo rest_info; bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,get_layer_mask(),mask); if (!c2) { //should not happen, but floating point precision is so weird.. colliding=false; } else { //print_line("Travel: "+rtos(travel)); colliding=true; collision=rest_info.point; normal=rest_info.normal; collider=rest_info.collider_id; collider_vel=rest_info.linear_velocity; collider_shape=rest_info.shape; collider_metadata=rest_info.metadata; } } Vector2 motion=p_motion*safe; Matrix32 gt = get_global_transform(); gt.elements[2]+=motion; set_global_transform(gt); return p_motion-motion; #endif return false; }
void AudioStreamPlayer2D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { AudioServer::get_singleton()->add_callback(_mix_audios, this); if (autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } } if (p_what == NOTIFICATION_EXIT_TREE) { AudioServer::get_singleton()->remove_callback(_mix_audios, this); } if (p_what == NOTIFICATION_INTERNAL_FIXED_PROCESS) { //update anything related to position first, if possible of course if (!output_ready) { List<Viewport *> viewports; Ref<World2D> world_2d = get_world_2d(); ERR_FAIL_COND(world_2d.is_null()); int new_output_count = 0; Vector2 global_pos = get_global_position(); int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); //check if any area is diverting sound into a bus Physics2DDirectSpaceState *space_state = Physics2DServer::get_singleton()->space_get_direct_state(world_2d->get_space()); Physics2DDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS]; int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, Physics2DDirectSpaceState::TYPE_MASK_AREA); for (int i = 0; i < areas; i++) { Area2D *area2d = Object::cast_to<Area2D>(sr[i].collider); if (!area2d) continue; if (!area2d->is_overriding_audio_bus()) continue; StringName bus_name = area2d->get_audio_bus_name(); bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name); break; } world_2d->get_viewport_list(&viewports); for (List<Viewport *>::Element *E = viewports.front(); E; E = E->next()) { Viewport *vp = E->get(); if (vp->is_audio_listener_2d()) { //compute matrix to convert to screen Transform2D to_screen = vp->get_global_canvas_transform() * vp->get_canvas_transform(); Vector2 screen_size = vp->get_visible_rect().size; //screen in global is used for attenuation Vector2 screen_in_global = to_screen.affine_inverse().xform(screen_size * 0.5); float dist = global_pos.distance_to(screen_in_global); //distance to screen center if (dist > max_distance) continue; //cant hear this sound in this viewport float multiplier = Math::pow(1.0f - dist / max_distance, attenuation); multiplier *= Math::db2linear(volume_db); //also apply player volume! //point in screen is used for panning Vector2 point_in_screen = to_screen.xform(global_pos); float pan = CLAMP(point_in_screen.x / screen_size.width, 0.0, 1.0); float l = 1.0 - pan; float r = pan; outputs[new_output_count].vol = AudioFrame(l, r) * multiplier; outputs[new_output_count].bus_index = bus_index; outputs[new_output_count].viewport = vp; //keep pointer only for reference new_output_count++; if (new_output_count == MAX_OUTPUTS) break; } } output_count = new_output_count; output_ready = true; } //start playing if requested if (setplay >= 0.0) { setseek = setplay; active = true; setplay = -1; //do not update, this makes it easier to animate (will shut off otherise) //_change_notify("playing"); //update property in editor } //stop playing if no longer active if (!active) { set_fixed_process_internal(false); //do not update, this makes it easier to animate (will shut off otherise) //_change_notify("playing"); //update property in editor emit_signal("finished"); } } }