Allow exemption of ships from collision with each other

S.addCollisionException(ship)
S.removeCollisionException(ship)
S.collisionExceptions
This commit is contained in:
cim 2014-12-02 20:28:03 +00:00
parent 7d1323ab68
commit c7ceba26e6
4 changed files with 188 additions and 65 deletions

View File

@ -316,91 +316,101 @@ static BOOL positionIsWithinBorders(HPVector position, CollisionRegion *region)
e1 = entities_to_test[i];
p1 = e1->position;
r1 = e1->collision_radius;
// check against the first in the collision chain
e2 = e1->collision_chain;
while (e2 != nil)
{
checks_this_tick++;
r2 = e2->collision_radius;
r0 = r1 + r2;
dist2 = HPdistance2(e2->position, p1);
min_dist2 = r0 * r0;
if (dist2 < PROXIMITY_WARN_DISTANCE2 * min_dist2)
if (e1->isShip && e2->isShip &&
[(ShipEntity *)e1 collisionExceptedFor:(ShipEntity *)e2])
{
OOLog(@"collision.except",@"ignoring potential collision between %@ and %@",e1,e2);
}
else
{
r2 = e2->collision_radius;
r0 = r1 + r2;
dist2 = HPdistance2(e2->position, p1);
min_dist2 = r0 * r0;
if (dist2 < PROXIMITY_WARN_DISTANCE2 * min_dist2)
{
#ifndef NDEBUG
if (gDebugFlags & DEBUG_COLLISIONS)
{
OOLog(@"collisionRegion.debug", @"DEBUG Testing collision between %@ (%@) and %@ (%@)",
e1, (e1->collisionTestFilter==3)?@"YES":@"NO", e2, (e2->collisionTestFilter==3)?@"YES":@"NO");
}
#endif
checks_within_range++;
if (e1->isShip && e2->isShip)
{
if ((dist2 < PROXIMITY_WARN_DISTANCE2 * r2 * r2) || (dist2 < PROXIMITY_WARN_DISTANCE2 * r1 * r1))
if (gDebugFlags & DEBUG_COLLISIONS)
{
[(ShipEntity*)e1 setProximityAlert:(ShipEntity*)e2];
[(ShipEntity*)e2 setProximityAlert:(ShipEntity*)e1];
OOLog(@"collisionRegion.debug", @"DEBUG Testing collision between %@ (%@) and %@ (%@)",
e1, (e1->collisionTestFilter==3)?@"YES":@"NO", e2, (e2->collisionTestFilter==3)?@"YES":@"NO");
}
}
if (dist2 < min_dist2)
{
BOOL collision = NO;
if (e1->isStation)
#endif
checks_within_range++;
if (e1->isShip && e2->isShip)
{
StationEntity* se1 = (StationEntity *)e1;
if ([se1 shipIsInDockingCorridor:(ShipEntity *)e2])
if ((dist2 < PROXIMITY_WARN_DISTANCE2 * r2 * r2) || (dist2 < PROXIMITY_WARN_DISTANCE2 * r1 * r1))
{
collision = NO;
[(ShipEntity*)e1 setProximityAlert:(ShipEntity*)e2];
[(ShipEntity*)e2 setProximityAlert:(ShipEntity*)e1];
}
}
if (dist2 < min_dist2)
{
BOOL collision = NO;
if (e1->isStation)
{
StationEntity* se1 = (StationEntity *)e1;
if ([se1 shipIsInDockingCorridor:(ShipEntity *)e2])
{
collision = NO;
}
else
{
collision = [e1 checkCloseCollisionWith:e2];
}
}
else if (e2->isStation)
{
StationEntity* se2 = (StationEntity *)e2;
if ([se2 shipIsInDockingCorridor:(ShipEntity *)e1])
{
collision = NO;
}
else
{
collision = [e2 checkCloseCollisionWith:e1];
}
}
else
{
collision = [e1 checkCloseCollisionWith:e2];
}
}
else if (e2->isStation)
{
StationEntity* se2 = (StationEntity *)e2;
if ([se2 shipIsInDockingCorridor:(ShipEntity *)e1])
{
collision = NO;
}
else
{
collision = [e2 checkCloseCollisionWith:e1];
}
}
else
{
collision = [e1 checkCloseCollisionWith:e2];
}
if (collision)
{
// now we have no need to check the e2-e1 collision
if (e1->collider)
if (collision)
{
[[e1 collisionArray] addObject:e1->collider];
}
else
{
[[e1 collisionArray] addObject:e2];
}
e1->hasCollided = YES;
// now we have no need to check the e2-e1 collision
if (e1->collider)
{
[[e1 collisionArray] addObject:e1->collider];
}
else
{
[[e1 collisionArray] addObject:e2];
}
e1->hasCollided = YES;
if (e2->collider)
{
[[e2 collisionArray] addObject:e2->collider];
if (e2->collider)
{
[[e2 collisionArray] addObject:e2->collider];
}
else
{
[[e2 collisionArray] addObject:e1];
}
e2->hasCollided = YES;
}
else
{
[[e2 collisionArray] addObject:e1];
}
e2->hasCollided = YES;
}
}
}

View File

@ -461,6 +461,9 @@ typedef enum
OOWeakSet *_defenseTargets; // defense targets
// ships in this set can't be collided with
OOWeakSet *_collisionExceptions;
GLfloat _profileRadius;
OOWeakReference *_shipHitByLaser; // entity hit by the last laser shot
@ -783,6 +786,13 @@ typedef enum
- (void) removeDefenseTarget:(Entity *)target;
- (void) removeAllDefenseTargets;
// collision exceptions
- (NSArray *) collisionExceptions;
- (void) addCollisionException:(ShipEntity *)ship;
- (void) removeCollisionException:(ShipEntity *)ship;
- (BOOL) collisionExceptedFor:(ShipEntity *)ship;
- (GLfloat) weaponRange;
- (void) setWeaponRange:(GLfloat) value;

View File

@ -1021,6 +1021,7 @@ static ShipEntity *doOctreesCollide(ShipEntity *prime, ShipEntity *other);
DESTROY(lastRadioMessage);
DESTROY(octree);
DESTROY(_defenseTargets);
DESTROY(_collisionExceptions);
DESTROY(commodity_type);
@ -10538,6 +10539,47 @@ Vector positionOffsetForShipInRotationToAlignment(ShipEntity* ship, Quaternion q
}
- (NSArray *) collisionExceptions
{
if (_collisionExceptions == nil)
{
return [NSArray array];
}
return [_collisionExceptions allObjects];
}
- (void) addCollisionException:(ShipEntity *)ship
{
if (_collisionExceptions == nil)
{
// Allocate lazily for the benefit of the ships that never need this.
_collisionExceptions = [[OOWeakSet alloc] init];
}
[_collisionExceptions addObject:ship];
}
- (void) removeCollisionException:(ShipEntity *)ship
{
if (_collisionExceptions != nil)
{
[_collisionExceptions removeObject:ship];
}
}
- (BOOL) collisionExceptedFor:(ShipEntity *)ship
{
if (_collisionExceptions == nil)
{
return NO;
}
return [_collisionExceptions containsObject:ship];
}
- (NSUInteger) defenseTargetCount
{
return [_defenseTargets count];

View File

@ -98,6 +98,8 @@ static JSBool ShipUpdateEscortFormation(JSContext *context, uintN argc, jsval *v
static JSBool ShipClearDefenseTargets(JSContext *context, uintN argc, jsval *vp);
static JSBool ShipAddDefenseTarget(JSContext *context, uintN argc, jsval *vp);
static JSBool ShipRemoveDefenseTarget(JSContext *context, uintN argc, jsval *vp);
static JSBool ShipAddCollisionException(JSContext *context, uintN argc, jsval *vp);
static JSBool ShipRemoveCollisionException(JSContext *context, uintN argc, jsval *vp);
static JSBool ShipGetMaterials(JSContext *context, uintN argc, jsval *vp);
static JSBool ShipGetShaders(JSContext *context, uintN argc, jsval *vp);
static JSBool ShipBecomeCascadeExplosion(JSContext *context, uintN argc, jsval *vp);
@ -194,6 +196,7 @@ enum
kShip_cargoSpaceAvailable, // free cargo space, integer, read-only
kShip_cargoSpaceCapacity, // maximum cargo, integer, read-only
kShip_cargoSpaceUsed, // cargo on board, integer, read-only
kShip_collisionExceptions, // collision exception list, array, read-only
kShip_contracts, // cargo contracts contracts, array - strings & whatnot, read only
kShip_commodity, // commodity of a ship, read only
kShip_commodityAmount, // commodityAmount of a ship, read only
@ -336,6 +339,7 @@ static JSPropertySpec sShipProperties[] =
{ "cargoSpaceUsed", kShip_cargoSpaceUsed, OOJS_PROP_READONLY_CB },
{ "cargoSpaceCapacity", kShip_cargoSpaceCapacity, OOJS_PROP_READONLY_CB },
{ "cargoSpaceAvailable", kShip_cargoSpaceAvailable, OOJS_PROP_READONLY_CB },
{ "collisionExceptions", kShip_collisionExceptions, OOJS_PROP_READONLY_CB },
{ "commodity", kShip_commodity, OOJS_PROP_READONLY_CB },
{ "commodityAmount", kShip_commodityAmount, OOJS_PROP_READONLY_CB },
// contracts instead of cargo to distinguish them from the manifest
@ -461,6 +465,7 @@ static JSFunctionSpec sShipMethods[] =
{
// JS name Function min args
{ "abandonShip", ShipAbandonShip, 0 },
{ "addCollisionException", ShipAddCollisionException, 1 },
{ "addDefenseTarget", ShipAddDefenseTarget, 1 },
{ "awardEquipment", ShipAwardEquipment, 1 },
{ "becomeCascadeExplosion", ShipBecomeCascadeExplosion, 0 },
@ -512,6 +517,7 @@ static JSFunctionSpec sShipMethods[] =
{ "reactToAIMessage", ShipReactToAIMessage, 1 },
{ "remove", ShipRemove, 0 },
{ "removeCollisionException", ShipRemoveCollisionException, 1 },
{ "removeDefenseTarget", ShipRemoveDefenseTarget, 1 },
{ "removeEquipment", ShipRemoveEquipment, 1 },
{ "requestHelpFromGroup", ShipRequestHelpFromGroup, 0},
@ -832,6 +838,11 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsid propID, j
case kShip_commodityAmount:
*value = INT_TO_JSVAL([entity commodityAmount]);
return YES;
case kShip_collisionExceptions:
result = [entity collisionExceptions];
break;
case kShip_speed:
return JS_NewNumberValue(context, [entity flightSpeed], value);
@ -3155,6 +3166,56 @@ static JSBool ShipRemoveDefenseTarget(JSContext *context, uintN argc, jsval *vp)
}
static JSBool ShipAddCollisionException(JSContext *context, uintN argc, jsval *vp)
{
OOJS_PROFILE_ENTER
ShipEntity *thisEnt = nil;
ShipEntity *target = nil;
GET_THIS_SHIP(thisEnt);
if (EXPECT_NOT(argc == 0 || (argc > 0 && (JSVAL_IS_NULL(OOJS_ARGV[0]) || !JSVAL_IS_OBJECT(OOJS_ARGV[0]) || !JSShipGetShipEntity(context, JSVAL_TO_OBJECT(OOJS_ARGV[0]), &target)))))
{
OOJSReportBadArguments(context, @"Ship", @"addCollisionException", 1U, OOJS_ARGV, nil, @"other ship");
return NO;
}
// have to do it both ways because it's not defined which order
// the collisions get tested in. More efficient to add both ways
// than to test both ways
[thisEnt addCollisionException:target];
[target addCollisionException:thisEnt];
OOJS_RETURN_VOID;
OOJS_PROFILE_EXIT
}
static JSBool ShipRemoveCollisionException(JSContext *context, uintN argc, jsval *vp)
{
OOJS_PROFILE_ENTER
ShipEntity *thisEnt = nil;
ShipEntity *target = nil;
GET_THIS_SHIP(thisEnt);
if (EXPECT_NOT(argc == 0 || (argc > 0 && (JSVAL_IS_NULL(OOJS_ARGV[0]) || !JSVAL_IS_OBJECT(OOJS_ARGV[0]) || !JSShipGetShipEntity(context, JSVAL_TO_OBJECT(OOJS_ARGV[0]), &target)))))
{
OOJSReportBadArguments(context, @"Ship", @"removeCollisionException", 1U, OOJS_ARGV, nil, @"other ship");
return NO;
}
// doesn't need a check to see if it was already gone
[thisEnt removeCollisionException:target];
[target removeCollisionException:thisEnt];
OOJS_RETURN_VOID;
OOJS_PROFILE_EXIT
}
//getMaterials()
static JSBool ShipGetMaterials(JSContext *context, uintN argc, jsval *vp)
{