git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@5054 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2012-07-08 20:02:17 +00:00
parent 579e236b34
commit 1dce047d0f
6 changed files with 275 additions and 264 deletions

View File

@ -100,15 +100,16 @@ extern void GenerateGraphVizForAIStateMachine(NSDictionary *stateMachine, NSStri
- (id) init - (id) init
{ {
self = [super init]; if ((self = [super init]))
{
aiStack = [[NSMutableArray alloc] init]; aiStack = [[NSMutableArray alloc] init];
pendingMessages = [[NSMutableSet alloc] init]; pendingMessages = [[NSMutableSet alloc] init];
nextThinkTime = INFINITY; // don't think for a while nextThinkTime = INFINITY; // don't think for a while
thinkTimeInterval = AI_THINK_INTERVAL; thinkTimeInterval = AI_THINK_INTERVAL;
stateMachineName = [[NSString stringWithString:@"<no AI>"] retain]; // no initial brain stateMachineName = @"<no AI>"; // no initial brain
}
return self; return self;
} }
@ -116,10 +117,11 @@ extern void GenerateGraphVizForAIStateMachine(NSDictionary *stateMachine, NSStri
- (id) initWithStateMachine:(NSString *) smName andState:(NSString *) stateName - (id) initWithStateMachine:(NSString *) smName andState:(NSString *) stateName
{ {
self = [self init]; if ((self = [self init]))
{
if (smName != nil) [self setStateMachine:smName]; if (smName != nil) [self setStateMachine:smName];
if (stateName != nil) currentState = [stateName retain]; if (stateName != nil) currentState = [stateName retain];
}
return self; return self;
} }

View File

@ -28,16 +28,17 @@ MA 02110-1301, USA.
#import "OOCocoa.h" #import "OOCocoa.h"
#import "OOMaths.h" #import "OOMaths.h"
#define COLLISION_REGION_BORDER_RADIUS 32000.0f #define COLLISION_REGION_BORDER_RADIUS 32000.0f
#define COLLISION_MAX_ENTITIES 128 #define COLLISION_MAX_ENTITIES 128
#define MINIMUM_SHADOWING_ENTITY_RADIUS 75.0 #define MINIMUM_SHADOWING_ENTITY_RADIUS 75.0
@class Entity; @class Entity;
@interface CollisionRegion : NSObject
{
@public
@interface CollisionRegion: NSObject
{
@private
BOOL isUniverse; // if YES location is origin and radius is 0.0f BOOL isUniverse; // if YES location is origin and radius is 0.0f
int crid; // identifier int crid; // identifier
@ -45,22 +46,18 @@ MA 02110-1301, USA.
GLfloat radius; // inner radius of the region GLfloat radius; // inner radius of the region
GLfloat border_radius; // additiønal, border radius of the region (typically 32km or some value > the scanner range) GLfloat border_radius; // additiønal, border radius of the region (typically 32km or some value > the scanner range)
int checks_this_tick; unsigned checks_this_tick;
int checks_within_range; unsigned checks_within_range;
NSMutableArray *subregions; NSMutableArray *subregions;
@protected
BOOL isPlayerInRegion; BOOL isPlayerInRegion;
Entity **entity_array; // entities within the region Entity **entity_array; // entities within the region
int n_entities; // number of entities unsigned n_entities; // number of entities
int max_entities; // so storage can be expanded unsigned max_entities; // so storage can be expanded
CollisionRegion *parentRegion; CollisionRegion *parentRegion;
} }
- (id) initAsUniverse; - (id) initAsUniverse;
@ -69,24 +66,17 @@ MA 02110-1301, USA.
- (void) clearSubregions; - (void) clearSubregions;
- (void) addSubregionAtPosition:(Vector) pos withRadius:(GLfloat) rad; - (void) addSubregionAtPosition:(Vector) pos withRadius:(GLfloat) rad;
// update routines to check if a position is within the radius or within it's borders
//
BOOL positionIsWithinRegion( Vector position, CollisionRegion* region);
BOOL sphereIsWithinRegion( Vector position, GLfloat rad, CollisionRegion* region);
BOOL positionIsWithinBorders( Vector position, CollisionRegion* region);
BOOL positionIsOnBorders( Vector position, CollisionRegion* region);
NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region);
// collision checking // collision checking
//
- (void) clearEntityList; - (void) clearEntityList;
- (void) addEntity:(Entity*) ent; - (void) addEntity:(Entity *)ent;
// - (BOOL) checkEntity:(Entity *)ent;
- (BOOL) checkEntity:(Entity*) ent;
//
- (void) findCollisions; - (void) findCollisions;
- (void) findShadowedEntities; - (void) findShadowedEntities;
- (NSString*) debugOut; // Description for FPS HUD
- (NSString *) collisionDescription;
- (NSString *) debugOut;
@end @end

View File

@ -36,87 +36,75 @@ MA 02110-1301, USA.
@implementation CollisionRegion @implementation CollisionRegion
- (NSString *) description
{
int n_subs = [subregions count];
return [NSString stringWithFormat:@"ID: %d, %d subregions, %d ents", crid, n_subs, n_entities];
}
// basic alloc/ dealloc routines // basic alloc/ dealloc routines
// //
static int crid_counter = 1; static int crid_counter = 1;
//
- (id) initAsUniverse
- (id) init // Designated initializer.
{ {
self = [super init]; if ((self = [super init]))
{
location = kZeroVector;
radius = 0.0f;
border_radius = 0.0f;
isUniverse = YES;
isPlayerInRegion = NO;
max_entities = COLLISION_MAX_ENTITIES; max_entities = COLLISION_MAX_ENTITIES;
n_entities = 0; entity_array = (Entity **)malloc(max_entities * sizeof(Entity *));
entity_array = (Entity**) malloc( max_entities * sizeof(Entity*)); if (entity_array == NULL)
{
subregions = [[NSMutableArray alloc] initWithCapacity: 32]; // retained [self release];
return nil;
parentRegion = nil; }
crid = crid_counter++; crid = crid_counter++;
}
return self; return self;
} }
- (id) initAtLocation:(Vector) locn withRadius:(GLfloat) rad withinRegion:(CollisionRegion*) otherRegion - (id) initAsUniverse
{ {
self = [super init]; if ((self = [self init]))
{
isUniverse = YES;
}
return self;
}
- (id) initAtLocation:(Vector)locn withRadius:(GLfloat)rad withinRegion:(CollisionRegion *)otherRegion
{
if ((self = [self init]))
{
location = locn; location = locn;
radius = rad; radius = rad;
border_radius = COLLISION_REGION_BORDER_RADIUS; border_radius = COLLISION_REGION_BORDER_RADIUS;
isUniverse = NO;
isPlayerInRegion = NO;
max_entities = COLLISION_MAX_ENTITIES;
n_entities = 0;
entity_array = (Entity**) malloc( max_entities * sizeof(Entity*));
subregions = [[NSMutableArray alloc] initWithCapacity: 32]; // retained
if (otherRegion)
parentRegion = otherRegion; parentRegion = otherRegion;
}
crid = crid_counter++;
return self; return self;
} }
- (void) dealloc - (void) dealloc
{ {
if (entity_array) free(entity_array);
free((void *)entity_array); // free up the allocated space DESTROY(subregions);
if (subregions)
[subregions release];
[super dealloc]; [super dealloc];
} }
- (NSString *) description
{
return [NSString stringWithFormat:@"<%@ %p>{ID: %d, %u subregions, %u ents}", [self class], self, crid, [subregions count], n_entities];
}
- (void) clearSubregions - (void) clearSubregions
{ {
int i; [subregions makeObjectsPerformSelector:@selector(clearSubregions)];
int n_subs = [subregions count];
for (i = 0; i < n_subs; i++)
[(CollisionRegion*)[subregions objectAtIndex: i] clearSubregions];
[subregions removeAllObjects]; [subregions removeAllObjects];
} }
- (void) addSubregionAtPosition:(Vector) pos withRadius:(GLfloat) rad - (void) addSubregionAtPosition:(Vector)pos withRadius:(GLfloat)rad
{ {
// check if this can be fitted within any of the subregions // check if this can be fitted within any of the subregions
// //
@ -124,14 +112,14 @@ static int crid_counter = 1;
int n_subs = [subregions count]; int n_subs = [subregions count];
for (i = 0; i < n_subs; i++) for (i = 0; i < n_subs; i++)
{ {
CollisionRegion* sub = (CollisionRegion*)[subregions objectAtIndex: i]; CollisionRegion *sub = (CollisionRegion *)[subregions objectAtIndex:i];
if (sphereIsWithinRegion( pos, rad, sub)) if (sphereIsWithinRegion(pos, rad, sub))
{ {
// if it fits, put it in! // if it fits, put it in!
[sub addSubregionAtPosition: pos withRadius: rad]; [sub addSubregionAtPosition:pos withRadius:rad];
return; return;
} }
if (positionIsWithinRegion( pos, sub)) if (positionIsWithinRegion(pos, sub))
{ {
// crosses the border of this region already - leave it out // crosses the border of this region already - leave it out
return; return;
@ -139,21 +127,19 @@ static int crid_counter = 1;
} }
// no subregion fit - move on... // no subregion fit - move on...
// //
CollisionRegion* sub = [[CollisionRegion alloc] initAtLocation: pos withRadius: rad withinRegion: self]; CollisionRegion *sub = [[CollisionRegion alloc] initAtLocation:pos withRadius:rad withinRegion:self];
if (subregions == nil) subregions = [[NSMutableArray alloc] initWithCapacity:32];
[subregions addObject:sub]; [subregions addObject:sub];
[sub release]; [sub release];
} }
// update routines to check if a position is within the radius or within it's borders // update routines to check if a position is within the radius or within its borders
// //
BOOL positionIsWithinRegion( Vector position, CollisionRegion* region) static BOOL positionIsWithinRegion(Vector position, CollisionRegion *region)
{ {
if (!region) if (region == nil) return NO;
return NO; if (region->isUniverse) return YES;
if (region->isUniverse)
return YES;
Vector loc = region->location; Vector loc = region->location;
GLfloat r1 = region->radius; GLfloat r1 = region->radius;
@ -161,19 +147,18 @@ BOOL positionIsWithinRegion( Vector position, CollisionRegion* region)
if ((position.x < loc.x - r1)||(position.x > loc.x + r1)|| if ((position.x < loc.x - r1)||(position.x > loc.x + r1)||
(position.y < loc.y - r1)||(position.y > loc.y + r1)|| (position.y < loc.y - r1)||(position.y > loc.y + r1)||
(position.z < loc.z - r1)||(position.z > loc.z + r1)) (position.z < loc.z - r1)||(position.z > loc.z + r1))
{
return NO; return NO;
}
return YES; return YES;
} }
BOOL sphereIsWithinRegion( Vector position, GLfloat rad, CollisionRegion* region) static BOOL sphereIsWithinRegion(Vector position, GLfloat rad, CollisionRegion *region)
{ {
if (!region) if (region == nil) return NO;
return NO; if (region->isUniverse) return YES;
if (region->isUniverse)
return YES;
Vector loc = region->location; Vector loc = region->location;
GLfloat r1 = region->radius; GLfloat r1 = region->radius;
@ -181,19 +166,18 @@ BOOL sphereIsWithinRegion( Vector position, GLfloat rad, CollisionRegion* region
if ((position.x - rad < loc.x - r1)||(position.x + rad > loc.x + r1)|| if ((position.x - rad < loc.x - r1)||(position.x + rad > loc.x + r1)||
(position.y - rad < loc.y - r1)||(position.y + rad > loc.y + r1)|| (position.y - rad < loc.y - r1)||(position.y + rad > loc.y + r1)||
(position.z - rad < loc.z - r1)||(position.z + rad > loc.z + r1)) (position.z - rad < loc.z - r1)||(position.z + rad > loc.z + r1))
{
return NO; return NO;
}
return YES; return YES;
} }
BOOL positionIsWithinBorders( Vector position, CollisionRegion* region) static BOOL positionIsWithinBorders(Vector position, CollisionRegion *region)
{ {
if (!region) if (region == nil) return NO;
return NO; if (region->isUniverse) return YES;
if (region->isUniverse)
return YES;
Vector loc = region->location; Vector loc = region->location;
GLfloat r1 = region->radius + region->border_radius; GLfloat r1 = region->radius + region->border_radius;
@ -201,19 +185,21 @@ BOOL positionIsWithinBorders( Vector position, CollisionRegion* region)
if ((position.x < loc.x - r1)||(position.x > loc.x + r1)|| if ((position.x < loc.x - r1)||(position.x > loc.x + r1)||
(position.y < loc.y - r1)||(position.y > loc.y + r1)|| (position.y < loc.y - r1)||(position.y > loc.y + r1)||
(position.z < loc.z - r1)||(position.z > loc.z + r1)) (position.z < loc.z - r1)||(position.z > loc.z + r1))
{
return NO; return NO;
}
return YES; return YES;
} }
BOOL positionIsOnBorders( Vector position, CollisionRegion* region) #if 0
{ // These were lying about unused when I found them, honest guv. -- Ahruman 2012-07-08
if (!region)
return NO;
if (region->isUniverse) static BOOL positionIsOnBorders(Vector position, CollisionRegion *region)
return NO; {
if (region == nil) return NO;
if (region->isUniverse) return NO;
Vector loc = region->location; Vector loc = region->location;
GLfloat r2 = region->radius + region->border_radius; GLfloat r2 = region->radius + region->border_radius;
@ -221,121 +207,125 @@ BOOL positionIsOnBorders( Vector position, CollisionRegion* region)
if ((position.x < loc.x - r2)||(position.x > loc.x + r2)|| if ((position.x < loc.x - r2)||(position.x > loc.x + r2)||
(position.y < loc.y - r2)||(position.y > loc.y + r2)|| (position.y < loc.y - r2)||(position.y > loc.y + r2)||
(position.z < loc.z - r2)||(position.z > loc.z + r2)) (position.z < loc.z - r2)||(position.z > loc.z + r2))
{
return NO; return NO;
}
return (!positionIsWithinRegion( position, region)); return !positionIsWithinRegion(position, region);
} }
NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region) static NSArray *subregionsContainingPosition(Vector position, CollisionRegion *region)
{ {
NSArray* subs = region->subregions; NSArray *subs = region->subregions;
NSMutableArray* result = [NSMutableArray array]; // autoreleased NSMutableArray *result = [NSMutableArray array]; // autoreleased
if (!subs) int i, n_subs = [subs count];
return result; // empty array
int i;
int n_subs = [subs count];
for (i = 0; i < n_subs; i++) for (i = 0; i < n_subs; i++)
if (positionIsWithinBorders( position, (CollisionRegion*)[subs objectAtIndex: i])) {
[result addObject: [subs objectAtIndex: i]]; if (positionIsWithinBorders(position, (CollisionRegion *)[subs objectAtIndex:i]))
{
[result addObject:[subs objectAtIndex:i]];
}
}
return result; return result;
} }
#endif
// collision checking // collision checking
// //
- (void) clearEntityList - (void) clearEntityList
{ {
[subregions makeObjectsPerformSelector:@selector(clearEntityList)];
n_entities = 0; n_entities = 0;
int i;
int n_subs = [subregions count];
for (i = 0; i < n_subs; i++)
[(CollisionRegion*)[subregions objectAtIndex: i] clearEntityList];
isPlayerInRegion = NO; isPlayerInRegion = NO;
} }
- (void) addEntity:(Entity*) ent - (void) addEntity:(Entity *)ent
{ {
// expand if necessary // expand if necessary
// //
if (n_entities == max_entities) if (n_entities == max_entities)
{ {
max_entities = 1 + max_entities * 2; max_entities = 1 + max_entities * 2;
Entity** new_store = (Entity**) malloc( max_entities * sizeof(Entity*)); Entity **new_store = (Entity **)realloc(entity_array, max_entities * sizeof(Entity *));
int i; if (new_store == NULL)
for (i = 0; i < n_entities; i++) {
new_store[i] = entity_array[i]; [NSException raise:NSMallocException format:@"Not enough memory to grow collision region member list."];
free( (void*)entity_array); }
entity_array = new_store; entity_array = new_store;
} }
isPlayerInRegion |= (ent->isPlayer); if ([ent isPlayer]) isPlayerInRegion = YES;
entity_array[n_entities++] = ent; entity_array[n_entities++] = ent;
} }
- (BOOL) checkEntity:(Entity*) ent - (BOOL) checkEntity:(Entity *)ent
{ {
Vector position = ent->position; Vector position = ent->position;
// check subregions // check subregions
BOOL foundRegion = NO; int i, n_subs = [subregions count];
int n_subs = [subregions count];
int i;
for (i = 0; i < n_subs; i++) for (i = 0; i < n_subs; i++)
{ {
CollisionRegion* sub = (CollisionRegion*)[subregions objectAtIndex:i]; CollisionRegion *sub = [subregions objectAtIndex:i];
if (positionIsWithinBorders( position, sub)) if (positionIsWithinBorders(position, sub) && [sub checkEntity:ent])
foundRegion |= [sub checkEntity:ent]; {
return YES;
}
} }
if (foundRegion)
return YES; // it's in a subregion so no further action is neccesary
if (!positionIsWithinBorders( position, self)) if (!positionIsWithinBorders(position, self))
{
return NO; return NO;
}
[self addEntity: ent]; [self addEntity:ent];
[ent setCollisionRegion: self]; [ent setCollisionRegion:self];
return YES; return YES;
} }
- (void) findCollisions - (void) findCollisions
{ {
// test for collisions in each subregion
[subregions makeObjectsPerformSelector:@selector(findCollisions)];
// reject trivial cases
if (n_entities < 2) return;
// //
// According to Shark, when this was in Universe this was where Oolite spent most time! // According to Shark, when this was in Universe this was where Oolite spent most time!
// //
Entity *e1,*e2; Entity *e1, *e2;
Vector p1, p2; Vector p1, p2;
double dist2, r1, r2, r0, min_dist2; double dist2, r1, r2, r0, min_dist2;
int i; unsigned i;
Entity* entities_to_test[n_entities]; Entity *entities_to_test[n_entities];
//
// reject trivial cases
//
if (n_entities < 2)
return;
// only check unfiltered entities // only check unfiltered entities
int n_entities_to_test = 0; unsigned n_entities_to_test = 0;
for (i = 0; i < n_entities; i++) for (i = 0; i < n_entities; i++)
{ {
e1 = entity_array[i]; e1 = entity_array[i];
if (!(e1->collisionTestFilter)) if (!(e1->collisionTestFilter))
{
entities_to_test[n_entities_to_test++] = e1; entities_to_test[n_entities_to_test++] = e1;
} }
}
#ifndef NDEBUG #ifndef NDEBUG
if (gDebugFlags & DEBUG_COLLISIONS) if (gDebugFlags & DEBUG_COLLISIONS)
{
OOLog(@"collisionRegion.debug", @"DEBUG in collision region %@ testing %d out of %d entities", self, n_entities_to_test, n_entities); OOLog(@"collisionRegion.debug", @"DEBUG in collision region %@ testing %d out of %d entities", self, n_entities_to_test, n_entities);
}
#endif #endif
if (n_entities_to_test < 2) if (n_entities_to_test < 2) return;
return;
// clear collision variables // clear collision variables
// //
@ -343,24 +333,17 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
{ {
e1 = entities_to_test[i]; e1 = entities_to_test[i];
if (e1->hasCollided) if (e1->hasCollided)
{
[[e1 collisionArray] removeAllObjects]; [[e1 collisionArray] removeAllObjects];
e1->hasCollided = NO; e1->hasCollided = NO;
}
if (e1->isShip) if (e1->isShip)
{
[(ShipEntity*)e1 setProximity_alert:nil]; [(ShipEntity*)e1 setProximity_alert:nil];
}
e1->collider = nil; e1->collider = nil;
} }
// test for collisions in each subregion
//
/* There are never subregions created in the current code, so skip this check for now.
int n_subs = [subregions count];
for (i = 0; i < n_subs; i++)
[(CollisionRegion*)[subregions objectAtIndex: i] findCollisions];
*/
//
checks_this_tick = 0; checks_this_tick = 0;
checks_within_range = 0; checks_within_range = 0;
@ -378,10 +361,9 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
{ {
checks_this_tick++; checks_this_tick++;
p2 = e2->position; p2 = vector_subtract(e2->position, p1);
r2 = e2->collision_radius; r2 = e2->collision_radius;
r0 = r1 + r2; r0 = r1 + r2;
p2 = vector_subtract(p2, p1);
dist2 = magnitude2(p2); dist2 = magnitude2(p2);
min_dist2 = r0 * r0; min_dist2 = r0 * r0;
if (dist2 < PROXIMITY_WARN_DISTANCE2 * min_dist2) if (dist2 < PROXIMITY_WARN_DISTANCE2 * min_dist2)
@ -395,7 +377,7 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
#endif #endif
checks_within_range++; checks_within_range++;
if ((e1->isShip) && (e2->isShip)) if (e1->isShip && e2->isShip)
{ {
if ((dist2 < PROXIMITY_WARN_DISTANCE2 * r2 * r2) || (dist2 < PROXIMITY_WARN_DISTANCE2 * r1 * r1)) if ((dist2 < PROXIMITY_WARN_DISTANCE2 * r2 * r2) || (dist2 < PROXIMITY_WARN_DISTANCE2 * r1 * r1))
{ {
@ -409,36 +391,54 @@ NSArray* subregionsContainingPosition( Vector position, CollisionRegion* region)
if (e1->isStation) if (e1->isStation)
{ {
StationEntity* se1 = (StationEntity*) e1; StationEntity* se1 = (StationEntity *)e1;
if ([se1 shipIsInDockingCorridor: (ShipEntity*)e2]) if ([se1 shipIsInDockingCorridor:(ShipEntity *)e2])
{
collision = NO; collision = NO;
}
else else
collision = [e1 checkCloseCollisionWith: e2]; {
collision = [e1 checkCloseCollisionWith:e2];
}
} }
else if (e2->isStation) else if (e2->isStation)
{ {
StationEntity* se2 = (StationEntity*) e2; StationEntity* se2 = (StationEntity *)e2;
if ([se2 shipIsInDockingCorridor: (ShipEntity*)e1]) if ([se2 shipIsInDockingCorridor:(ShipEntity *)e1])
{
collision = NO; collision = NO;
else
collision = [e2 checkCloseCollisionWith: e1];
} }
else else
collision = [e1 checkCloseCollisionWith: e2]; {
collision = [e2 checkCloseCollisionWith:e1];
}
}
else
{
collision = [e1 checkCloseCollisionWith:e2];
}
if (collision) if (collision)
{ {
// now we have no need to check the e2-e1 collision // now we have no need to check the e2-e1 collision
if (e1->collider) if (e1->collider)
{
[[e1 collisionArray] addObject:e1->collider]; [[e1 collisionArray] addObject:e1->collider];
}
else else
{
[[e1 collisionArray] addObject:e2]; [[e1 collisionArray] addObject:e2];
}
e1->hasCollided = YES; e1->hasCollided = YES;
//
if (e2->collider) if (e2->collider)
{
[[e2 collisionArray] addObject:e2->collider]; [[e2 collisionArray] addObject:e2->collider];
}
else else
{
[[e2 collisionArray] addObject:e1]; [[e2 collisionArray] addObject:e1];
}
e2->hasCollided = YES; e2->hasCollided = YES;
} }
} }
@ -535,58 +535,59 @@ static BOOL testEntityOccludedByEntity(Entity *e1, Entity *e2, OOSunEntity *the_
- (void) findShadowedEntities - (void) findShadowedEntities
{ {
// reject trivial cases
if (n_entities < 2) return;
// //
// Copy/pasting the collision code to detect occlusion! // Copy/pasting the collision code to detect occlusion!
// //
Entity* e1; unsigned i, j;
int i,j;
if ([UNIVERSE reducedDetail]) return; // don't do this in reduced detail mode if ([UNIVERSE reducedDetail]) return; // don't do this in reduced detail mode
OOSunEntity* the_sun = [UNIVERSE sun]; OOSunEntity* the_sun = [UNIVERSE sun];
if (!the_sun) if (the_sun == nil)
{
return; // sun is required return; // sun is required
}
unsigned ent_count = UNIVERSE->n_entities;
Entity **uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
Entity *planets[ent_count];
unsigned n_planets = 0;
Entity *ships[ent_count];
unsigned n_ships = 0;
//
// get a list of planet entities because they can shade across regions
int ent_count = UNIVERSE->n_entities;
Entity** uni_entities = UNIVERSE->sortedEntities; // grab the public sorted list
Entity* planets[ent_count];
int n_planets = 0;
Entity* ships[ent_count];
int n_ships = 0;
for (i = 0; i < ent_count; i++) for (i = 0; i < ent_count; i++)
{ {
if ([uni_entities[i] isPlanet] && uni_entities[i]->isSunlit) if (uni_entities[i]->isSunlit)
planets[n_planets++] = uni_entities[i]; // don't bother retaining - nothing will happen to them! {
// get a list of planet entities because they can shade across regions
if ([uni_entities[i] isPlanet])
{
// don't bother retaining - nothing will happen to them!
planets[n_planets++] = uni_entities[i];
}
// and a list of shipentities large enough that they might cast a noticeable shadow // and a list of shipentities large enough that they might cast a noticeable shadow
// if we can't see it, it can't be shadowing anything important // if we can't see it, it can't be shadowing anything important
else if ([uni_entities[i] isShip] && uni_entities[i]->isSunlit && [uni_entities[i] isVisible] && uni_entities[i]->collision_radius >= MINIMUM_SHADOWING_ENTITY_RADIUS) else if ([uni_entities[i] isShip] &&
[uni_entities[i] isVisible] &&
uni_entities[i]->collision_radius >= MINIMUM_SHADOWING_ENTITY_RADIUS)
{ {
ships[n_ships++] = uni_entities[i]; // don't bother retaining - nothing will happen to them! ships[n_ships++] = uni_entities[i]; // don't bother retaining - nothing will happen to them!
} }
} }
}
// reject trivial cases
//
if (n_entities < 2)
return;
// test for shadows in each subregion // test for shadows in each subregion
// [subregions makeObjectsPerformSelector:@selector(findShadowedEntities)];
int n_subs = [subregions count];
for (i = 0; i < n_subs; i++)
[[subregions objectAtIndex: i] findShadowedEntities];
//
// test each entity in this region against the others // test each entity in this region against the others
//
for (i = 0; i < n_entities; i++) for (i = 0; i < n_entities; i++)
{ {
e1 = entity_array[i]; Entity *e1 = entity_array[i];
if (![e1 isVisible]) if (![e1 isVisible])
{ {
continue; // don't check shading of objects we can't see continue; // don't check shading of objects we can't see
@ -598,13 +599,15 @@ static BOOL testEntityOccludedByEntity(Entity *e1, Entity *e2, OOSunEntity *the_
e1->shadingEntityID = NO_TARGET; e1->shadingEntityID = NO_TARGET;
continue; // don't check shading in demo mode continue; // don't check shading in demo mode
} }
Entity* occluder = nil; Entity *occluder = nil;
if (e1->isSunlit == NO) if (e1->isSunlit == NO)
{ {
occluder = [UNIVERSE entityForUniversalID:e1->shadingEntityID]; occluder = [UNIVERSE entityForUniversalID:e1->shadingEntityID];
if (occluder) if (occluder != nil)
{
occluder_moved = occluder->hasMoved; occluder_moved = occluder->hasMoved;
} }
}
if (([e1 isShip] ||[e1 isPlanet]) && (e1->hasMoved || occluder_moved)) if (([e1 isShip] ||[e1 isPlanet]) && (e1->hasMoved || occluder_moved))
{ {
e1->isSunlit = YES; // sunlit by default e1->isSunlit = YES; // sunlit by default
@ -612,39 +615,47 @@ static BOOL testEntityOccludedByEntity(Entity *e1, Entity *e2, OOSunEntity *the_
// //
// check demo mode here.. // check demo mode here..
if ([e1 isPlayer] && ([(PlayerEntity*)e1 showDemoShips])) if ([e1 isPlayer] && ([(PlayerEntity*)e1 showDemoShips]))
{
continue; // don't check shading in demo mode continue; // don't check shading in demo mode
// }
// test last occluder (most likely case) // test last occluder (most likely case)
//
double occlusionNumber;
if (occluder) if (occluder)
{ {
if (entityByEntityOcclusionToValue(e1, occluder, the_sun, &occlusionNumber)) if (testEntityOccludedByEntity(e1, occluder, the_sun))
{ {
e1->isSunlit = NO; e1->isSunlit = NO;
e1->shadingEntityID = [occluder universalID]; e1->shadingEntityID = [occluder universalID];
} }
} }
if (!e1->isSunlit) // no point in continuing tests if (!e1->isSunlit)
{
// no point in continuing tests
continue; continue;
// }
// test planets // test planets
//
for (j = 0; j < n_planets; j++) for (j = 0; j < n_planets; j++)
{ {
double occlusionNumber;
if (entityByEntityOcclusionToValue(e1, planets[j], the_sun, &occlusionNumber)) if (entityByEntityOcclusionToValue(e1, planets[j], the_sun, &occlusionNumber))
{ {
e1->isSunlit = NO; e1->isSunlit = NO;
e1->shadingEntityID = [planets[j] universalID]; e1->shadingEntityID = [planets[j] universalID];
break; break;
} }
if (EXPECT_NOT([e1 isPlayer])) ((PlayerEntity *)e1)->occlusion_dial = occlusionNumber; if ([e1 isPlayer])
{
((PlayerEntity *)e1)->occlusion_dial = occlusionNumber;
} }
if (!e1->isSunlit) // no point in continuing tests }
if (!e1->isSunlit)
{
// no point in continuing tests
continue; continue;
// }
// test local entities // test local entities
//
for (j = 0; j < n_ships; j++) for (j = 0; j < n_ships; j++)
{ {
if (testEntityOccludedByEntity(e1, ships[j], the_sun)) if (testEntityOccludedByEntity(e1, ships[j], the_sun))
@ -659,13 +670,21 @@ static BOOL testEntityOccludedByEntity(Entity *e1, Entity *e2, OOSunEntity *the_
} }
- (NSString*) debugOut - (NSString *) collisionDescription
{
return [NSString stringWithFormat:@"p%u - c%u", checks_this_tick, checks_within_range];
}
- (NSString *) debugOut
{ {
int i; int i;
int n_subs = [subregions count]; int n_subs = [subregions count];
NSMutableString* result = [[NSMutableString alloc] initWithFormat:@"%d:", n_entities]; NSMutableString *result = [[NSMutableString alloc] initWithFormat:@"%d:", n_entities];
for (i = 0; i < n_subs; i++) for (i = 0; i < n_subs; i++)
{
[result appendString:[(CollisionRegion*)[subregions objectAtIndex:i] debugOut]]; [result appendString:[(CollisionRegion*)[subregions objectAtIndex:i] debugOut]];
}
return [result autorelease]; return [result autorelease];
} }

View File

@ -279,16 +279,17 @@ static void DrawWormholeCorona(GLfloat inner_radius, GLfloat outer_radius, int s
int i; int i;
for (i = 0; i < n_ships; i++) for (i = 0; i < n_ships; i++)
{ {
ShipEntity* ship = (ShipEntity*)[(NSDictionary*)[shipsInTransit objectAtIndex:i] objectForKey:@"ship"]; NSDictionary *shipInfo = [shipsInTransit objectAtIndex:i];
NSString *shipBeacon = [(NSDictionary *)[shipsInTransit objectAtIndex:i] objectForKey:@"shipBeacon"]; ShipEntity *ship = [shipInfo objectForKey:@"ship"];
double ship_arrival_time = arrival_time + [(NSNumber*)[(NSDictionary*)[shipsInTransit objectAtIndex:i] objectForKey:@"time"] doubleValue]; NSString *shipBeacon = [shipInfo objectForKey:@"shipBeacon"];
double ship_arrival_time = arrival_time + [shipInfo oo_doubleForKey:@"time"];
double time_passed = now - ship_arrival_time; double time_passed = now - ship_arrival_time;
if ([ship status] == STATUS_DEAD) continue; // skip dead ships. if ([ship status] == STATUS_DEAD) continue; // skip dead ships.
if (ship_arrival_time > now) if (ship_arrival_time > now)
{ {
[shipsStillInTransit addObject:[shipsInTransit objectAtIndex:i]]; [shipsStillInTransit addObject:shipInfo];
} }
else else
{ {

View File

@ -876,7 +876,7 @@ NSString *OOJSDescribeLocation(JSContext *context, JSStackFrame *stackFrame)
const char *fileName; const char *fileName;
OOUInteger lineNo; OOUInteger lineNo;
GetLocationNameAndLine(context, stackFrame, &fileName, &lineNo); GetLocationNameAndLine(context, stackFrame, &fileName, &lineNo);
if (fileName == NULL) return NO; if (fileName == NULL) return nil;
// If this stops working, we probably need to switch to strcmp(). // If this stops working, we probably need to switch to strcmp().
if (fileName == sConsoleScriptName && lineNo >= sConsoleEvalLineNo) return @"<console input>"; if (fileName == sConsoleScriptName && lineNo >= sConsoleEvalLineNo) return @"<console input>";

View File

@ -4913,22 +4913,21 @@ OOINLINE BOOL EntityInRange(Vector p1, Entity *e2, float range)
[universeRegion clearEntityList]; [universeRegion clearEntityList];
for (i = 0; i < n_entities; i++) for (i = 0; i < n_entities; i++)
[universeRegion checkEntity: sortedEntities[i]]; // sorts out which region it's in {
[universeRegion checkEntity:sortedEntities[i]]; // sorts out which region it's in
}
[universeRegion findCollisions]; [universeRegion findCollisions];
// do check for entities that can't see the sun! // do check for entities that can't see the sun!
[universeRegion findShadowedEntities]; [universeRegion findShadowedEntities];
} }
- (NSString*) collisionDescription - (NSString*) collisionDescription
{ {
if (universeRegion) if (universeRegion != nil) return [universeRegion collisionDescription];
return [NSString stringWithFormat:@"p%d - c%d", universeRegion->checks_this_tick, universeRegion->checks_within_range]; else return @"-";
else
return @"-";
} }