2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* godot_space_2d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2021-10-18 21:24:30 +02:00
# include "godot_space_2d.h"
# include "godot_collision_solver_2d.h"
# include "godot_physics_server_2d.h"
2017-08-27 21:07:15 +02:00
2018-11-02 19:44:29 +01:00
# include "core/os/os.h"
2020-11-07 23:33:38 +01:00
# include "core/templates/pair.h"
2021-09-17 03:38:17 +02:00
2021-12-09 18:52:27 +01:00
# define TEST_MOTION_MARGIN_MIN_VALUE 0.0001
2021-09-17 03:38:17 +02:00
# define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05
2021-10-18 21:24:30 +02:00
_FORCE_INLINE_ static bool _can_collide_with ( GodotCollisionObject2D * p_object , uint32_t p_collision_mask , bool p_collide_with_bodies , bool p_collide_with_areas ) {
2020-07-27 22:45:01 +02:00
if ( ! ( p_object - > get_collision_layer ( ) & p_collision_mask ) ) {
2018-08-21 20:30:41 +02:00
return false ;
}
2021-10-18 21:24:30 +02:00
if ( p_object - > get_type ( ) = = GodotCollisionObject2D : : TYPE_AREA & & ! p_collide_with_areas ) {
2018-08-21 20:30:41 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-08-21 20:30:41 +02:00
2021-10-18 21:24:30 +02:00
if ( p_object - > get_type ( ) = = GodotCollisionObject2D : : TYPE_BODY & & ! p_collide_with_bodies ) {
2018-08-21 20:30:41 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2018-08-21 20:30:41 +02:00
return true ;
2014-02-23 00:28:19 +01:00
}
2021-11-02 02:00:58 +01:00
int GodotPhysicsDirectSpaceState2D : : intersect_point ( const PointParameters & p_parameters , ShapeResult * r_results , int p_result_max ) {
2020-05-14 16:41:43 +02:00
if ( p_result_max < = 0 ) {
2015-03-22 05:46:18 +01:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2015-03-22 05:46:18 +01:00
Rect2 aabb ;
2021-11-02 02:00:58 +01:00
aabb . position = p_parameters . position - Vector2 ( 0.00001 , 0.00001 ) ;
2015-03-22 05:46:18 +01:00
aabb . size = Vector2 ( 0.00002 , 0.00002 ) ;
2021-10-18 21:24:30 +02:00
int amount = space - > broadphase - > cull_aabb ( aabb , space - > intersection_query_results , GodotSpace2D : : INTERSECTION_QUERY_MAX , space - > intersection_query_subindex_results ) ;
2015-03-22 05:46:18 +01:00
int cc = 0 ;
for ( int i = 0 ; i < amount ; i + + ) {
2021-11-02 02:00:58 +01:00
if ( ! _can_collide_with ( space - > intersection_query_results [ i ] , p_parameters . collision_mask , p_parameters . collide_with_bodies , p_parameters . collide_with_areas ) ) {
2015-03-22 05:46:18 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-03-22 05:46:18 +01:00
2021-11-02 02:00:58 +01:00
if ( p_parameters . exclude . has ( space - > intersection_query_results [ i ] - > get_self ( ) ) ) {
2015-03-22 05:46:18 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-03-22 05:46:18 +01:00
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = space - > intersection_query_results [ i ] ;
2015-03-22 05:46:18 +01:00
2021-11-02 02:00:58 +01:00
if ( p_parameters . pick_point & & ! col_obj - > is_pickable ( ) ) {
2015-03-22 05:46:18 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-03-22 05:46:18 +01:00
2022-09-18 23:18:29 +02:00
if ( col_obj - > get_canvas_instance_id ( ) ! = p_parameters . canvas_instance_id ) {
2018-08-25 00:03:26 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-08-25 00:03:26 +02:00
2015-03-22 05:46:18 +01:00
int shape_idx = space - > intersection_query_subindex_results [ i ] ;
2021-10-18 21:24:30 +02:00
GodotShape2D * shape = col_obj - > get_shape ( shape_idx ) ;
2015-03-22 05:46:18 +01:00
2021-11-02 02:00:58 +01:00
Vector2 local_point = ( col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) ) . affine_inverse ( ) . xform ( p_parameters . position ) ;
2015-03-22 05:46:18 +01:00
2020-05-14 16:41:43 +02:00
if ( ! shape - > contains_point ( local_point ) ) {
2015-03-22 05:46:18 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-03-22 05:46:18 +01:00
2020-05-14 16:41:43 +02:00
if ( cc > = p_result_max ) {
2016-09-27 04:40:06 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2016-09-27 04:40:06 +02:00
2015-03-22 05:46:18 +01:00
r_results [ cc ] . collider_id = col_obj - > get_instance_id ( ) ;
2020-05-14 16:41:43 +02:00
if ( r_results [ cc ] . collider_id . is_valid ( ) ) {
2015-03-22 05:46:18 +01:00
r_results [ cc ] . collider = ObjectDB : : get_instance ( r_results [ cc ] . collider_id ) ;
2020-05-14 16:41:43 +02:00
}
2015-03-22 05:46:18 +01:00
r_results [ cc ] . rid = col_obj - > get_self ( ) ;
r_results [ cc ] . shape = shape_idx ;
cc + + ;
}
return cc ;
}
2021-11-02 02:00:58 +01:00
bool GodotPhysicsDirectSpaceState2D : : intersect_ray ( const RayParameters & p_parameters , RayResult & r_result ) {
2014-02-19 15:57:14 +01:00
ERR_FAIL_COND_V ( space - > locked , false ) ;
Vector2 begin , end ;
Vector2 normal ;
2021-11-02 02:00:58 +01:00
begin = p_parameters . from ;
end = p_parameters . to ;
2014-02-19 15:57:14 +01:00
normal = ( end - begin ) . normalized ( ) ;
2021-10-18 21:24:30 +02:00
int amount = space - > broadphase - > cull_segment ( begin , end , space - > intersection_query_results , GodotSpace2D : : INTERSECTION_QUERY_MAX , space - > intersection_query_subindex_results ) ;
2014-02-19 15:57:14 +01:00
2018-09-13 03:38:39 +02:00
//todo, create another array that references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision
2014-02-19 15:57:14 +01:00
bool collided = false ;
Vector2 res_point , res_normal ;
2022-09-28 17:05:34 +02:00
int res_shape = - 1 ;
const GodotCollisionObject2D * res_obj = nullptr ;
2014-02-19 15:57:14 +01:00
real_t min_d = 1e10 ;
for ( int i = 0 ; i < amount ; i + + ) {
2021-11-02 02:00:58 +01:00
if ( ! _can_collide_with ( space - > intersection_query_results [ i ] , p_parameters . collision_mask , p_parameters . collide_with_bodies , p_parameters . collide_with_areas ) ) {
2014-02-23 00:28:19 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
if ( p_parameters . exclude . has ( space - > intersection_query_results [ i ] - > get_self ( ) ) ) {
2014-02-19 15:57:14 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = space - > intersection_query_results [ i ] ;
2014-02-19 15:57:14 +01:00
int shape_idx = space - > intersection_query_subindex_results [ i ] ;
2017-01-11 04:52:51 +01:00
Transform2D inv_xform = col_obj - > get_shape_inv_transform ( shape_idx ) * col_obj - > get_inv_transform ( ) ;
2014-02-19 15:57:14 +01:00
Vector2 local_from = inv_xform . xform ( begin ) ;
Vector2 local_to = inv_xform . xform ( end ) ;
2021-10-18 21:24:30 +02:00
const GodotShape2D * shape = col_obj - > get_shape ( shape_idx ) ;
2014-02-19 15:57:14 +01:00
Vector2 shape_point , shape_normal ;
2021-11-10 23:57:11 +01:00
if ( shape - > contains_point ( local_from ) ) {
if ( p_parameters . hit_from_inside ) {
// Hit shape at starting point.
min_d = 0 ;
2022-03-20 10:31:03 +01:00
res_point = begin ;
2021-11-10 23:57:11 +01:00
res_normal = Vector2 ( ) ;
res_shape = shape_idx ;
res_obj = col_obj ;
collided = true ;
break ;
} else {
// Ignore shape when starting inside.
continue ;
}
}
2014-02-19 15:57:14 +01:00
if ( shape - > intersect_segment ( local_from , local_to , shape_point , shape_normal ) ) {
2017-01-11 04:52:51 +01:00
Transform2D xform = col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) ;
2014-02-19 15:57:14 +01:00
shape_point = xform . xform ( shape_point ) ;
real_t ld = normal . dot ( shape_point ) ;
if ( ld < min_d ) {
min_d = ld ;
res_point = shape_point ;
res_normal = inv_xform . basis_xform_inv ( shape_normal ) . normalized ( ) ;
res_shape = shape_idx ;
res_obj = col_obj ;
collided = true ;
}
}
}
2020-05-14 16:41:43 +02:00
if ( ! collided ) {
2014-02-19 15:57:14 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2022-09-28 17:05:34 +02:00
ERR_FAIL_NULL_V ( res_obj , false ) ; // Shouldn't happen but silences warning.
2014-02-19 15:57:14 +01:00
r_result . collider_id = res_obj - > get_instance_id ( ) ;
2020-05-14 16:41:43 +02:00
if ( r_result . collider_id . is_valid ( ) ) {
2014-02-19 15:57:14 +01:00
r_result . collider = ObjectDB : : get_instance ( r_result . collider_id ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
r_result . normal = res_normal ;
r_result . position = res_point ;
r_result . rid = res_obj - > get_self ( ) ;
r_result . shape = res_shape ;
return true ;
}
2021-11-02 02:00:58 +01:00
int GodotPhysicsDirectSpaceState2D : : intersect_shape ( const ShapeParameters & p_parameters , ShapeResult * r_results , int p_result_max ) {
2020-05-14 16:41:43 +02:00
if ( p_result_max < = 0 ) {
2014-02-19 15:57:14 +01:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
GodotShape2D * shape = GodotPhysicsServer2D : : godot_singleton - > shape_owner . get_or_null ( p_parameters . shape_rid ) ;
2023-09-09 17:04:18 +02:00
ERR_FAIL_NULL_V ( shape , 0 ) ;
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
Rect2 aabb = p_parameters . transform . xform ( shape - > get_aabb ( ) ) ;
aabb = aabb . merge ( Rect2 ( aabb . position + p_parameters . motion , aabb . size ) ) ; //motion
aabb = aabb . grow ( p_parameters . margin ) ;
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
int amount = space - > broadphase - > cull_aabb ( aabb , space - > intersection_query_results , GodotSpace2D : : INTERSECTION_QUERY_MAX , space - > intersection_query_subindex_results ) ;
2014-02-19 15:57:14 +01:00
int cc = 0 ;
for ( int i = 0 ; i < amount ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( cc > = p_result_max ) {
2018-04-22 10:16:55 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2018-04-22 10:16:55 +02:00
2021-11-02 02:00:58 +01:00
if ( ! _can_collide_with ( space - > intersection_query_results [ i ] , p_parameters . collision_mask , p_parameters . collide_with_bodies , p_parameters . collide_with_areas ) ) {
2014-02-23 00:28:19 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
if ( p_parameters . exclude . has ( space - > intersection_query_results [ i ] - > get_self ( ) ) ) {
2014-02-19 15:57:14 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = space - > intersection_query_results [ i ] ;
2014-02-19 15:57:14 +01:00
int shape_idx = space - > intersection_query_subindex_results [ i ] ;
2021-11-02 02:00:58 +01:00
if ( ! GodotCollisionSolver2D : : solve ( shape , p_parameters . transform , p_parameters . motion , col_obj - > get_shape ( shape_idx ) , col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) , Vector2 ( ) , nullptr , nullptr , nullptr , p_parameters . margin ) ) {
2014-02-19 15:57:14 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
r_results [ cc ] . collider_id = col_obj - > get_instance_id ( ) ;
2020-05-14 16:41:43 +02:00
if ( r_results [ cc ] . collider_id . is_valid ( ) ) {
2014-02-19 15:57:14 +01:00
r_results [ cc ] . collider = ObjectDB : : get_instance ( r_results [ cc ] . collider_id ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
r_results [ cc ] . rid = col_obj - > get_self ( ) ;
r_results [ cc ] . shape = shape_idx ;
cc + + ;
}
return cc ;
}
2021-11-02 02:00:58 +01:00
bool GodotPhysicsDirectSpaceState2D : : cast_motion ( const ShapeParameters & p_parameters , real_t & p_closest_safe , real_t & p_closest_unsafe ) {
GodotShape2D * shape = GodotPhysicsServer2D : : godot_singleton - > shape_owner . get_or_null ( p_parameters . shape_rid ) ;
2023-09-09 17:04:18 +02:00
ERR_FAIL_NULL_V ( shape , false ) ;
2014-02-23 00:28:19 +01:00
2021-11-02 02:00:58 +01:00
Rect2 aabb = p_parameters . transform . xform ( shape - > get_aabb ( ) ) ;
aabb = aabb . merge ( Rect2 ( aabb . position + p_parameters . motion , aabb . size ) ) ; //motion
aabb = aabb . grow ( p_parameters . margin ) ;
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
int amount = space - > broadphase - > cull_aabb ( aabb , space - > intersection_query_results , GodotSpace2D : : INTERSECTION_QUERY_MAX , space - > intersection_query_subindex_results ) ;
2014-02-23 00:28:19 +01:00
2017-02-14 00:25:05 +01:00
real_t best_safe = 1 ;
2014-02-23 00:28:19 +01:00
real_t best_unsafe = 1 ;
2014-02-19 15:57:14 +01:00
for ( int i = 0 ; i < amount ; i + + ) {
2021-11-02 02:00:58 +01:00
if ( ! _can_collide_with ( space - > intersection_query_results [ i ] , p_parameters . collision_mask , p_parameters . collide_with_bodies , p_parameters . collide_with_areas ) ) {
2014-02-23 00:28:19 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-23 00:28:19 +01:00
2021-11-02 02:00:58 +01:00
if ( p_parameters . exclude . has ( space - > intersection_query_results [ i ] - > get_self ( ) ) ) {
2014-02-23 00:28:19 +01:00
continue ; //ignore excluded
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = space - > intersection_query_results [ i ] ;
2014-02-23 00:28:19 +01:00
int shape_idx = space - > intersection_query_subindex_results [ i ] ;
2017-01-11 04:52:51 +01:00
Transform2D col_obj_xform = col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) ;
2014-02-23 00:28:19 +01:00
//test initial overlap, does it collide if going all the way?
2021-11-02 02:00:58 +01:00
if ( ! GodotCollisionSolver2D : : solve ( shape , p_parameters . transform , p_parameters . motion , col_obj - > get_shape ( shape_idx ) , col_obj_xform , Vector2 ( ) , nullptr , nullptr , nullptr , p_parameters . margin ) ) {
2014-02-23 00:28:19 +01:00
continue ;
2014-02-19 15:57:14 +01:00
}
2020-11-27 15:33:10 +01:00
//test initial overlap, ignore objects it's inside of.
2021-11-02 02:00:58 +01:00
if ( GodotCollisionSolver2D : : solve ( shape , p_parameters . transform , Vector2 ( ) , col_obj - > get_shape ( shape_idx ) , col_obj_xform , Vector2 ( ) , nullptr , nullptr , nullptr , p_parameters . margin ) ) {
2020-11-27 15:33:10 +01:00
continue ;
2014-02-23 00:28:19 +01:00
}
2021-11-02 02:00:58 +01:00
Vector2 mnormal = p_parameters . motion . normalized ( ) ;
2014-02-23 00:28:19 +01:00
2021-07-02 00:14:30 +02:00
//just do kinematic solving
real_t low = 0.0 ;
real_t hi = 1.0 ;
real_t fraction_coeff = 0.5 ;
2019-02-12 21:10:08 +01:00
for ( int j = 0 ; j < 8 ; j + + ) { //steps should be customizable..
2021-07-02 00:14:30 +02:00
real_t fraction = low + ( hi - low ) * fraction_coeff ;
2014-02-23 00:28:19 +01:00
Vector2 sep = mnormal ; //important optimization for this to work fast enough
2021-11-02 02:00:58 +01:00
bool collided = GodotCollisionSolver2D : : solve ( shape , p_parameters . transform , p_parameters . motion * fraction , col_obj - > get_shape ( shape_idx ) , col_obj_xform , Vector2 ( ) , nullptr , nullptr , & sep , p_parameters . margin ) ;
2014-02-23 00:28:19 +01:00
if ( collided ) {
2021-07-02 00:14:30 +02:00
hi = fraction ;
if ( ( j = = 0 ) | | ( low > 0.0 ) ) { // Did it not collide before?
// When alternating or first iteration, use dichotomy.
fraction_coeff = 0.5 ;
} else {
// When colliding again, converge faster towards low fraction
// for more accurate results with long motions that collide near the start.
fraction_coeff = 0.25 ;
}
2014-02-23 00:28:19 +01:00
} else {
2021-07-02 00:14:30 +02:00
low = fraction ;
if ( ( j = = 0 ) | | ( hi < 1.0 ) ) { // Did it collide before?
// When alternating or first iteration, use dichotomy.
fraction_coeff = 0.5 ;
} else {
// When not colliding again, converge faster towards high fraction
// for more accurate results with long motions that collide near the end.
fraction_coeff = 0.75 ;
}
2014-02-23 00:28:19 +01:00
}
}
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
if ( low < best_safe ) {
best_safe = low ;
best_unsafe = hi ;
}
2014-02-19 15:57:14 +01:00
}
2014-02-23 00:28:19 +01:00
p_closest_safe = best_safe ;
p_closest_unsafe = best_unsafe ;
return true ;
2014-02-19 15:57:14 +01:00
}
2021-11-02 02:00:58 +01:00
bool GodotPhysicsDirectSpaceState2D : : collide_shape ( const ShapeParameters & p_parameters , Vector2 * r_results , int p_result_max , int & r_result_count ) {
2020-05-14 16:41:43 +02:00
if ( p_result_max < = 0 ) {
2020-05-14 11:00:19 +02:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
GodotShape2D * shape = GodotPhysicsServer2D : : godot_singleton - > shape_owner . get_or_null ( p_parameters . shape_rid ) ;
2023-09-09 17:04:18 +02:00
ERR_FAIL_NULL_V ( shape , 0 ) ;
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
Rect2 aabb = p_parameters . transform . xform ( shape - > get_aabb ( ) ) ;
aabb = aabb . merge ( Rect2 ( aabb . position + p_parameters . motion , aabb . size ) ) ; //motion
aabb = aabb . grow ( p_parameters . margin ) ;
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
int amount = space - > broadphase - > cull_aabb ( aabb , space - > intersection_query_results , GodotSpace2D : : INTERSECTION_QUERY_MAX , space - > intersection_query_subindex_results ) ;
2014-02-19 15:57:14 +01:00
bool collided = false ;
2014-02-23 00:28:19 +01:00
r_result_count = 0 ;
2021-10-18 21:24:30 +02:00
GodotPhysicsServer2D : : CollCbkData cbk ;
2014-02-23 00:28:19 +01:00
cbk . max = p_result_max ;
cbk . amount = 0 ;
2019-01-18 18:15:05 +01:00
cbk . passed = 0 ;
2014-02-23 00:28:19 +01:00
cbk . ptr = r_results ;
2021-10-18 21:24:30 +02:00
GodotCollisionSolver2D : : CallbackResult cbkres = GodotPhysicsServer2D : : _shape_col_cbk ;
2017-03-05 16:44:50 +01:00
2021-10-18 21:24:30 +02:00
GodotPhysicsServer2D : : CollCbkData * cbkptr = & cbk ;
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
for ( int i = 0 ; i < amount ; i + + ) {
2021-11-02 02:00:58 +01:00
if ( ! _can_collide_with ( space - > intersection_query_results [ i ] , p_parameters . collision_mask , p_parameters . collide_with_bodies , p_parameters . collide_with_areas ) ) {
2014-02-23 00:28:19 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = space - > intersection_query_results [ i ] ;
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
if ( p_parameters . exclude . has ( col_obj - > get_self ( ) ) ) {
2014-02-23 00:28:19 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-06-24 04:30:43 +02:00
2021-02-10 03:00:21 +01:00
int shape_idx = space - > intersection_query_subindex_results [ i ] ;
2017-06-24 04:30:43 +02:00
cbk . valid_dir = Vector2 ( ) ;
cbk . valid_depth = 0 ;
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
if ( GodotCollisionSolver2D : : solve ( shape , p_parameters . transform , p_parameters . motion , col_obj - > get_shape ( shape_idx ) , col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) , Vector2 ( ) , cbkres , cbkptr , nullptr , p_parameters . margin ) ) {
2019-04-08 11:03:37 +02:00
collided = cbk . amount > 0 ;
2014-02-19 15:57:14 +01:00
}
2014-02-23 00:28:19 +01:00
}
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
r_result_count = cbk . amount ;
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
return collided ;
}
2014-02-19 15:57:14 +01:00
2014-09-03 04:13:40 +02:00
struct _RestCallbackData2D {
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * object = nullptr ;
const GodotCollisionObject2D * best_object = nullptr ;
2021-09-14 11:01:49 +02:00
int local_shape = 0 ;
int best_local_shape = 0 ;
int shape = 0 ;
int best_shape = 0 ;
2014-02-23 00:28:19 +01:00
Vector2 best_contact ;
Vector2 best_normal ;
2021-09-14 11:01:49 +02:00
real_t best_len = 0.0 ;
2015-01-14 01:19:11 +01:00
Vector2 valid_dir ;
2021-09-14 11:01:49 +02:00
real_t valid_depth = 0.0 ;
real_t min_allowed_depth = 0.0 ;
2014-02-23 00:28:19 +01:00
} ;
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
static void _rest_cbk_result ( const Vector2 & p_point_A , const Vector2 & p_point_B , void * p_userdata ) {
2022-04-05 12:40:26 +02:00
_RestCallbackData2D * rd = static_cast < _RestCallbackData2D * > ( p_userdata ) ;
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
Vector2 contact_rel = p_point_B - p_point_A ;
2017-02-14 00:25:05 +01:00
real_t len = contact_rel . length ( ) ;
2019-02-16 17:45:01 +01:00
2021-02-18 02:27:19 +01:00
if ( len < rd - > min_allowed_depth ) {
2020-10-05 15:55:11 +02:00
return ;
}
2021-02-18 02:27:19 +01:00
if ( len < = rd - > best_len ) {
2020-10-05 15:55:11 +02:00
return ;
}
2021-02-18 02:27:19 +01:00
Vector2 normal = contact_rel / len ;
2019-02-16 17:45:01 +01:00
2021-02-18 02:27:19 +01:00
if ( rd - > valid_dir ! = Vector2 ( ) ) {
if ( len > rd - > valid_depth ) {
return ;
}
if ( rd - > valid_dir . dot ( normal ) > - CMP_EPSILON ) {
return ;
}
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
rd - > best_len = len ;
rd - > best_contact = p_point_B ;
2020-10-05 15:55:11 +02:00
rd - > best_normal = normal ;
2014-02-23 00:28:19 +01:00
rd - > best_object = rd - > object ;
rd - > best_shape = rd - > shape ;
2018-11-15 01:17:36 +01:00
rd - > best_local_shape = rd - > local_shape ;
2014-02-23 00:28:19 +01:00
}
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
bool GodotPhysicsDirectSpaceState2D : : rest_info ( const ShapeParameters & p_parameters , ShapeRestInfo * r_info ) {
GodotShape2D * shape = GodotPhysicsServer2D : : godot_singleton - > shape_owner . get_or_null ( p_parameters . shape_rid ) ;
2023-09-09 17:04:18 +02:00
ERR_FAIL_NULL_V ( shape , 0 ) ;
2014-02-19 15:57:14 +01:00
2021-12-09 18:52:27 +01:00
real_t margin = MAX ( p_parameters . margin , TEST_MOTION_MARGIN_MIN_VALUE ) ;
2021-11-02 02:00:58 +01:00
Rect2 aabb = p_parameters . transform . xform ( shape - > get_aabb ( ) ) ;
aabb = aabb . merge ( Rect2 ( aabb . position + p_parameters . motion , aabb . size ) ) ; //motion
2021-12-09 18:52:27 +01:00
aabb = aabb . grow ( margin ) ;
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
int amount = space - > broadphase - > cull_aabb ( aabb , space - > intersection_query_results , GodotSpace2D : : INTERSECTION_QUERY_MAX , space - > intersection_query_subindex_results ) ;
2014-02-23 00:28:19 +01:00
2014-09-03 04:13:40 +02:00
_RestCallbackData2D rcd ;
2021-11-12 21:30:54 +01:00
// Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
real_t motion_length = p_parameters . motion . length ( ) ;
2021-12-09 18:52:27 +01:00
real_t min_contact_depth = margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR ;
2021-11-12 21:30:54 +01:00
rcd . min_allowed_depth = MIN ( motion_length , min_contact_depth ) ;
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
for ( int i = 0 ; i < amount ; i + + ) {
2021-11-02 02:00:58 +01:00
if ( ! _can_collide_with ( space - > intersection_query_results [ i ] , p_parameters . collision_mask , p_parameters . collide_with_bodies , p_parameters . collide_with_areas ) ) {
2014-02-23 00:28:19 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = space - > intersection_query_results [ i ] ;
2014-02-19 15:57:14 +01:00
2021-11-02 02:00:58 +01:00
if ( p_parameters . exclude . has ( col_obj - > get_self ( ) ) ) {
2014-02-19 15:57:14 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2021-02-10 03:00:21 +01:00
int shape_idx = space - > intersection_query_subindex_results [ i ] ;
2017-06-24 04:30:43 +02:00
rcd . valid_dir = Vector2 ( ) ;
2014-02-23 00:28:19 +01:00
rcd . object = col_obj ;
rcd . shape = shape_idx ;
2018-11-15 01:17:36 +01:00
rcd . local_shape = 0 ;
2021-12-09 18:52:27 +01:00
bool sc = GodotCollisionSolver2D : : solve ( shape , p_parameters . transform , p_parameters . motion , col_obj - > get_shape ( shape_idx ) , col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) , Vector2 ( ) , _rest_cbk_result , & rcd , nullptr , margin ) ;
2020-05-14 16:41:43 +02:00
if ( ! sc ) {
2014-02-23 00:28:19 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
}
2020-05-14 16:41:43 +02:00
if ( rcd . best_len = = 0 | | ! rcd . best_object ) {
2014-02-23 00:28:19 +01:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
r_info - > collider_id = rcd . best_object - > get_instance_id ( ) ;
r_info - > shape = rcd . best_shape ;
r_info - > normal = rcd . best_normal ;
r_info - > point = rcd . best_contact ;
r_info - > rid = rcd . best_object - > get_self ( ) ;
2021-10-18 21:24:30 +02:00
if ( rcd . best_object - > get_type ( ) = = GodotCollisionObject2D : : TYPE_BODY ) {
const GodotBody2D * body = static_cast < const GodotBody2D * > ( rcd . best_object ) ;
2021-06-11 02:37:19 +02:00
Vector2 rel_vec = r_info - > point - ( body - > get_transform ( ) . get_origin ( ) + body - > get_center_of_mass ( ) ) ;
2014-02-23 00:28:19 +01:00
r_info - > linear_velocity = Vector2 ( - body - > get_angular_velocity ( ) * rel_vec . y , body - > get_angular_velocity ( ) * rel_vec . x ) + body - > get_linear_velocity ( ) ;
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
} else {
r_info - > linear_velocity = Vector2 ( ) ;
}
return true ;
2014-02-19 15:57:14 +01:00
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
2021-10-18 21:24:30 +02:00
int GodotSpace2D : : _cull_aabb_for_body ( GodotBody2D * p_body , const Rect2 & p_aabb ) {
2015-05-04 03:37:10 +02:00
int amount = broadphase - > cull_aabb ( p_aabb , intersection_query_results , INTERSECTION_QUERY_MAX , intersection_query_subindex_results ) ;
2014-02-19 15:57:14 +01:00
2014-02-23 00:28:19 +01:00
for ( int i = 0 ; i < amount ; i + + ) {
2015-05-04 03:37:10 +02:00
bool keep = true ;
2015-04-20 01:50:55 +02:00
2020-05-14 16:41:43 +02:00
if ( intersection_query_results [ i ] = = p_body ) {
2015-04-20 01:50:55 +02:00
keep = false ;
2021-10-18 21:24:30 +02:00
} else if ( intersection_query_results [ i ] - > get_type ( ) = = GodotCollisionObject2D : : TYPE_AREA ) {
2015-04-20 01:50:55 +02:00
keep = false ;
2021-10-18 21:24:30 +02:00
} else if ( ! p_body - > collides_with ( static_cast < GodotBody2D * > ( intersection_query_results [ i ] ) ) ) {
2015-04-20 01:50:55 +02:00
keep = false ;
2021-10-18 21:24:30 +02:00
} else if ( static_cast < GodotBody2D * > ( intersection_query_results [ i ] ) - > has_exception ( p_body - > get_self ( ) ) | | p_body - > has_exception ( intersection_query_results [ i ] - > get_self ( ) ) ) {
2015-04-20 01:50:55 +02:00
keep = false ;
2020-05-14 16:41:43 +02:00
}
2015-04-20 01:50:55 +02:00
if ( ! keep ) {
if ( i < amount - 1 ) {
SWAP ( intersection_query_results [ i ] , intersection_query_results [ amount - 1 ] ) ;
SWAP ( intersection_query_subindex_results [ i ] , intersection_query_subindex_results [ amount - 1 ] ) ;
}
amount - - ;
i - - ;
}
}
2015-05-04 03:37:10 +02:00
return amount ;
}
2021-10-18 21:24:30 +02:00
bool GodotSpace2D : : test_body_motion ( GodotBody2D * p_body , const PhysicsServer2D : : MotionParameters & p_parameters , PhysicsServer2D : : MotionResult * r_result ) {
2015-05-04 03:37:10 +02:00
//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..
2016-09-01 17:03:55 +02:00
if ( r_result ) {
2020-02-12 18:24:06 +01:00
r_result - > collider_id = ObjectID ( ) ;
2016-09-01 17:03:55 +02:00
r_result - > collider_shape = 0 ;
}
2021-12-09 18:52:27 +01:00
2015-05-04 03:37:10 +02:00
Rect2 body_aabb ;
2018-11-02 19:44:29 +01:00
bool shapes_found = false ;
2015-05-04 03:37:10 +02:00
for ( int i = 0 ; i < p_body - > get_shape_count ( ) ; i + + ) {
2021-06-23 01:36:43 +02:00
if ( p_body - > is_shape_disabled ( i ) ) {
2018-11-02 19:44:29 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-11-02 19:44:29 +01:00
if ( ! shapes_found ) {
2015-05-04 03:37:10 +02:00
body_aabb = p_body - > get_shape_aabb ( i ) ;
2018-11-02 19:44:29 +01:00
shapes_found = true ;
} else {
2015-05-04 03:37:10 +02:00
body_aabb = body_aabb . merge ( p_body - > get_shape_aabb ( i ) ) ;
2018-11-02 19:44:29 +01:00
}
}
if ( ! shapes_found ) {
2019-02-16 15:06:17 +01:00
if ( r_result ) {
2020-03-27 19:21:27 +01:00
* r_result = PhysicsServer2D : : MotionResult ( ) ;
2021-09-30 20:28:57 +02:00
r_result - > travel = p_parameters . motion ;
2019-02-16 15:06:17 +01:00
}
2018-11-02 19:44:29 +01:00
return false ;
2015-05-04 03:37:10 +02:00
}
2021-12-09 18:52:27 +01:00
real_t margin = MAX ( p_parameters . margin , TEST_MOTION_MARGIN_MIN_VALUE ) ;
2017-03-06 05:23:00 +01:00
// Undo the currently transform the physics server is aware of and apply the provided one
2021-09-30 20:28:57 +02:00
body_aabb = p_parameters . from . xform ( p_body - > get_inv_transform ( ) . xform ( body_aabb ) ) ;
2021-12-09 18:52:27 +01:00
body_aabb = body_aabb . grow ( margin ) ;
2015-05-04 03:37:10 +02:00
2017-09-01 03:55:01 +02:00
static const int max_excluded_shape_pairs = 32 ;
2017-09-17 14:38:09 +02:00
ExcludedShapeSW excluded_shape_pairs [ max_excluded_shape_pairs ] ;
2017-09-01 03:55:01 +02:00
int excluded_shape_pair_count = 0 ;
2021-12-09 18:52:27 +01:00
real_t min_contact_depth = margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR ;
2021-09-17 03:38:17 +02:00
2021-09-30 20:28:57 +02:00
real_t motion_length = p_parameters . motion . length ( ) ;
Vector2 motion_normal = p_parameters . motion / motion_length ;
2018-11-15 01:17:36 +01:00
2021-09-30 20:28:57 +02:00
Transform2D body_transform = p_parameters . from ;
2015-04-20 01:50:55 +02:00
2021-02-18 02:27:19 +01:00
bool recovered = false ;
2015-04-20 01:50:55 +02:00
{
//STEP 1, FREE BODY IF STUCK
const int max_results = 32 ;
int recover_attempts = 4 ;
Vector2 sr [ max_results * 2 ] ;
2022-08-10 18:45:36 +02:00
real_t priorities [ max_results ] ;
2015-04-20 01:50:55 +02:00
do {
2021-10-18 21:24:30 +02:00
GodotPhysicsServer2D : : CollCbkData cbk ;
2015-04-20 01:50:55 +02:00
cbk . max = max_results ;
cbk . amount = 0 ;
2019-01-18 18:15:05 +01:00
cbk . passed = 0 ;
2015-04-20 01:50:55 +02:00
cbk . ptr = sr ;
2017-09-01 03:55:01 +02:00
cbk . invalid_by_dir = 0 ;
excluded_shape_pair_count = 0 ; //last step is the one valid
2015-04-20 01:50:55 +02:00
2021-10-18 21:24:30 +02:00
GodotPhysicsServer2D : : CollCbkData * cbkptr = & cbk ;
GodotCollisionSolver2D : : CallbackResult cbkres = GodotPhysicsServer2D : : _shape_col_cbk ;
2022-08-10 18:45:36 +02:00
int priority_amount = 0 ;
2015-04-20 01:50:55 +02:00
bool collided = false ;
2017-02-15 12:29:46 +01:00
2015-05-04 03:37:10 +02:00
int amount = _cull_aabb_for_body ( p_body , body_aabb ) ;
2015-04-20 01:50:55 +02:00
for ( int j = 0 ; j < p_body - > get_shape_count ( ) ; j + + ) {
2021-06-23 01:36:43 +02:00
if ( p_body - > is_shape_disabled ( j ) ) {
2015-04-20 01:50:55 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-04-20 01:50:55 +02:00
2021-10-18 21:24:30 +02:00
GodotShape2D * body_shape = p_body - > get_shape ( j ) ;
2018-07-17 01:04:07 +02:00
Transform2D body_shape_xform = body_transform * p_body - > get_shape_transform ( j ) ;
2021-08-10 20:48:19 +02:00
2015-04-20 01:50:55 +02:00
for ( int i = 0 ; i < amount ; i + + ) {
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = intersection_query_results [ i ] ;
2021-09-30 20:28:57 +02:00
if ( p_parameters . exclude_bodies . has ( col_obj - > get_self ( ) ) ) {
2021-07-09 16:16:15 +02:00
continue ;
}
2021-09-30 20:05:30 +02:00
if ( p_parameters . exclude_objects . has ( col_obj - > get_instance_id ( ) ) ) {
continue ;
}
2015-04-20 01:50:55 +02:00
2021-08-10 20:48:19 +02:00
int shape_idx = intersection_query_subindex_results [ i ] ;
2018-02-16 19:06:00 +01:00
2018-11-10 14:12:35 +01:00
Transform2D col_obj_shape_xform = col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) ;
2021-08-18 03:41:21 +02:00
if ( body_shape - > allows_one_way_collision ( ) & & col_obj - > is_shape_set_as_one_way_collision ( shape_idx ) ) {
2022-05-03 14:50:35 +02:00
cbk . valid_dir = col_obj_shape_xform . columns [ 1 ] . normalized ( ) ;
2018-11-10 14:12:35 +01:00
2021-01-28 07:34:26 +01:00
real_t owc_margin = col_obj - > get_shape_one_way_collision_margin ( shape_idx ) ;
2021-12-09 18:52:27 +01:00
cbk . valid_depth = MAX ( owc_margin , margin ) ; //user specified, but never less than actual margin or it won't work
2017-09-01 03:55:01 +02:00
cbk . invalid_by_dir = 0 ;
2018-11-02 20:22:23 +01:00
2021-10-18 21:24:30 +02:00
if ( col_obj - > get_type ( ) = = GodotCollisionObject2D : : TYPE_BODY ) {
const GodotBody2D * b = static_cast < const GodotBody2D * > ( col_obj ) ;
2022-08-25 19:35:52 +02:00
if ( b - > get_mode ( ) = = PhysicsServer2D : : BODY_MODE_KINEMATIC | | b - > get_mode ( ) = = PhysicsServer2D : : BODY_MODE_RIGID ) {
2018-11-03 17:23:25 +01:00
//fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
2018-11-02 20:22:23 +01:00
Vector2 lv = b - > get_linear_velocity ( ) ;
//compute displacement from linear velocity
2021-06-05 01:09:41 +02:00
Vector2 motion = lv * last_step ;
2021-01-28 07:34:26 +01:00
real_t motion_len = motion . length ( ) ;
2018-11-02 20:22:23 +01:00
motion . normalize ( ) ;
cbk . valid_depth + = motion_len * MAX ( motion . dot ( - cbk . valid_dir ) , 0.0 ) ;
}
}
2015-04-20 01:50:55 +02:00
} else {
cbk . valid_dir = Vector2 ( ) ;
cbk . valid_depth = 0 ;
2017-09-01 03:55:01 +02:00
cbk . invalid_by_dir = 0 ;
2015-04-20 01:50:55 +02:00
}
2019-01-18 18:15:05 +01:00
int current_passed = cbk . passed ; //save how many points passed collision
2018-11-02 19:44:29 +01:00
bool did_collide = false ;
2021-10-18 21:24:30 +02:00
GodotShape2D * against_shape = col_obj - > get_shape ( shape_idx ) ;
2021-12-09 18:52:27 +01:00
if ( GodotCollisionSolver2D : : solve ( body_shape , body_shape_xform , Vector2 ( ) , against_shape , col_obj_shape_xform , Vector2 ( ) , cbkres , cbkptr , nullptr , margin ) ) {
2019-01-18 18:15:05 +01:00
did_collide = cbk . passed > current_passed ; //more passed, so collision actually existed
2015-04-20 01:50:55 +02:00
}
2022-08-10 18:45:36 +02:00
while ( cbk . amount > priority_amount ) {
priorities [ priority_amount ] = col_obj - > get_collision_priority ( ) ;
priority_amount + + ;
}
2017-09-01 03:55:01 +02:00
2018-11-02 19:44:29 +01:00
if ( ! did_collide & & cbk . invalid_by_dir > 0 ) {
2017-09-01 03:55:01 +02:00
//this shape must be excluded
if ( excluded_shape_pair_count < max_excluded_shape_pairs ) {
2017-09-17 14:38:09 +02:00
ExcludedShapeSW esp ;
esp . local_shape = body_shape ;
esp . against_object = col_obj ;
2017-09-17 15:18:09 +02:00
esp . against_shape_index = shape_idx ;
2017-09-17 14:38:09 +02:00
excluded_shape_pairs [ excluded_shape_pair_count + + ] = esp ;
2017-09-01 03:55:01 +02:00
}
}
2018-11-02 19:44:29 +01:00
if ( did_collide ) {
collided = true ;
}
2015-04-20 01:50:55 +02:00
}
}
2017-02-15 12:29:46 +01:00
if ( ! collided ) {
2015-04-20 01:50:55 +02:00
break ;
2017-02-15 12:29:46 +01:00
}
2015-04-20 01:50:55 +02:00
2022-08-10 18:45:36 +02:00
real_t inv_total_weight = 0.0 ;
for ( int i = 0 ; i < cbk . amount ; i + + ) {
inv_total_weight + = priorities [ i ] ;
}
inv_total_weight = Math : : is_zero_approx ( inv_total_weight ) ? 1.0 : ( real_t ) cbk . amount / inv_total_weight ;
2021-09-17 03:38:17 +02:00
recovered = true ;
2015-04-20 01:50:55 +02:00
Vector2 recover_motion ;
for ( int i = 0 ; i < cbk . amount ; i + + ) {
Vector2 a = sr [ i * 2 + 0 ] ;
Vector2 b = sr [ i * 2 + 1 ] ;
2021-02-18 02:27:19 +01:00
// Compute plane on b towards a.
Vector2 n = ( a - b ) . normalized ( ) ;
real_t d = n . dot ( b ) ;
// Compute depth on recovered motion.
real_t depth = n . dot ( a + recover_motion ) - d ;
2021-09-17 03:38:17 +02:00
if ( depth > min_contact_depth + CMP_EPSILON ) {
2021-02-18 02:27:19 +01:00
// Only recover if there is penetration.
2022-08-10 18:45:36 +02:00
recover_motion - = n * ( depth - min_contact_depth ) * 0.4 * priorities [ i ] * inv_total_weight ;
2021-02-18 02:27:19 +01:00
}
2015-04-20 01:50:55 +02:00
}
if ( recover_motion = = Vector2 ( ) ) {
collided = false ;
break ;
}
2022-04-24 23:59:24 +02:00
body_transform . columns [ 2 ] + = recover_motion ;
2017-06-04 00:25:13 +02:00
body_aabb . position + = recover_motion ;
2015-04-20 01:50:55 +02:00
recover_attempts - - ;
} while ( recover_attempts ) ;
}
2017-02-14 00:25:05 +01:00
real_t safe = 1.0 ;
real_t unsafe = 1.0 ;
2015-04-20 01:50:55 +02:00
int best_shape = - 1 ;
{
// STEP 2 ATTEMPT MOTION
2015-05-04 03:37:10 +02:00
Rect2 motion_aabb = body_aabb ;
2021-09-30 20:28:57 +02:00
motion_aabb . position + = p_parameters . motion ;
2015-05-04 03:37:10 +02:00
motion_aabb = motion_aabb . merge ( body_aabb ) ;
2015-04-20 01:50:55 +02:00
2015-05-04 03:37:10 +02:00
int amount = _cull_aabb_for_body ( p_body , motion_aabb ) ;
2015-04-20 01:50:55 +02:00
2017-11-08 21:45:49 +01:00
for ( int body_shape_idx = 0 ; body_shape_idx < p_body - > get_shape_count ( ) ; body_shape_idx + + ) {
2021-06-23 01:36:43 +02:00
if ( p_body - > is_shape_disabled ( body_shape_idx ) ) {
2015-04-20 01:50:55 +02:00
continue ;
2020-05-14 16:41:43 +02:00
}
2015-04-20 01:50:55 +02:00
2021-10-18 21:24:30 +02:00
GodotShape2D * body_shape = p_body - > get_shape ( body_shape_idx ) ;
2021-08-19 17:28:04 +02:00
// Colliding separation rays allows to properly snap to the ground,
// otherwise it's not needed in regular motion.
2021-09-30 20:28:57 +02:00
if ( ! p_parameters . collide_separation_ray & & ( body_shape - > get_type ( ) = = PhysicsServer2D : : SHAPE_SEPARATION_RAY ) ) {
2021-08-19 20:02:40 +02:00
// When slide on slope is on, separation ray shape acts like a regular shape.
2021-10-18 21:24:30 +02:00
if ( ! static_cast < GodotSeparationRayShape2D * > ( body_shape ) - > get_slide_on_slope ( ) ) {
2021-08-19 17:28:04 +02:00
continue ;
}
}
2018-07-17 01:04:07 +02:00
Transform2D body_shape_xform = body_transform * p_body - > get_shape_transform ( body_shape_idx ) ;
2015-04-20 01:50:55 +02:00
bool stuck = false ;
2017-02-14 00:25:05 +01:00
real_t best_safe = 1 ;
real_t best_unsafe = 1 ;
2015-04-20 01:50:55 +02:00
for ( int i = 0 ; i < amount ; i + + ) {
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = intersection_query_results [ i ] ;
2021-09-30 20:28:57 +02:00
if ( p_parameters . exclude_bodies . has ( col_obj - > get_self ( ) ) ) {
2021-07-09 16:16:15 +02:00
continue ;
}
2021-09-30 20:05:30 +02:00
if ( p_parameters . exclude_objects . has ( col_obj - > get_instance_id ( ) ) ) {
continue ;
}
2021-09-30 20:28:57 +02:00
2017-11-08 21:45:49 +01:00
int col_shape_idx = intersection_query_subindex_results [ i ] ;
2021-10-18 21:24:30 +02:00
GodotShape2D * against_shape = col_obj - > get_shape ( col_shape_idx ) ;
2017-09-01 03:55:01 +02:00
bool excluded = false ;
for ( int k = 0 ; k < excluded_shape_pair_count ; k + + ) {
2017-11-08 21:45:49 +01:00
if ( excluded_shape_pairs [ k ] . local_shape = = body_shape & & excluded_shape_pairs [ k ] . against_object = = col_obj & & excluded_shape_pairs [ k ] . against_shape_index = = col_shape_idx ) {
2017-09-01 03:55:01 +02:00
excluded = true ;
break ;
}
}
if ( excluded ) {
continue ;
}
2015-04-20 01:50:55 +02:00
2018-11-10 14:12:35 +01:00
Transform2D col_obj_shape_xform = col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( col_shape_idx ) ;
2015-04-20 01:50:55 +02:00
//test initial overlap, does it collide if going all the way?
2021-10-18 21:24:30 +02:00
if ( ! GodotCollisionSolver2D : : solve ( body_shape , body_shape_xform , p_parameters . motion , against_shape , col_obj_shape_xform , Vector2 ( ) , nullptr , nullptr , nullptr , 0 ) ) {
2015-04-20 01:50:55 +02:00
continue ;
}
//test initial overlap
2021-10-18 21:24:30 +02:00
if ( GodotCollisionSolver2D : : solve ( body_shape , body_shape_xform , Vector2 ( ) , against_shape , col_obj_shape_xform , Vector2 ( ) , nullptr , nullptr , nullptr , 0 ) ) {
2021-08-18 03:41:21 +02:00
if ( body_shape - > allows_one_way_collision ( ) & & col_obj - > is_shape_set_as_one_way_collision ( col_shape_idx ) ) {
2022-05-03 14:50:35 +02:00
Vector2 direction = col_obj_shape_xform . columns [ 1 ] . normalized ( ) ;
2021-02-18 02:27:19 +01:00
if ( motion_normal . dot ( direction ) < 0 ) {
continue ;
}
2015-04-20 01:50:55 +02:00
}
stuck = true ;
break ;
}
//just do kinematic solving
2021-07-02 00:14:30 +02:00
real_t low = 0.0 ;
real_t hi = 1.0 ;
real_t fraction_coeff = 0.5 ;
2017-06-24 04:30:43 +02:00
for ( int k = 0 ; k < 8 ; k + + ) { //steps should be customizable..
2021-07-02 00:14:30 +02:00
real_t fraction = low + ( hi - low ) * fraction_coeff ;
2015-04-20 01:50:55 +02:00
2021-02-18 02:27:19 +01:00
Vector2 sep = motion_normal ; //important optimization for this to work fast enough
2021-10-18 21:24:30 +02:00
bool collided = GodotCollisionSolver2D : : solve ( body_shape , body_shape_xform , p_parameters . motion * fraction , against_shape , col_obj_shape_xform , Vector2 ( ) , nullptr , nullptr , & sep , 0 ) ;
2015-04-20 01:50:55 +02:00
if ( collided ) {
2021-07-02 00:14:30 +02:00
hi = fraction ;
if ( ( k = = 0 ) | | ( low > 0.0 ) ) { // Did it not collide before?
// When alternating or first iteration, use dichotomy.
fraction_coeff = 0.5 ;
} else {
// When colliding again, converge faster towards low fraction
// for more accurate results with long motions that collide near the start.
fraction_coeff = 0.25 ;
}
2015-04-20 01:50:55 +02:00
} else {
2021-07-02 00:14:30 +02:00
low = fraction ;
if ( ( k = = 0 ) | | ( hi < 1.0 ) ) { // Did it collide before?
// When alternating or first iteration, use dichotomy.
fraction_coeff = 0.5 ;
} else {
// When not colliding again, converge faster towards high fraction
// for more accurate results with long motions that collide near the end.
fraction_coeff = 0.75 ;
}
2015-04-20 01:50:55 +02:00
}
}
2021-08-18 03:41:21 +02:00
if ( body_shape - > allows_one_way_collision ( ) & & col_obj - > is_shape_set_as_one_way_collision ( col_shape_idx ) ) {
2017-08-16 12:36:26 +02:00
Vector2 cd [ 2 ] ;
2021-10-18 21:24:30 +02:00
GodotPhysicsServer2D : : CollCbkData cbk ;
2017-08-16 12:36:26 +02:00
cbk . max = 1 ;
cbk . amount = 0 ;
2019-01-18 18:15:05 +01:00
cbk . passed = 0 ;
2017-08-16 12:36:26 +02:00
cbk . ptr = cd ;
2022-05-03 14:50:35 +02:00
cbk . valid_dir = col_obj_shape_xform . columns [ 1 ] . normalized ( ) ;
2017-09-01 03:55:01 +02:00
2017-08-16 12:36:26 +02:00
cbk . valid_depth = 10e20 ;
2015-04-20 01:50:55 +02:00
2021-02-18 02:27:19 +01:00
Vector2 sep = motion_normal ; //important optimization for this to work fast enough
2021-10-18 21:24:30 +02:00
bool collided = GodotCollisionSolver2D : : solve ( body_shape , body_shape_xform , p_parameters . motion * ( hi + contact_max_allowed_penetration ) , col_obj - > get_shape ( col_shape_idx ) , col_obj_shape_xform , Vector2 ( ) , GodotPhysicsServer2D : : _shape_col_cbk , & cbk , & sep , 0 ) ;
2017-08-16 12:36:26 +02:00
if ( ! collided | | cbk . amount = = 0 ) {
continue ;
2015-04-20 01:50:55 +02:00
}
}
if ( low < best_safe ) {
best_safe = low ;
best_unsafe = hi ;
}
}
if ( stuck ) {
safe = 0 ;
unsafe = 0 ;
2017-11-08 21:45:49 +01:00
best_shape = body_shape_idx ; //sadly it's the best
2015-04-20 01:50:55 +02:00
break ;
}
if ( best_safe = = 1.0 ) {
continue ;
}
if ( best_safe < safe ) {
safe = best_safe ;
unsafe = best_unsafe ;
2017-11-08 21:45:49 +01:00
best_shape = body_shape_idx ;
2015-04-20 01:50:55 +02:00
}
}
}
bool collided = false ;
2022-04-28 22:44:09 +02:00
if ( ( p_parameters . recovery_as_collision & & recovered ) | | ( safe < 1 ) ) {
2021-02-18 02:27:19 +01:00
if ( safe > = 1 ) {
best_shape = - 1 ; //no best shape with cast, reset to -1
}
2015-04-20 01:50:55 +02:00
//it collided, let's get the rest info in unsafe advance
2017-01-11 04:52:51 +01:00
Transform2D ugt = body_transform ;
2022-04-24 23:59:24 +02:00
ugt . columns [ 2 ] + = p_parameters . motion * unsafe ;
2015-04-20 01:50:55 +02:00
_RestCallbackData2D rcd ;
2021-02-18 02:27:19 +01:00
// Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
2021-09-17 03:38:17 +02:00
rcd . min_allowed_depth = MIN ( motion_length , min_contact_depth ) ;
2021-02-18 02:27:19 +01:00
2022-02-18 19:43:38 +01:00
body_aabb . position + = p_parameters . motion * unsafe ;
int amount = _cull_aabb_for_body ( p_body , body_aabb ) ;
2018-11-15 01:17:36 +01:00
int from_shape = best_shape ! = - 1 ? best_shape : 0 ;
int to_shape = best_shape ! = - 1 ? best_shape + 1 : p_body - > get_shape_count ( ) ;
2015-04-20 01:50:55 +02:00
2018-11-15 01:17:36 +01:00
for ( int j = from_shape ; j < to_shape ; j + + ) {
2021-06-23 01:36:43 +02:00
if ( p_body - > is_shape_disabled ( j ) ) {
2019-02-16 20:32:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2019-02-16 20:32:30 +01:00
2018-11-15 01:17:36 +01:00
Transform2D body_shape_xform = ugt * p_body - > get_shape_transform ( j ) ;
2021-10-18 21:24:30 +02:00
GodotShape2D * body_shape = p_body - > get_shape ( j ) ;
2015-05-04 03:37:10 +02:00
2018-11-15 01:17:36 +01:00
for ( int i = 0 ; i < amount ; i + + ) {
2021-10-18 21:24:30 +02:00
const GodotCollisionObject2D * col_obj = intersection_query_results [ i ] ;
2021-09-30 20:28:57 +02:00
if ( p_parameters . exclude_bodies . has ( col_obj - > get_self ( ) ) ) {
2021-07-09 16:16:15 +02:00
continue ;
}
2021-09-30 20:05:30 +02:00
if ( p_parameters . exclude_objects . has ( col_obj - > get_instance_id ( ) ) ) {
continue ;
}
2018-11-15 01:17:36 +01:00
2021-08-10 20:48:19 +02:00
int shape_idx = intersection_query_subindex_results [ i ] ;
2018-02-16 19:06:00 +01:00
2021-10-18 21:24:30 +02:00
GodotShape2D * against_shape = col_obj - > get_shape ( shape_idx ) ;
2017-09-01 03:55:01 +02:00
2018-11-15 01:17:36 +01:00
bool excluded = false ;
for ( int k = 0 ; k < excluded_shape_pair_count ; k + + ) {
if ( excluded_shape_pairs [ k ] . local_shape = = body_shape & & excluded_shape_pairs [ k ] . against_object = = col_obj & & excluded_shape_pairs [ k ] . against_shape_index = = shape_idx ) {
excluded = true ;
break ;
}
2017-09-01 03:55:01 +02:00
}
2020-05-14 16:41:43 +02:00
if ( excluded ) {
2018-11-15 01:17:36 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-09-01 03:55:01 +02:00
2018-11-15 01:17:36 +01:00
Transform2D col_obj_shape_xform = col_obj - > get_transform ( ) * col_obj - > get_shape_transform ( shape_idx ) ;
2018-11-10 14:12:35 +01:00
2021-08-18 03:41:21 +02:00
if ( body_shape - > allows_one_way_collision ( ) & & col_obj - > is_shape_set_as_one_way_collision ( shape_idx ) ) {
2022-05-03 14:50:35 +02:00
rcd . valid_dir = col_obj_shape_xform . columns [ 1 ] . normalized ( ) ;
2021-02-18 02:27:19 +01:00
real_t owc_margin = col_obj - > get_shape_one_way_collision_margin ( shape_idx ) ;
2021-12-09 18:52:27 +01:00
rcd . valid_depth = MAX ( owc_margin , margin ) ; //user specified, but never less than actual margin or it won't work
2021-02-18 02:27:19 +01:00
2021-10-18 21:24:30 +02:00
if ( col_obj - > get_type ( ) = = GodotCollisionObject2D : : TYPE_BODY ) {
const GodotBody2D * b = static_cast < const GodotBody2D * > ( col_obj ) ;
2022-08-25 19:35:52 +02:00
if ( b - > get_mode ( ) = = PhysicsServer2D : : BODY_MODE_KINEMATIC | | b - > get_mode ( ) = = PhysicsServer2D : : BODY_MODE_RIGID ) {
2021-02-18 02:27:19 +01:00
//fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
Vector2 lv = b - > get_linear_velocity ( ) ;
//compute displacement from linear velocity
2021-06-05 01:09:41 +02:00
Vector2 motion = lv * last_step ;
2021-02-18 02:27:19 +01:00
real_t motion_len = motion . length ( ) ;
motion . normalize ( ) ;
rcd . valid_depth + = motion_len * MAX ( motion . dot ( - rcd . valid_dir ) , 0.0 ) ;
}
}
2018-11-15 01:17:36 +01:00
} else {
rcd . valid_dir = Vector2 ( ) ;
2021-02-18 02:27:19 +01:00
rcd . valid_depth = 0 ;
2018-11-15 01:17:36 +01:00
}
2015-04-20 01:50:55 +02:00
2018-11-15 01:17:36 +01:00
rcd . object = col_obj ;
rcd . shape = shape_idx ;
rcd . local_shape = j ;
2021-12-09 18:52:27 +01:00
bool sc = GodotCollisionSolver2D : : solve ( body_shape , body_shape_xform , Vector2 ( ) , against_shape , col_obj_shape_xform , Vector2 ( ) , _rest_cbk_result , & rcd , nullptr , margin ) ;
2020-05-14 16:41:43 +02:00
if ( ! sc ) {
2018-11-15 01:17:36 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2018-11-15 01:17:36 +01:00
}
2015-04-20 01:50:55 +02:00
}
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 ;
2018-11-15 01:17:36 +01:00
r_result - > collision_local_shape = rcd . best_local_shape ;
2015-04-20 01:50:55 +02:00
r_result - > collision_normal = rcd . best_normal ;
r_result - > collision_point = rcd . best_contact ;
2021-06-25 04:25:26 +02:00
r_result - > collision_depth = rcd . best_len ;
r_result - > collision_safe_fraction = safe ;
r_result - > collision_unsafe_fraction = unsafe ;
2017-03-05 16:44:50 +01:00
2021-10-18 21:24:30 +02:00
const GodotBody2D * body = static_cast < const GodotBody2D * > ( rcd . best_object ) ;
2021-06-11 02:37:19 +02:00
Vector2 rel_vec = r_result - > collision_point - ( body - > get_transform ( ) . get_origin ( ) + body - > get_center_of_mass ( ) ) ;
2015-04-20 01:50:55 +02:00
r_result - > collider_velocity = Vector2 ( - body - > get_angular_velocity ( ) * rel_vec . y , body - > get_angular_velocity ( ) * rel_vec . x ) + body - > get_linear_velocity ( ) ;
2021-09-30 20:28:57 +02:00
r_result - > travel = safe * p_parameters . motion ;
r_result - > remainder = p_parameters . motion - safe * p_parameters . motion ;
r_result - > travel + = ( body_transform . get_origin ( ) - p_parameters . from . get_origin ( ) ) ;
2015-04-20 01:50:55 +02:00
}
collided = true ;
2018-11-15 01:17:36 +01:00
}
}
2015-04-20 01:50:55 +02:00
2018-11-15 01:17:36 +01:00
if ( ! collided & & r_result ) {
2021-09-30 20:28:57 +02:00
r_result - > travel = p_parameters . motion ;
2018-11-15 01:17:36 +01:00
r_result - > remainder = Vector2 ( ) ;
2021-09-30 20:28:57 +02:00
r_result - > travel + = ( body_transform . get_origin ( ) - p_parameters . from . get_origin ( ) ) ;
2015-04-20 01:50:55 +02:00
}
return collided ;
}
2014-02-19 15:57:14 +01:00
2022-02-04 17:46:10 +01:00
// Assumes a valid collision pair, this should have been checked beforehand in the BVH or octree.
2021-10-18 21:24:30 +02:00
void * GodotSpace2D : : _broadphase_pair ( GodotCollisionObject2D * A , int p_subindex_A , GodotCollisionObject2D * B , int p_subindex_B , void * p_self ) {
GodotCollisionObject2D : : Type type_A = A - > get_type ( ) ;
GodotCollisionObject2D : : Type type_B = B - > get_type ( ) ;
2014-02-19 15:57:14 +01:00
if ( type_A > type_B ) {
SWAP ( A , B ) ;
SWAP ( p_subindex_A , p_subindex_B ) ;
SWAP ( type_A , type_B ) ;
}
2022-04-05 12:40:26 +02:00
GodotSpace2D * self = static_cast < GodotSpace2D * > ( p_self ) ;
2014-09-03 04:13:40 +02:00
self - > collision_pairs + + ;
2014-02-19 15:57:14 +01:00
2021-10-18 21:24:30 +02:00
if ( type_A = = GodotCollisionObject2D : : TYPE_AREA ) {
GodotArea2D * area = static_cast < GodotArea2D * > ( A ) ;
if ( type_B = = GodotCollisionObject2D : : TYPE_AREA ) {
GodotArea2D * area_b = static_cast < GodotArea2D * > ( B ) ;
GodotArea2Pair2D * area2_pair = memnew ( GodotArea2Pair2D ( area_b , p_subindex_B , area , p_subindex_A ) ) ;
2015-03-17 04:45:25 +01:00
return area2_pair ;
} else {
2021-10-18 21:24:30 +02:00
GodotBody2D * body = static_cast < GodotBody2D * > ( B ) ;
GodotAreaPair2D * area_pair = memnew ( GodotAreaPair2D ( body , p_subindex_B , area , p_subindex_A ) ) ;
2015-03-17 04:45:25 +01:00
return area_pair ;
}
2014-02-19 15:57:14 +01:00
} else {
2022-04-05 12:40:26 +02:00
GodotBodyPair2D * b = memnew ( GodotBodyPair2D ( static_cast < GodotBody2D * > ( A ) , p_subindex_A , static_cast < GodotBody2D * > ( B ) , p_subindex_B ) ) ;
2014-02-19 15:57:14 +01:00
return b ;
}
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : _broadphase_unpair ( GodotCollisionObject2D * A , int p_subindex_A , GodotCollisionObject2D * B , int p_subindex_B , void * p_data , void * p_self ) {
2020-06-08 18:46:21 +02:00
if ( ! p_data ) {
return ;
}
2022-04-07 12:23:40 +02:00
GodotSpace2D * self = static_cast < GodotSpace2D * > ( p_self ) ;
2014-09-03 04:13:40 +02:00
self - > collision_pairs - - ;
2022-04-07 12:23:40 +02:00
GodotConstraint2D * c = static_cast < GodotConstraint2D * > ( p_data ) ;
2014-02-19 15:57:14 +01:00
memdelete ( c ) ;
}
2021-10-18 21:24:30 +02:00
const SelfList < GodotBody2D > : : List & GodotSpace2D : : get_active_body_list ( ) const {
2014-02-19 15:57:14 +01:00
return active_list ;
}
2020-05-14 14:29:06 +02:00
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : body_add_to_active_list ( SelfList < GodotBody2D > * p_body ) {
2014-02-19 15:57:14 +01:00
active_list . add ( p_body ) ;
}
2020-05-14 14:29:06 +02:00
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : body_remove_from_active_list ( SelfList < GodotBody2D > * p_body ) {
2014-02-19 15:57:14 +01:00
active_list . remove ( p_body ) ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : body_add_to_mass_properties_update_list ( SelfList < GodotBody2D > * p_body ) {
2021-06-11 02:37:19 +02:00
mass_properties_update_list . add ( p_body ) ;
2014-02-19 15:57:14 +01:00
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : body_remove_from_mass_properties_update_list ( SelfList < GodotBody2D > * p_body ) {
2021-06-11 02:37:19 +02:00
mass_properties_update_list . remove ( p_body ) ;
2014-02-19 15:57:14 +01:00
}
2021-10-18 21:24:30 +02:00
GodotBroadPhase2D * GodotSpace2D : : get_broadphase ( ) {
2014-02-19 15:57:14 +01:00
return broadphase ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : add_object ( GodotCollisionObject2D * p_object ) {
2014-02-19 15:57:14 +01:00
ERR_FAIL_COND ( objects . has ( p_object ) ) ;
objects . insert ( p_object ) ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : remove_object ( GodotCollisionObject2D * p_object ) {
2014-02-19 15:57:14 +01:00
ERR_FAIL_COND ( ! objects . has ( p_object ) ) ;
objects . erase ( p_object ) ;
}
2022-05-19 17:00:06 +02:00
const HashSet < GodotCollisionObject2D * > & GodotSpace2D : : get_objects ( ) const {
2014-02-19 15:57:14 +01:00
return objects ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : body_add_to_state_query_list ( SelfList < GodotBody2D > * p_body ) {
2014-02-19 15:57:14 +01:00
state_query_list . add ( p_body ) ;
}
2020-05-14 14:29:06 +02:00
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : body_remove_from_state_query_list ( SelfList < GodotBody2D > * p_body ) {
2014-02-19 15:57:14 +01:00
state_query_list . remove ( p_body ) ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : area_add_to_monitor_query_list ( SelfList < GodotArea2D > * p_area ) {
2014-02-19 15:57:14 +01:00
monitor_query_list . add ( p_area ) ;
}
2020-05-14 14:29:06 +02:00
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : area_remove_from_monitor_query_list ( SelfList < GodotArea2D > * p_area ) {
2014-02-19 15:57:14 +01:00
monitor_query_list . remove ( p_area ) ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : area_add_to_moved_list ( SelfList < GodotArea2D > * p_area ) {
2014-02-19 15:57:14 +01:00
area_moved_list . add ( p_area ) ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : area_remove_from_moved_list ( SelfList < GodotArea2D > * p_area ) {
2014-02-19 15:57:14 +01:00
area_moved_list . remove ( p_area ) ;
}
2021-10-18 21:24:30 +02:00
const SelfList < GodotArea2D > : : List & GodotSpace2D : : get_moved_area_list ( ) const {
2014-02-19 15:57:14 +01:00
return area_moved_list ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : call_queries ( ) {
2014-02-19 15:57:14 +01:00
while ( state_query_list . first ( ) ) {
2021-10-18 21:24:30 +02:00
GodotBody2D * b = state_query_list . first ( ) - > self ( ) ;
2014-02-19 15:57:14 +01:00
state_query_list . remove ( state_query_list . first ( ) ) ;
2017-11-10 12:31:25 +01:00
b - > call_queries ( ) ;
2014-02-19 15:57:14 +01:00
}
while ( monitor_query_list . first ( ) ) {
2021-10-18 21:24:30 +02:00
GodotArea2D * a = monitor_query_list . first ( ) - > self ( ) ;
2014-02-19 15:57:14 +01:00
monitor_query_list . remove ( monitor_query_list . first ( ) ) ;
2017-11-10 12:31:25 +01:00
a - > call_queries ( ) ;
2014-02-19 15:57:14 +01:00
}
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : setup ( ) {
2015-09-20 18:03:46 +02:00
contact_debug_count = 0 ;
2014-02-19 15:57:14 +01:00
2021-06-11 02:37:19 +02:00
while ( mass_properties_update_list . first ( ) ) {
mass_properties_update_list . first ( ) - > self ( ) - > update_mass_properties ( ) ;
mass_properties_update_list . remove ( mass_properties_update_list . first ( ) ) ;
2014-02-19 15:57:14 +01:00
}
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : update ( ) {
2014-02-19 15:57:14 +01:00
broadphase - > update ( ) ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : set_param ( PhysicsServer2D : : SpaceParameter p_param , real_t p_value ) {
2014-02-19 15:57:14 +01:00
switch ( p_param ) {
2020-05-10 13:00:47 +02:00
case PhysicsServer2D : : SPACE_PARAM_CONTACT_RECYCLE_RADIUS :
contact_recycle_radius = p_value ;
break ;
case PhysicsServer2D : : SPACE_PARAM_CONTACT_MAX_SEPARATION :
contact_max_separation = p_value ;
break ;
2021-12-03 18:38:40 +01:00
case PhysicsServer2D : : SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION :
2020-05-10 13:00:47 +02:00
contact_max_allowed_penetration = p_value ;
break ;
2021-12-03 18:38:40 +01:00
case PhysicsServer2D : : SPACE_PARAM_CONTACT_DEFAULT_BIAS :
contact_bias = p_value ;
break ;
2020-05-10 13:00:47 +02:00
case PhysicsServer2D : : SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD :
body_linear_velocity_sleep_threshold = p_value ;
break ;
case PhysicsServer2D : : SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD :
body_angular_velocity_sleep_threshold = p_value ;
break ;
case PhysicsServer2D : : SPACE_PARAM_BODY_TIME_TO_SLEEP :
body_time_to_sleep = p_value ;
break ;
case PhysicsServer2D : : SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS :
constraint_bias = p_value ;
break ;
2021-12-03 18:38:40 +01:00
case PhysicsServer2D : : SPACE_PARAM_SOLVER_ITERATIONS :
solver_iterations = p_value ;
break ;
2014-02-19 15:57:14 +01:00
}
}
2021-10-18 21:24:30 +02:00
real_t GodotSpace2D : : get_param ( PhysicsServer2D : : SpaceParameter p_param ) const {
2014-02-19 15:57:14 +01:00
switch ( p_param ) {
2020-05-10 13:00:47 +02:00
case PhysicsServer2D : : SPACE_PARAM_CONTACT_RECYCLE_RADIUS :
return contact_recycle_radius ;
case PhysicsServer2D : : SPACE_PARAM_CONTACT_MAX_SEPARATION :
return contact_max_separation ;
2021-12-03 18:38:40 +01:00
case PhysicsServer2D : : SPACE_PARAM_CONTACT_MAX_ALLOWED_PENETRATION :
2020-05-10 13:00:47 +02:00
return contact_max_allowed_penetration ;
2021-12-03 18:38:40 +01:00
case PhysicsServer2D : : SPACE_PARAM_CONTACT_DEFAULT_BIAS :
return contact_bias ;
2020-05-10 13:00:47 +02:00
case PhysicsServer2D : : SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_THRESHOLD :
return body_linear_velocity_sleep_threshold ;
case PhysicsServer2D : : SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD :
return body_angular_velocity_sleep_threshold ;
case PhysicsServer2D : : SPACE_PARAM_BODY_TIME_TO_SLEEP :
return body_time_to_sleep ;
case PhysicsServer2D : : SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS :
return constraint_bias ;
2021-12-03 18:38:40 +01:00
case PhysicsServer2D : : SPACE_PARAM_SOLVER_ITERATIONS :
return solver_iterations ;
2014-02-19 15:57:14 +01:00
}
return 0 ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : lock ( ) {
2014-02-19 15:57:14 +01:00
locked = true ;
}
2021-10-18 21:24:30 +02:00
void GodotSpace2D : : unlock ( ) {
2014-02-19 15:57:14 +01:00
locked = false ;
}
2021-10-18 21:24:30 +02:00
bool GodotSpace2D : : is_locked ( ) const {
2014-02-19 15:57:14 +01:00
return locked ;
}
2021-10-18 21:24:30 +02:00
GodotPhysicsDirectSpaceState2D * GodotSpace2D : : get_direct_state ( ) {
2014-02-19 15:57:14 +01:00
return direct_access ;
}
2021-10-18 21:24:30 +02:00
GodotSpace2D : : GodotSpace2D ( ) {
2023-01-31 00:01:21 +01:00
body_linear_velocity_sleep_threshold = GLOBAL_GET ( " physics/2d/sleep_threshold_linear " ) ;
body_angular_velocity_sleep_threshold = GLOBAL_GET ( " physics/2d/sleep_threshold_angular " ) ;
body_time_to_sleep = GLOBAL_GET ( " physics/2d/time_before_sleep " ) ;
solver_iterations = GLOBAL_GET ( " physics/2d/solver/solver_iterations " ) ;
contact_recycle_radius = GLOBAL_GET ( " physics/2d/solver/contact_recycle_radius " ) ;
contact_max_separation = GLOBAL_GET ( " physics/2d/solver/contact_max_separation " ) ;
contact_max_allowed_penetration = GLOBAL_GET ( " physics/2d/solver/contact_max_allowed_penetration " ) ;
contact_bias = GLOBAL_GET ( " physics/2d/solver/default_contact_bias " ) ;
constraint_bias = GLOBAL_GET ( " physics/2d/solver/default_constraint_bias " ) ;
2021-12-07 02:10:13 +01:00
2021-10-18 21:24:30 +02:00
broadphase = GodotBroadPhase2D : : create_func ( ) ;
2014-02-19 15:57:14 +01:00
broadphase - > set_pair_callback ( _broadphase_pair , this ) ;
broadphase - > set_unpair_callback ( _broadphase_unpair , this ) ;
2015-09-20 18:03:46 +02:00
2021-10-18 21:24:30 +02:00
direct_access = memnew ( GodotPhysicsDirectSpaceState2D ) ;
2014-02-19 15:57:14 +01:00
direct_access - > space = this ;
}
2021-10-18 21:24:30 +02:00
GodotSpace2D : : ~ GodotSpace2D ( ) {
2014-02-19 15:57:14 +01:00
memdelete ( broadphase ) ;
memdelete ( direct_access ) ;
}