fixed collision detection that go over world boundaries
parent
1687b657d4
commit
8daee27ed8
|
@ -145,7 +145,12 @@ int main (int argc, char* argv[]) {
|
|||
SDL_WM_SetCaption("Asteroids -BETA1-","Asteroids -BETA 1-");
|
||||
|
||||
engine.GetView()->SetGridSize (8,8);
|
||||
|
||||
/// \todo get rid of the world settings in asteroids
|
||||
dynamic_cast<asteroids::Physics*>(engine.GetPhysics())->SetWorldSize (26, 20);
|
||||
engine.GetPhysics()->SetWorldBounds (vector3d (-13, 0, -10), vector3d (13, 0, 10));
|
||||
engine.GetPhysics()->EnableWorldWarp(Engine::PhysicsBase::WorldWarpModeX);
|
||||
engine.GetPhysics()->EnableWorldWarp(Engine::PhysicsBase::WorldWarpModeZ);
|
||||
|
||||
// run the default commands and load the configuration
|
||||
Engine::RunCommand ("exec asteroids.rc");
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace Engine {
|
|||
int PhysicsBase::OnInit (int argc, char* argv[]) {
|
||||
LogDebug ("Physics Init");
|
||||
mEntities.clear ();
|
||||
mWorldMin.setValues (-0.5, -0.5, -0.5);
|
||||
mWorldMax.setValues (0.5, 0.5, 0.5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -254,6 +256,7 @@ bool PhysicsBase::CalcNextCollision (
|
|||
if (coll2d_result == 0) {
|
||||
// Now we have to check whether a warp is required
|
||||
vector3d warp_directions = CheckEntityWarp (entity_a, stepsize);
|
||||
|
||||
if (warp_directions.length2() == 0.) {
|
||||
// If none is reported for entity_a we still have to check whether we might have
|
||||
// to warp entity_b. If so, we have to negate the warp_direction as
|
||||
|
@ -267,6 +270,7 @@ bool PhysicsBase::CalcNextCollision (
|
|||
// if a valid warp direction was found we perform the checks at
|
||||
// the warped positions
|
||||
if (warp_directions.length2() != 0.) {
|
||||
// LogMessage ("doing some warping: %f, %f, %f", warp_directions[0], warp_directions[1], warp_directions[2]);
|
||||
coll2d_result = PerformWarpedCollisionChecks (stepsize, entity_a, entity_b, warp_directions, temp_info);
|
||||
}
|
||||
}
|
||||
|
@ -299,16 +303,67 @@ int PhysicsBase::PerformWarpedCollisionChecks (float stepsize, EntityPhysicState
|
|||
int coll2d_result = 0;
|
||||
|
||||
vector3d entity_original_pos = entity_a->mPosition;
|
||||
vector3d test_warp;
|
||||
|
||||
vector3d test_warp(warp_directions[0], 0., 0.);
|
||||
LogMessage ("warping position %f, %f, %f", test_warp[0], test_warp[1], test_warp[2]);
|
||||
entity_a->mPosition += test_warp;
|
||||
// LogMessage ("warping directions %f, %f, %f ids %d, %d", warp_directions[0], warp_directions[1], warp_directions[2], entity_a->mId, entity_b->mId);
|
||||
|
||||
// check for along 1, 0, 0
|
||||
if (warp_directions[0] != 0.) {
|
||||
test_warp.setValues(warp_directions[0], 0., 0.);
|
||||
// LogMessage ("warping position %f, %f, %f", test_warp[0], test_warp[1], test_warp[2]);
|
||||
entity_a->mPosition += test_warp;
|
||||
entity_a->UpdateShape();
|
||||
coll2d_result = coll2d::check_collision (stepsize, entity_a->mShape, entity_b->mShape, &info);
|
||||
// LogMessage ("collision result = %d", coll2d_result);
|
||||
|
||||
if (coll2d_result) {
|
||||
// reset the entity
|
||||
entity_a->mPosition = entity_original_pos;
|
||||
entity_a->UpdateShape();
|
||||
return coll2d_result;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the entity
|
||||
entity_a->mPosition = entity_original_pos;
|
||||
entity_a->UpdateShape();
|
||||
coll2d_result = coll2d::check_collision (stepsize, entity_a->mShape, entity_b->mShape, &info);
|
||||
LogMessage ("collision result = %d", coll2d_result);
|
||||
|
||||
if (coll2d_result == 0) {
|
||||
test_warp.setValues (warp_directions[0], warp_directions[1], 0.);
|
||||
// check along 0, 0, 1
|
||||
if (warp_directions[2] != 0.) {
|
||||
test_warp.setValues(0, 0, warp_directions[2]);
|
||||
// LogMessage ("warping position %f, %f, %f", test_warp[0], test_warp[1], test_warp[2]);
|
||||
entity_a->mPosition += test_warp;
|
||||
entity_a->UpdateShape();
|
||||
coll2d_result = coll2d::check_collision (stepsize, entity_a->mShape, entity_b->mShape, &info);
|
||||
// LogMessage ("collision result = %d", coll2d_result);
|
||||
|
||||
if (coll2d_result) {
|
||||
// reset the entity
|
||||
entity_a->mPosition = entity_original_pos;
|
||||
entity_a->UpdateShape();
|
||||
return coll2d_result;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the entity
|
||||
entity_a->mPosition = entity_original_pos;
|
||||
entity_a->UpdateShape();
|
||||
|
||||
// check along 1, 0, 1
|
||||
if (warp_directions[0] != 0. && warp_directions[2] != 0.) {
|
||||
test_warp.setValues(warp_directions[0], 0, warp_directions[2]);
|
||||
// LogMessage ("warping position %f, %f, %f", test_warp[0], test_warp[1], test_warp[2]);
|
||||
entity_a->mPosition += test_warp;
|
||||
entity_a->UpdateShape();
|
||||
coll2d_result = coll2d::check_collision (stepsize, entity_a->mShape, entity_b->mShape, &info);
|
||||
// LogMessage ("collision result = %d", coll2d_result);
|
||||
|
||||
if (coll2d_result) {
|
||||
// reset the entity
|
||||
entity_a->mPosition = entity_original_pos;
|
||||
entity_a->UpdateShape();
|
||||
return coll2d_result;
|
||||
}
|
||||
}
|
||||
|
||||
// reset the entity
|
||||
|
@ -583,15 +638,42 @@ vector3d PhysicsBase::CheckEntityWarp (EntityPhysicState* entity, float stepsize
|
|||
result += vector3d (world_size[0], 0., 0.);
|
||||
}
|
||||
|
||||
// then we check whether the entity overlaps at its final destination
|
||||
test_dir.setValues (1., 0., 0.);
|
||||
test_pos = entity->mPosition + test_dir * bounding_sphere_radius + entity->mVelocity * stepsize;
|
||||
if (test_pos[0] > mWorldMax[0])
|
||||
result += vector3d (-world_size[0], 0., 0.);
|
||||
if (result[0] == 0.) {
|
||||
// then we check whether the entity overlaps at its final destination
|
||||
test_dir.setValues (1., 0., 0.);
|
||||
test_pos = entity->mPosition + test_dir * bounding_sphere_radius + entity->mVelocity * stepsize;
|
||||
if (test_pos[0] > mWorldMax[0])
|
||||
result += vector3d (-world_size[0], 0., 0.);
|
||||
else {
|
||||
test_pos = entity->mPosition - test_dir * bounding_sphere_radius + entity->mVelocity * stepsize;
|
||||
if (test_pos[0] < mWorldMin[0])
|
||||
result += vector3d (world_size[0], 0., 0.);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mWorldWarp.test(WorldWarpModeZ)) {
|
||||
vector3d test_dir (0., 0., 1.);
|
||||
vector3d test_pos = entity->mPosition + test_dir * bounding_sphere_radius;
|
||||
if (test_pos[2] > mWorldMax[2])
|
||||
result += vector3d (0, 0., -world_size[2]);
|
||||
else {
|
||||
test_pos = entity->mPosition - test_dir * bounding_sphere_radius + entity->mVelocity * stepsize;
|
||||
if (test_pos[0] < mWorldMin[0])
|
||||
result += vector3d (world_size[0], 0., 0.);
|
||||
test_pos = entity->mPosition - test_dir * bounding_sphere_radius;
|
||||
if (test_pos[2] < mWorldMin[2])
|
||||
result += vector3d (0, 0., world_size[2]);
|
||||
}
|
||||
|
||||
if (result[2] == 0.) {
|
||||
// then we check whether the entity overlaps at its final destination
|
||||
test_dir.setValues (0., 0., 1.);
|
||||
test_pos = entity->mPosition + test_dir * bounding_sphere_radius + entity->mVelocity * stepsize;
|
||||
if (test_pos[2] > mWorldMax[2])
|
||||
result += vector3d (0, 0, -world_size[2]);
|
||||
else {
|
||||
test_pos = entity->mPosition - test_dir * bounding_sphere_radius + entity->mVelocity * stepsize;
|
||||
if (test_pos[2] < mWorldMin[2])
|
||||
result += vector3d (0, 0, world_size[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,17 +43,22 @@ class PhysicsBase : public Module {
|
|||
unsigned int &incidence_entity_id,
|
||||
coll2d::CollisionInfo &info);
|
||||
|
||||
/** \brief Modes for warping entities when they reach the world boundaries */
|
||||
/** \brief Modes for warping entities when they reach the world boundaries
|
||||
*
|
||||
* \todo add entity warping along the y direction
|
||||
*
|
||||
* */
|
||||
enum WorldWarp {
|
||||
WorldWarpModeX = 0,
|
||||
WorldWarpModeY,
|
||||
WorldWarpModeZ,
|
||||
WorldWarpModeLast
|
||||
};
|
||||
|
||||
/** \brief Enables wrapping of entities at the given world boundary */
|
||||
void EnableWorldWarp (WorldWarp mode) {
|
||||
mWorldWarp.set(mode, true);
|
||||
}
|
||||
/** \brief Disables wrapping of entities at the given world boundary */
|
||||
void DisableWorldWarp (WorldWarp mode) {
|
||||
mWorldWarp.set(mode, false);
|
||||
}
|
||||
|
@ -64,6 +69,12 @@ class PhysicsBase : public Module {
|
|||
mWorldMax = max_bound;
|
||||
}
|
||||
|
||||
/** \brief Returns the boundaries for the world */
|
||||
void GetWorldBounds (vector3d &min_bound, vector3d &max_bound) {
|
||||
min_bound = mWorldMin;
|
||||
max_bound = mWorldMax;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** \brief Initializes the system */
|
||||
virtual int OnInit (int argc, char* argv[]);
|
||||
|
@ -117,9 +128,15 @@ class PhysicsBase : public Module {
|
|||
bool HandleColl2dError (int coll2d_result, float stepsize,
|
||||
EntityPhysicState* entity_a, EntityPhysicState* entity_b, coll2d::CollisionInfo &info);
|
||||
|
||||
/** \brief Contains information for which boundaries there should be an entity warp
|
||||
*/
|
||||
std::bitset<WorldWarpModeLast> mWorldWarp;
|
||||
|
||||
/** \brief Lower bound of the world coordinates
|
||||
*/
|
||||
vector3d mWorldMin;
|
||||
/** \brief Upper bound of the world coordinates
|
||||
*/
|
||||
vector3d mWorldMax;
|
||||
};
|
||||
|
||||
|
|
|
@ -72,7 +72,6 @@
|
|||
* todos within the code have a look at the \ref todo.
|
||||
*
|
||||
* \todo [high] Create a simple racing or asteroids game
|
||||
* \todo [high] fix collisions that go over boundaries
|
||||
* \todo [med] disallow or fix resize of the game window
|
||||
*
|
||||
* These are the (for now) postponed todos:
|
||||
|
@ -92,6 +91,7 @@
|
|||
* Engine::Module::Init()
|
||||
*
|
||||
* Done:
|
||||
* \todo [high] (01-02-2011) fix collisions that go over boundaries
|
||||
* \todo [med] (30-01-2011) add Engine::GUI::CheckKeyPressed that checks for completed key presses
|
||||
* \todo [med] (30-01-2011) fix LineEdit input which generates blanks when entering backspace for an empty edit
|
||||
* \todo [high] (30-01-2011) fix random crashes for certain characters (has to do with boundary box computation in OGLFT) fix: disabled debug assertion for proper boundary box merging.
|
||||
|
|
|
@ -81,23 +81,24 @@ TEST_FIXTURE (PhysicsFixture, PhysicsTestWarpCollisionX ) {
|
|||
|
||||
float actor_radius = dynamic_cast<coll2d::Sphere*>(actor_entity->mShape)->getRadius();
|
||||
// actor_entity->mPosition = vector3d (-world_size + actor_radius + 0.01 + 2 * world_size, 0., world_size - actor_radius);
|
||||
actor_entity->mPosition = vector3d (-world_size + actor_radius + 0.01, 0., world_size - actor_radius);
|
||||
actor_entity->mPosition = vector3d (-world_size + actor_radius + 0.01, 0., 0.);
|
||||
actor_entity->mVelocity = vector3d (-1., 0., 0.);
|
||||
|
||||
actor_2_entity->mPosition = vector3d (world_size - actor_radius - 0.01, 0., world_size - actor_radius);
|
||||
actor_2_entity->mPosition = vector3d (world_size - actor_radius - 0.01, 0., 0.);
|
||||
actor_2_entity->mVelocity = vector3d (0., 0., 0.);
|
||||
|
||||
bool coll_res = false;
|
||||
coll2d::CollisionInfo info;
|
||||
unsigned int reference_id, incidence_id;
|
||||
|
||||
// with disabled world warp, there should not be a collision ...
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeX);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., actor_entity->mId, actor_2_entity->mId, info);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (!coll_res);
|
||||
|
||||
// ... however with WorldWarp enabled, there should be!
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeX);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., actor_entity->mId, actor_2_entity->mId, info);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (coll_res);
|
||||
|
||||
// Now we change the velocities and let actor_2 move out of the maximum x
|
||||
|
@ -107,12 +108,116 @@ TEST_FIXTURE (PhysicsFixture, PhysicsTestWarpCollisionX ) {
|
|||
|
||||
// with disabled world warp, there should not be a collision ...
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeX);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., actor_entity->mId, actor_2_entity->mId, info);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (!coll_res);
|
||||
|
||||
// ... however with WorldWarp enabled, there should be!
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeX);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., actor_entity->mId, actor_2_entity->mId, info);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (coll_res);
|
||||
}
|
||||
|
||||
TEST_FIXTURE (PhysicsFixture, PhysicsTestWarpCollisionZ ) {
|
||||
float world_size = 10;
|
||||
PhysicsModule.SetWorldBounds (
|
||||
vector3d (-world_size, -world_size, -world_size),
|
||||
vector3d (world_size, world_size, world_size)
|
||||
);
|
||||
|
||||
EntityPhysicState* actor_2_entity = CreateEntityPhysicState (EntityBaseTypeActor, 4);
|
||||
assert (actor_2_entity->mShape);
|
||||
assert (actor_entity->mShape);
|
||||
|
||||
PhysicsModule.RegisterEntity (actor_2_entity);
|
||||
|
||||
float actor_radius = dynamic_cast<coll2d::Sphere*>(actor_entity->mShape)->getRadius();
|
||||
// actor_entity->mPosition = vector3d (-world_size + actor_radius + 0.01 + 2 * world_size, 0., world_size - actor_radius);
|
||||
actor_entity->mPosition = vector3d (0, 0, -world_size + actor_radius + 0.01);
|
||||
actor_entity->mVelocity = vector3d (0., 0., -1.);
|
||||
|
||||
actor_2_entity->mPosition = vector3d (0, 0, world_size - actor_radius - 0.01);
|
||||
actor_2_entity->mVelocity = vector3d (0., 0., 1.);
|
||||
|
||||
bool coll_res = false;
|
||||
coll2d::CollisionInfo info;
|
||||
unsigned int reference_id, incidence_id;
|
||||
|
||||
// with disabled world warp, there should not be a collision ...
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (!coll_res);
|
||||
|
||||
// ... however with WorldWarp enabled, there should be!
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (coll_res);
|
||||
|
||||
// Now we change the velocities and let actor_2 move out of the maximum x
|
||||
// direction
|
||||
actor_entity->mVelocity = vector3d (0., 0., -1.);
|
||||
actor_2_entity->mVelocity = vector3d (0., 0., 0.);
|
||||
|
||||
// with disabled world warp, there should not be a collision ...
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (!coll_res);
|
||||
|
||||
// ... however with WorldWarp enabled, there should be!
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (coll_res);
|
||||
}
|
||||
|
||||
TEST_FIXTURE (PhysicsFixture, PhysicsTestWarpCollisionXZ ) {
|
||||
float world_size = 10;
|
||||
PhysicsModule.SetWorldBounds (
|
||||
vector3d (-world_size, -world_size, -world_size),
|
||||
vector3d (world_size, world_size, world_size)
|
||||
);
|
||||
|
||||
EntityPhysicState* actor_2_entity = CreateEntityPhysicState (EntityBaseTypeActor, 4);
|
||||
assert (actor_2_entity->mShape);
|
||||
assert (actor_entity->mShape);
|
||||
|
||||
PhysicsModule.RegisterEntity (actor_2_entity);
|
||||
|
||||
float actor_radius = dynamic_cast<coll2d::Sphere*>(actor_entity->mShape)->getRadius();
|
||||
actor_entity->mPosition = vector3d (- world_size + actor_radius + 0.01, 0, -world_size + actor_radius + 0.01);
|
||||
actor_entity->mVelocity = vector3d (-1., 0., -1.);
|
||||
|
||||
actor_2_entity->mPosition = vector3d (world_size - actor_radius - 0.01, 0, world_size - actor_radius - 0.01);
|
||||
actor_2_entity->mVelocity = vector3d (0., 0., 0.);
|
||||
|
||||
bool coll_res = false;
|
||||
coll2d::CollisionInfo info;
|
||||
unsigned int reference_id, incidence_id;
|
||||
|
||||
// with disabled world warp, there should not be a collision ...
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeX);
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (!coll_res);
|
||||
|
||||
// ... however with WorldWarp enabled, there should be!
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeX);
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (coll_res);
|
||||
|
||||
// Now we change the velocities and let actor_2 move out of the maximum x
|
||||
// direction
|
||||
actor_entity->mVelocity = vector3d (0., 0., 0.);
|
||||
actor_2_entity->mVelocity = vector3d (1., 0., 1.);
|
||||
|
||||
// with disabled world warp, there should not be a collision ...
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeX);
|
||||
PhysicsModule.DisableWorldWarp(PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (!coll_res);
|
||||
|
||||
// ... however with WorldWarp enabled, there should be!
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeX);
|
||||
PhysicsModule.EnableWorldWarp (PhysicsBase::WorldWarpModeZ);
|
||||
coll_res = PhysicsModule.CalcNextCollision (1., reference_id, incidence_id, info);
|
||||
CHECK (coll_res);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue