w00t narrowed ghost bug to subregions of CollisionRegion, eliminated them, and implemented much more efficient collision group finding routines

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@495 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Giles Williams 2006-04-26 09:41:56 +00:00
parent 7543d5db37
commit 0037ef4493
8 changed files with 218 additions and 37 deletions

View File

@ -309,7 +309,7 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
Entity *e1,*e2;
Vector p1, p2;
double dist2, r1, r2, r0, min_dist2;
int i,j;
int i;
Entity* entities_to_test[n_entities];
//
@ -323,9 +323,14 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
for (i = 0; i < n_entities; i++)
{
e1 = entity_array[i];
if (!e1->collisionTestFilter)
if (!(e1->collisionTestFilter))
entities_to_test[n_entities_to_test++] = e1;
}
if (debug)
NSLog(@"\nDEBUG in collision region %@ testing %d out of %d entities", self, n_entities_to_test, n_entities);
if (n_entities_to_test < 2)
return;
@ -350,26 +355,30 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
[(CollisionRegion*)[subregions objectAtIndex: i] findCollisionsInUniverse: universe];
//
// test each entity in this region against the others
// test each entity in this region against the entities in its collision chain
//
for (i = 0; i < n_entities_to_test; i++)
{
e1 = entities_to_test[i];
p1 = e1->position;
r1 = e1->collision_radius;
for (j = i + 1; j < n_entities_to_test; j++)
// check against the first in the collision chain
e2 = e1->collision_chain;
while (e2)
{
e2 = entities_to_test[j];
if (debug)
{
debug = NO;
NSLog(@"DEBUG Testing collision between %@ and %@", e1, e2);
debug = YES;
}
p2 = e2->position;
r2 = e2->collision_radius;
r0 = r1 + r2;
p2.x -= p1.x; p2.y -= p1.y; p2.z -= p1.z;
if ((p2.x > r0)||(p2.x < -r0)) // test for simple x distance
continue; // next j
if ((p2.y > r0)||(p2.y < -r0)) // test for simple y distance
continue; // next j
if ((p2.z > r0)||(p2.z < -r0)) // test for simple z distance
continue; // next j
dist2 = p2.x*p2.x + p2.y*p2.y + p2.z*p2.z;
min_dist2 = r0 * r0;
if (dist2 < PROXIMITY_WARN_DISTANCE2 * min_dist2)
@ -419,6 +428,8 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
}
}
}
// check the next in the collision chain
e2 = e2->collision_chain;
}
}
}

View File

@ -76,7 +76,7 @@ Your fair use and other rights are in no way affected by the above.
//
displayListName = 0;
//
status = STATUS_TEST;
status = STATUS_ACTIVE;
//
return self;
}

View File

@ -190,12 +190,13 @@ extern int debug;
int status;
//
int zero_index;
// int x_index, y_index, z_index;
BOOL collisionTestFilter;
// replace x_index etc. with linked lists..
Entity *x_previous, *x_next;
Entity *y_previous, *y_next;
Entity *z_previous, *z_next;
//
Entity *collision_chain;
//
// experimental lighting:

View File

