Esempio n. 1
0
RID DampedSpringJoint2D::_configure_joint() {

	Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
	Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;

	if (!node_a || !node_b)
		return RID();

	PhysicsBody2D *body_a = node_a->cast_to<PhysicsBody2D>();
	PhysicsBody2D *body_b = node_b->cast_to<PhysicsBody2D>();

	if (!body_a || !body_b)
		return RID();

	if (get_exclude_nodes_from_collision())
		Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
	else
		Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid());

	Transform2D gt = get_global_transform();
	Vector2 anchor_A = gt.get_origin();
	Vector2 anchor_B = gt.xform(Vector2(0, length));

	RID dsj = Physics2DServer::get_singleton()->damped_spring_joint_create(anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid());
	if (rest_length)
		Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_REST_LENGTH, rest_length);
	Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_STIFFNESS, stiffness);
	Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_DAMPING, damping);

	return dsj;
}
Esempio n. 2
0
bool CollisionSolver2DSW::solve_raycast(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis) {

	const RayShape2DSW *ray = static_cast<const RayShape2DSW *>(p_shape_A);
	if (p_shape_B->get_type() == Physics2DServer::SHAPE_RAY)
		return false;

	Vector2 from = p_transform_A.get_origin();
	Vector2 to = from + p_transform_A[1] * ray->get_length();
	Vector2 support_A = to;

	Transform2D invb = p_transform_B.affine_inverse();
	from = invb.xform(from);
	to = invb.xform(to);

	Vector2 p, n;
	if (!p_shape_B->intersect_segment(from, to, p, n)) {

		if (sep_axis)
			*sep_axis = p_transform_A[1].normalized();
		return false;
	}

	Vector2 support_B = p_transform_B.xform(p);

	if (p_result_callback) {
		if (p_swap_result)
			p_result_callback(support_B, support_A, p_userdata);
		else
			p_result_callback(support_A, support_B, p_userdata);
	}
	return true;
}
Esempio n. 3
0
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;
	}
}
Esempio n. 4
0
RID GrooveJoint2D::_configure_joint() {

	Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL;
	Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL;

	if (!node_a || !node_b)
		return RID();

	PhysicsBody2D *body_a = node_a->cast_to<PhysicsBody2D>();
	PhysicsBody2D *body_b = node_b->cast_to<PhysicsBody2D>();

	if (!body_a || !body_b)
		return RID();

	if (get_exclude_nodes_from_collision())
		Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
	else
		Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(), body_b->get_rid());

	Transform2D gt = get_global_transform();
	Vector2 groove_A1 = gt.get_origin();
	Vector2 groove_A2 = gt.xform(Vector2(0, length));
	Vector2 anchor_B = gt.xform(Vector2(0, initial_offset));

	return Physics2DServer::get_singleton()->groove_joint_create(groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid());
}
Esempio n. 5
0
RID GrooveJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {

	Transform2D gt = get_global_transform();
	Vector2 groove_A1 = gt.get_origin();
	Vector2 groove_A2 = gt.xform(Vector2(0, length));
	Vector2 anchor_B = gt.xform(Vector2(0, initial_offset));

	return Physics2DServer::get_singleton()->groove_joint_create(groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid());
}
Esempio n. 6
0
RID DampedSpringJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) {

	Transform2D gt = get_global_transform();
	Vector2 anchor_A = gt.get_origin();
	Vector2 anchor_B = gt.xform(Vector2(0, length));

	RID dsj = Physics2DServer::get_singleton()->damped_spring_joint_create(anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid());
	if (rest_length)
		Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_REST_LENGTH, rest_length);
	Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_STIFFNESS, stiffness);
	Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj, Physics2DServer::DAMPED_STRING_DAMPING, damping);

	return dsj;
}
Esempio n. 7
0
bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) {

	const ConcaveShape2DSW *concave_B = static_cast<const ConcaveShape2DSW *>(p_shape_B);

	_ConcaveCollisionInfo2D cinfo;
	cinfo.transform_A = &p_transform_A;
	cinfo.shape_A = p_shape_A;
	cinfo.transform_B = &p_transform_B;
	cinfo.motion_A = p_motion_A;
	cinfo.result_callback = p_result_callback;
	cinfo.userdata = p_userdata;
	cinfo.swap_result = p_swap_result;
	cinfo.collided = false;
	cinfo.collisions = 0;
	cinfo.sep_axis = sep_axis;
	cinfo.margin_A = p_margin_A;
	cinfo.margin_B = p_margin_B;

	cinfo.aabb_tests = 0;

	Transform2D rel_transform = p_transform_A;
	rel_transform.elements[2] -= p_transform_B.get_origin();

	//quickly compute a local Rect2

	Rect2 local_aabb;
	for (int i = 0; i < 2; i++) {

		Vector2 axis(p_transform_B.elements[i]);
		real_t axis_scale = 1.0 / axis.length();
		axis *= axis_scale;

		real_t smin, smax;
		p_shape_A->project_rangev(axis, rel_transform, smin, smax);
		smin *= axis_scale;
		smax *= axis_scale;

		local_aabb.position[i] = smin;
		local_aabb.size[i] = smax - smin;
	}

	concave_B->cull(local_aabb, concave_callback, &cinfo);

	//print_line("Rect2 TESTS: "+itos(cinfo.aabb_tests));
	return cinfo.collided;
}
Esempio n. 8
0
bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t 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..

	if (r_result) {
		r_result->collider_id = 0;
		r_result->collider_shape = 0;
	}
	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));
	}

	// Undo the currently transform the physics server is aware of and apply the provided one
	body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb));
	body_aabb = body_aabb.grow(p_margin);

	Transform2D body_transform = p_from;

	{
		//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;

			Physics2DServerSW::CollCbkData *cbkptr = &cbk;
			CollisionSolver2DSW::CallbackResult 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_disabled(j))
					continue;

				Transform2D 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->is_shape_set_as_one_way_collision(shape_idx)) {

						cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
						cbk.valid_depth = p_margin; //only valid depth is the collision margin
					} 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];

#if 0
				Vector2 rel = b-a;
				real_t d = rel.length();
				if (d==0)
					continue;

				Vector2 n = rel/d;
				real_t traveled = n.dot(recover_motion);
				a+=n*traveled;

				real_t d = a.distance_to(b);
				if (d<margin)
					continue;
#endif
				recover_motion += (b - a) * 0.4;
			}

			if (recover_motion == Vector2()) {
				collided = false;
				break;
			}

			body_transform.elements[2] += recover_motion;
			body_aabb.position += recover_motion;

			recover_attempts--;

		} while (recover_attempts);
	}

	real_t safe = 1.0;
	real_t unsafe = 1.0;
	int best_shape = -1;

	{
		// STEP 2 ATTEMPT MOTION

		Rect2 motion_aabb = body_aabb;
		motion_aabb.position += 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_disabled(j))
				continue;

			Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
			Shape2DSW *body_shape = p_body->get_shape(j);

			bool stuck = false;

			real_t best_safe = 1;
			real_t 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];

				Transform2D 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->is_shape_set_as_one_way_collision(j)) {
						continue;
					}

					stuck = true;
					break;
				}

				//just do kinematic solving
				real_t low = 0;
				real_t hi = 1;
				Vector2 mnormal = p_motion.normalized();

				for (int k = 0; k < 8; k++) { //steps should be customizable..

					real_t 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->is_shape_set_as_one_way_collision(j)) {

					Vector2 cd[2];
					Physics2DServerSW::CollCbkData cbk;
					cbk.max = 1;
					cbk.amount = 0;
					cbk.ptr = cd;
					cbk.valid_dir = body_shape_xform.get_axis(1).normalized();
					;
					cbk.valid_depth = 10e20;

					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;
			r_result->remainder = Vector2();
			r_result->motion += (body_transform.get_origin() - p_from.get_origin());
		}

	} else {

		//it collided, let's get the rest info in unsafe advance
		Transform2D ugt = body_transform;
		ugt.elements[2] += p_motion * unsafe;

		_RestCallbackData2D rcd;
		rcd.best_len = 0;
		rcd.best_object = NULL;
		rcd.best_shape = 0;

		Transform2D body_shape_xform = ugt * p_body->get_shape_transform(best_shape);
		Shape2DSW *body_shape = p_body->get_shape(best_shape);

		body_aabb.position += 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->is_shape_set_as_one_way_collision(shape_idx)) {

				rcd.valid_dir = body_shape_xform.get_axis(1).normalized();
				rcd.valid_depth = 10e20;
			} 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_local_shape = 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;
				r_result->remainder = p_motion - safe * p_motion;
				r_result->motion += (body_transform.get_origin() - p_from.get_origin());
			}

			collided = true;
		} else {
			if (r_result) {

				r_result->motion = p_motion;
				r_result->remainder = Vector2();
				r_result->motion += (body_transform.get_origin() - p_from.get_origin());
			}

			collided = false;
		}
	}

	return collided;
}
Esempio n. 9
0
void Body2DSW::update_inertias() {

	//update shapes and motions

	switch (mode) {

		case Physics2DServer::BODY_MODE_RIGID: {

			if (user_inertia) break;

			//update tensor for allshapes, not the best way but should be somehow OK. (inspired from bullet)
			real_t total_area = 0;

			for (int i = 0; i < get_shape_count(); i++) {

				total_area += get_shape_aabb(i).get_area();
			}

			real_t _inertia = 0;

			for (int i = 0; i < get_shape_count(); i++) {

				const Shape2DSW *shape = get_shape(i);

				real_t area = get_shape_aabb(i).get_area();

				real_t mass = area * this->mass / total_area;

				Transform2D mtx = get_shape_transform(i);
				Vector2 scale = mtx.get_scale();
				_inertia += shape->get_moment_of_inertia(mass, scale) + mass * mtx.get_origin().length_squared();
				//Rect2 ab = get_shape_aabb(i);
				//_inertia+=mass*ab.size.dot(ab.size)/12.0f;
			}

			if (_inertia != 0)
				_inv_inertia = 1.0 / _inertia;
			else
				_inv_inertia = 0.0; //wathever

			if (mass)
				_inv_mass = 1.0 / mass;
			else
				_inv_mass = 0;

		} break;
		case Physics2DServer::BODY_MODE_KINEMATIC:
		case Physics2DServer::BODY_MODE_STATIC: {

			_inv_inertia = 0;
			_inv_mass = 0;
		} break;
		case Physics2DServer::BODY_MODE_CHARACTER: {

			_inv_inertia = 0;
			_inv_mass = 1.0 / mass;

		} break;
	}
	//_update_inertia_tensor();

	//_update_shapes();
}