From 0037ef4493436b29cdbbc95797cf3ef1279abf7c Mon Sep 17 00:00:00 2001 From: Giles Williams Date: Wed, 26 Apr 2006 09:41:56 +0000 Subject: [PATCH] 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 --- src/Core/CollisionRegion.m | 33 ++++--- src/Core/DustEntity.m | 2 +- src/Core/Entity.h | 3 +- src/Core/Entity.m | 4 +- src/Core/PlayerEntity (Controls).m | 3 + src/Core/PlayerEntity.m | 2 +- src/Core/ShipEntity.m | 57 ++++++++++- src/Core/Universe.m | 151 +++++++++++++++++++++++++---- 8 files changed, 218 insertions(+), 37 deletions(-) diff --git a/src/Core/CollisionRegion.m b/src/Core/CollisionRegion.m index 8ac5f242..21dd60e4 100644 --- a/src/Core/CollisionRegion.m +++ b/src/Core/CollisionRegion.m @@ -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; } } } diff --git a/src/Core/DustEntity.m b/src/Core/DustEntity.m index 6797724c..df20bd6d 100644 --- a/src/Core/DustEntity.m +++ b/src/Core/DustEntity.m @@ -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; } diff --git a/src/Core/Entity.h b/src/Core/Entity.h index 99e9787c..40642f92 100644 --- a/src/Core/Entity.h +++ b/src/Core/Entity.h @@ -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: diff --git a/src/Core/Entity.m b/src/Core/Entity.m index c06d2959..0cfdcb64 100644 --- a/src/Core/Entity.m +++ b/src/Core/Entity.m @@ -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; diff --git a/src/Core/PlayerEntity (Controls).m b/src/Core/PlayerEntity (Controls).m index 45965195..d96baa9f 100644 --- a/src/Core/PlayerEntity (Controls).m +++ b/src/Core/PlayerEntity (Controls).m @@ -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 diff --git a/src/Core/PlayerEntity.m b/src/Core/PlayerEntity.m index af527fc1..261c7132 100644 --- a/src/Core/PlayerEntity.m +++ b/src/Core/PlayerEntity.m @@ -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; diff --git a/src/Core/ShipEntity.m b/src/Core/ShipEntity.m index 1ee35a56..0fa1cbdb 100644 --- a/src/Core/ShipEntity.m +++ b/src/Core/ShipEntity.m @@ -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:@"", name, universal_id]; - NSString* result = [NSString stringWithFormat:@"\n", - name, universal_id, roles, (universe == nil)? @" (not in universe)":@"", describeBehaviour(behaviour), primaryTarget, collision_region]; + NSMutableString* result = [NSMutableString stringWithFormat:@"\n", 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 diff --git a/src/Core/Universe.m b/src/Core/Universe.m index fa661515..ccc9a42e 100644 --- a/src/Core/Universe.m +++ b/src/Core/Universe.m @@ -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