@ -292,6 +292,8 @@ static Universe *data_store_universe;
y_next = y_previous = nil;
z_next = z_previous = nil;
//
collision_chain = nil;
//
return self;
}
@ -1789,7 +1791,7 @@ static Universe *data_store_universe;
- (BoundingBox) findBoundingBoxRelativeToPosition:(Vector)opv InVectors:(Vector) _i :(Vector) _j :(Vector) _k
{
NSLog(@"DEBUG ** DEPRECATED [Entity findBoundingBoxRelativeToPosition:(Vector)opv InVectors:(Vector) _i :(Vector) _j :(Vector) _k] CALLED **");
// NSLog(@"DEBUG ** DEPRECATED [Entity findBoundingBoxRelativeToPosition:(Vector)opv InVectors:(Vector) _i :(Vector) _j :(Vector) _k] CALLED **");
Vector pv, rv;
Vector rpos = position;

View File

@ -886,7 +886,10 @@ static NSTimeInterval time_last_frame;
if ([gameView isDown:48])// look for the '0' key
{
if (!cloak_pressed)
{
[universe obj_dump]; // dump objects
debug = !debug;
}
cloak_pressed = YES;
}
else

View File

@ -1015,7 +1015,7 @@ static Quaternion quaternion_identity = { (GLfloat)1.0, (GLfloat)0.0, (GLfloat)0
//
displayListName = 0;
//
status = STATUS_TEST;
status = STATUS_ACTIVE;
//
shield_booster = 1;
shield_enhancer = 0;

View File

@ -299,13 +299,62 @@ NSString* describeBehaviour(int some_behaviour)
return @"** BEHAVIOUR UNKNOWN **";
}
NSString* describeStatus(int some_status)
{
switch(some_status)
{
case STATUS_AUTOPILOT_ENGAGED :
return @"STATUS_AUTOPILOT_ENGAGED";
case STATUS_DEAD :
return @"STATUS_DEAD";
case STATUS_START_GAME :
return @"STATUS_START_GAME";
case STATUS_DEMO :
return @"STATUS_DEMO";
case STATUS_DOCKING :
return @"STATUS_DOCKING";
case STATUS_DOCKED :
return @"STATUS_DOCKED";
case STATUS_EFFECT :
return @"STATUS_EFFECT";
case STATUS_ENTERING_WITCHSPACE :
return @"STATUS_ENTERING_WITCHSPACE";
case STATUS_ESCAPE_SEQUENCE :
return @"STATUS_ESCAPE_SEQUENCE";
case STATUS_EXITING_WITCHSPACE :
return @"STATUS_EXITING_WITCHSPACE";
case STATUS_EXPERIMENTAL :
return @"STATUS_EXPERIMENTAL";
case STATUS_IN_FLIGHT :
return @"STATUS_IN_FLIGHT";
case STATUS_IN_HOLD :
return @"STATUS_IN_HOLD";
case STATUS_INACTIVE :
return @"STATUS_INACTIVE";
case STATUS_LAUNCHING :
return @"STATUS_LAUNCHING";
case STATUS_TEST :
return @"STATUS_TEST";
case STATUS_WITCHSPACE_COUNTDOWN :
return @"STATUS_WITCHSPACE_COUNTDOWN";
}
return @"** STATUS UNKNOWN **";
}
- (NSString*) description
{
if (!debug)
return [NSString stringWithFormat:@"<ShipEntity %@ %d>", name, universal_id];
NSString* result = [NSString stringWithFormat:@"\n<ShipEntity %@ %d (%@) %@ %@ on target %d // %@>",
name, universal_id, roles, (universe == nil)? @" (not in universe)":@"", describeBehaviour(behaviour), primaryTarget, collision_region];
NSMutableString* result = [NSMutableString stringWithFormat:@"\n<ShipEntity %@ %d>", name, universal_id];
[result appendFormat:@"\n isPlayer: %@", (isPlayer)? @"YES":@"NO"];
[result appendFormat:@"\n isShip: %@", (isShip)? @"YES":@"NO"];
[result appendFormat:@"\n isStation: %@", (isStation)? @"YES":@"NO"];
[result appendFormat:@"\n isSubentity: %@", (isSubentity)? @"YES":@"NO"];
[result appendFormat:@"\n canCollide: %@", ([self canCollide])? @"YES":@"NO"];
[result appendFormat:@"\n behaviour: %d %@", behaviour, describeBehaviour(behaviour)];
[result appendFormat:@"\n status: %d %@", status, describeStatus(status)];
[result appendFormat:@"\n collisionRegion: %@", collision_region];
return result;
}
@ -4197,10 +4246,10 @@ static GLfloat mascem_color2[4] = { 0.4, 0.1, 0.4, 1.0}; // purple
[plate setVelocity:v];
quaternion_set_random(&q);
[plate setQRotation:q];
[plate setStatus:STATUS_TEST];
[plate setScanClass: CLASS_CARGO];
[plate setCommodity:9 andAmount:1];
[universe addEntity:plate];
[plate setStatus:STATUS_IN_FLIGHT];
[[plate getAI] setState:@"GLOBAL"];
[plate release];
}
@ -4430,11 +4479,11 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
rpos.x += (ranrot_rand() % 7) - 3;
rpos.y += (ranrot_rand() % 7) - 3;
rpos.z += (ranrot_rand() % 7) - 3;
[container setStatus:STATUS_TEST];
[container setPosition:rpos];
[container setScanClass: CLASS_CARGO];
[universe addEntity:container];
[[container getAI] setState:@"GLOBAL"];
[container setStatus:STATUS_IN_FLIGHT];
[container release];
if (n_cargo > 0)
n_cargo--; // count down extra cargo

View File

@ -514,9 +514,10 @@ Your fair use and other rights are in no way affected by the above.
- (void) obj_dump
{
int show_count = (debug)? 10 : n_entities;
NSLog(@"DEBUG ENTITY DUMP: [entities count] = %d,\tn_entities = %d", [entities count], n_entities);
int i;
for (i = 0; i < n_entities; i++)
for (i = 0; i < show_count; i++)
{
ShipEntity* se = (sortedEntities[i]->isShip)? (ShipEntity*)sortedEntities[i]: nil;
NSLog(@"-> Ent:%d\t\t%@ mass %.2f %@", i, sortedEntities[i], [sortedEntities[i] mass], [se getAI]);
@ -524,33 +525,36 @@ Your fair use and other rights are in no way affected by the above.
if ([entities count] != n_entities)
NSLog(@"entities = %@", [entities description]);
//
NSLog(@"\n----->X list...");
NSLog(@"\n----->X list... to %d", show_count);
int n = 0;
Entity* e0 = x_list_start;
while (e0)
{
n++;
NSLog(@"%d.) %@ at x-cr = %.2f", n, e0, e0->position.x - e0->collision_radius);
if (n <= show_count)
NSLog(@"%d.) %@ at x-cr = %.2f", n, e0, e0->position.x - e0->collision_radius);
e0 = e0->x_next;
}
//
NSLog(@"\n----->Y list...");
NSLog(@"\n----->Y list... to %d", show_count);
n = 0;
e0 = y_list_start;
while (e0)
{
n++;
NSLog(@"%d.) %@ at y-cr = %.2f", n, e0, e0->position.y - e0->collision_radius);
if (n <= show_count)
NSLog(@"%d.) %@ at y-cr = %.2f", n, e0, e0->position.y - e0->collision_radius);
e0 = e0->y_next;
}
//
NSLog(@"\n----->Z list...");
NSLog(@"\n----->Z list... to %d", show_count);
n = 0;
e0 = z_list_start;
while (e0)
{
n++;
NSLog(@"%d.) %@ at z-cr = %.2f", n, e0, e0->position.z - e0->collision_radius);
if (n <= show_count)
NSLog(@"%d.) %@ at z-cr = %.2f", n, e0, e0->position.z - e0->collision_radius);
e0 = e0->z_next;
}
}
@ -901,7 +905,7 @@ Your fair use and other rights are in no way affected by the above.
Vector region_pos = a_planet->position;
while (region_pos.z > -planet_radius)
{
[universeRegion addSubregionAtPosition: region_pos withRadius: region_radius]; // collision regions from planet to witchpoint
// [universeRegion addSubregionAtPosition: region_pos withRadius: region_radius]; // collision regions from planet to witchpoint
region_pos.z -= region_spacing;
}
@ -1784,11 +1788,11 @@ GLfloat docked_light_specular[] = { (GLfloat) 1.0, (GLfloat) 1.0, (GLfloat) 0.5,
}
}
// hint to the collision detection system
if (cluster_size > 3)
{
[universeRegion addSubregionAtPosition: spawnPos withRadius: SCANNER_MAX_RANGE * 1.5f ]; // 50% fudge on size
}
// // hint to the collision detection system
// if (cluster_size > 3)
// {
// [universeRegion addSubregionAtPosition: spawnPos withRadius: SCANNER_MAX_RANGE * 1.5f ]; // 50% fudge on size
// }
return rocks;
}
@ -4950,8 +4954,7 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
[universeRegion clearEntityList];
//
for (i = 0; i < n_entities; i++)
if ([sortedEntities[i] canCollide]) // on Jens' suggestion only check collidables
[universeRegion checkEntity: sortedEntities[i]]; // sorts out which region it's in
[universeRegion checkEntity: sortedEntities[i]]; // sorts out which region it's in
//
[universeRegion findCollisionsInUniverse: self];
//
@ -5280,10 +5283,16 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
// now the linked lists
[thing updateLinkedLists];
//
thing->collisionTestFilter = NO;
// filter from collision detection?
thing->collisionTestFilter = ![thing canCollide];
//
// reset list of colliding objects
thing->collision_chain = nil;
//
// done maintaining sorted lists
// update deterministic AI
//
if (thing->isShip)
{
AI* theShipsAI = [(ShipEntity *)thing getAI];
@ -5297,6 +5306,8 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
}
}
}
//
////
}
//
@ -5373,7 +5384,7 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
}
// done! list filtered
// then with the y_list
// then with the y_list, z_list singletons now create more gaps..
e0 = y_list_start;
while (e0)
{
@ -5381,8 +5392,11 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
start = e0->position.y - e0->collision_radius;
finish = start + 2.0f * e0->collision_radius;
next = e0->y_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated from the list of possible colliders - so skip it
next = next->y_next;
if (next)
{
next_start = next->position.y - next->collision_radius;
if (next_start < finish)
{
@ -5395,6 +5409,8 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
finish = next_finish;
e0 = next;
next = e0->y_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated - so skip it
next = next->y_next;
if (next)
next_start = next->position.y - next->collision_radius;
}
@ -5423,6 +5439,8 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
start = e0->position.x - e0->collision_radius;
finish = start + 2.0f * e0->collision_radius;
next = e0->x_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated from the list of possible colliders - so skip it
next = next->x_next;
if (next)
{
next_start = next->position.x - next->collision_radius;
@ -5437,6 +5455,8 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
finish = next_finish;
e0 = next;
next = e0->x_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated - so skip it
next = next->x_next;
if (next)
next_start = next->position.x - next->collision_radius;
}
@ -5457,6 +5477,101 @@ GLfloat starboard_matrix[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
}
// done! list filtered
// repeat the y_list - so gaps from the x_list influence singletons
e0 = y_list_start;
while (e0)
{
// here we are either at the start of the list or just past a gap
start = e0->position.y - e0->collision_radius;
finish = start + 2.0f * e0->collision_radius;
next = e0->y_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated from the list of possible colliders - so skip it
next = next->y_next;
if (next)
{
next_start = next->position.y - next->collision_radius;
if (next_start < finish)
{
// e0 and next overlap
while ((next)&&(next_start < finish))
{
// skip forward to the next gap or the end of the list
next_finish = next_start + 2.0f * next->collision_radius;
if (next_finish > finish)
finish = next_finish;
e0 = next;
next = e0->y_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated - so skip it
next = next->y_next;
if (next)
next_start = next->position.y - next->collision_radius;
}
// now either (next == nil) or (next_start >= finish)-which would imply a gap!
}
else
{
// e0 is a singleton
e0->collisionTestFilter = YES;
}
}
else // (next == nil)
{
// at the end of the list so e0 is a singleton
e0->collisionTestFilter = YES;
}
e0 = next;
}
// done! list filtered
// finally, repeat the z_list - this time building collision chains...
e0 = z_list_start;
while (e0)
{
// here we are either at the start of the list or just past a gap
start = e0->position.z - e0->collision_radius;
finish = start + 2.0f * e0->collision_radius;
next = e0->z_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated from the list of possible colliders - so skip it
next = next->z_next;
if (next)
{
next_start = next->position.z - next->collision_radius;
if (next_start < finish)
{
// e0 and next overlap
while ((next)&&(next_start < finish))
{
// chain e0 to next in collision
e0->collision_chain = next;
// skip forward to the next gap or the end of the list
next_finish = next_start + 2.0f * next->collision_radius;
if (next_finish > finish)
finish = next_finish;
e0 = next;
next = e0->z_next;
while ((next)&&(next->collisionTestFilter)) // next has been eliminated - so skip it
next = next->z_next;
if (next)
next_start = next->position.z - next->collision_radius;
}
// now either (next == nil) or (next_start >= finish)-which would imply a gap!
}
else
{
// e0 is a singleton
e0->collisionTestFilter = YES;
}
}
else // (next == nil)
{
// at the end of the list so e0 is a singleton
e0->collisionTestFilter = YES;
}
e0 = next;
}
// done! list filtered
}
- (void) setGalaxy_seed:(Random_Seed) gal_seed