ShipEntity collideWithShip

For test results, bug reports, announcements of new builds etc.

Moderators: winston, another_commander, Getafix

Post Reply
User avatar
Cmdr James
Commodore
Commodore
Posts: 1357
Joined: Tue Jun 05, 2007 10:43 pm
Location: Berlin

ShipEntity collideWithShip

Post by Cmdr James »

this code looks odd

Code: Select all

	// apply change in velocity
	if ((otherIsSubentity)&&(otherParent))
		[otherParent adjustVelocity:vel1a];	// move the otherParent not the subentity
	else
		[self adjustVelocity:vel1a];
	[other adjustVelocity:vel2a];
should it be

Code: Select all

	// apply change in velocity
	if ((otherIsSubentity)&&(otherParent))
		[otherParent adjustVelocity:vel1a];	// move the otherParent not the subentity
	else
		[other adjustVelocity:vel1a];
	[self adjustVelocity:vel2a];
??

I was going to make a change so that if other is the main station (self cannot be a StationEntity) we do not change its location. This is due to the previously discussed weird things that can happen if you knock a station out of orbit.

This is just for my testing purposes, Im not going to do it in trunk etc. ;) but I suspect it would be a good idea if it doesnt break anything else.
User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

Seems likely. Try it, then go crashing into some ships and see what happens. :-)
User avatar
Cmdr James
Commodore
Commodore
Posts: 1357
Joined: Tue Jun 05, 2007 10:43 pm
Location: Berlin

Post by Cmdr James »

OK, I have done some experimentation, and this is the revised code which looks right (and tested a bit by me). This is almost exactly like the code already there, so dont get all excited about how much super new stu I am providing, its about 3 new lines :(

Code: Select all

- (BOOL) collideWithShip:(ShipEntity *)other
{
	Vector  loc, opos, pos;
	double  inc1, dam1, dam2;
	
	if (!other)
		return NO;
	
	ShipEntity* otherParent = (ShipEntity*)[other owner];
	BOOL otherIsSubentity = ((otherParent)&&(otherParent != other)&&([otherParent->sub_entities containsObject:other]));
	BOOL otherIsStation = other == [UNIVERSE station];
	// calculate line of centers using centres
	if (otherIsSubentity)
		opos = [other absolutePositionForSubentity];
	else
		opos = other->position;
	loc = opos;
	loc.x -= position.x;	loc.y -= position.y;	loc.z -= position.z;

	if (loc.x||loc.y||loc.z)
		loc = unit_vector(&loc);
	else
		loc.z = 1.0;

	inc1 = (v_forward.x*loc.x)+(v_forward.y*loc.y)+(v_forward.z*loc.z);

	if ([self canScoop:other])
	{
		[self scoopIn:other];
		return NO;
	}
	if ([other canScoop:self])
	{
		[other scoopIn:self];
		return NO;
	}
	if (universalID == NO_TARGET)
		return NO;
	if (other->universalID == NO_TARGET)
		return NO;

	// find velocity along line of centers
	//
	// momentum = mass x velocity
	// ke = mass x velocity x velocity
	//
	GLfloat m1 = mass;			// mass of self
	GLfloat m2 = [other mass];	// mass of other

	// starting velocities:
	Vector	vel1b =	[self velocity];
	// calculate other's velocity relative to self
	Vector	v =	[other velocity];
	if (otherIsSubentity)
	{
		if (otherParent)
		{
			v = [otherParent velocity];
			// if the subentity is rotating (subentityRotationalVelocity is not 1 0 0 0)
			// we should calculate the tangential velocity from the other's position
			// relative to our absolute position and add that in. For now this is a TODO
		}
		else
			v = kZeroVector;
	}

	//
	v = make_vector(vel1b.x - v.x, vel1b.y - v.y, vel1b.z - v.z);	// velocity of self relative to other

	//
	GLfloat	v2b = dot_product(v, loc);			// velocity of other along loc before collision
	//
	GLfloat v1a = sqrt(v2b * v2b * m2 / m1);	// velocity of self along loc after elastic collision
	if (v2b < 0.0f)	v1a = -v1a;					// in same direction as v2b


	// are they moving apart at over 1m/s already?
	if (v2b < 0.0f)
	{
		if (v2b < -1.0f)  return NO;
		else
		{
			position = make_vector(position.x - loc.x, position.y - loc.y, position.z - loc.z);	// adjust self position
			v = kZeroVector;	// go for the 1m/s solution
		}
	}

	// convert change in velocity into damage energy (KE)
	//
	dam1 = m2 * v2b * v2b / 50000000;
	dam2 = m1 * v2b * v2b / 50000000;

	// calculate adjustments to velocity after collision
	Vector vel1a = make_vector(-v1a * loc.x, -v1a * loc.y, -v1a * loc.z);
	Vector vel2a = make_vector(v2b * loc.x, v2b * loc.y, v2b * loc.z);

	if (magnitude2(v) <= 0.1)	// virtually no relative velocity - we must provide at least 1m/s to avoid conjoined objects
	{
			vel1a = make_vector(-loc.x, -loc.y, -loc.z);
			vel2a = make_vector(loc.x, loc.y, loc.z);
	}

	// apply change in velocity
	if ((otherIsSubentity)&&(otherParent))
		[otherParent adjustVelocity:vel2a];	// move the otherParent not the subentity
	else
		[other adjustVelocity:vel2a];

	[self adjustVelocity:vel1a];

	//
	BOOL selfDestroyed = (dam1 > energy);
	BOOL otherDestroyed = (dam2 > [other energy]) && !otherIsStation;
	//
	if (dam1 > 0.05)
	{
		[self takeScrapeDamage: dam1 from:other];
		if (selfDestroyed)	// inelastic! - take xplosion velocity damage instead
		{
			vel2a.x = -vel2a.x;	vel2a.y = -vel2a.y;	vel2a.z = -vel2a.z;
			[other adjustVelocity:vel2a];
		}
	}
	//
	if (dam2 > 0.05)
	{
		if ((otherIsSubentity) && (otherParent) && !([otherParent isFrangible]))
			[otherParent takeScrapeDamage: dam2 from:self];
		else
			[other	takeScrapeDamage: dam2 from:self];
		if (otherDestroyed)	// inelastic! - take explosion velocity damage instead
		{
			vel1a.x = -vel1a.x;	vel1a.y = -vel1a.y;	vel1a.z = -vel1a.z;
			[self adjustVelocity:vel1a];
		}
	}
	
	if ((!selfDestroyed)&&(!otherDestroyed))
	{
		float t = 10.0 * [UNIVERSE getTimeDelta];	// 10 ticks
		//
		pos = self->position;
		opos = other->position;
		//
		Vector pos1a = make_vector(pos.x + t * v1a * loc.x, pos.y + t * v1a * loc.y, pos.z + t * v1a * loc.z);
		Vector pos2a = make_vector(opos.x - t * v2b * loc.x, opos.y - t * v2b * loc.y, opos.z - t * v2b * loc.z);
		//
		[self setPosition:pos1a];
		if (!otherIsStation) {
			[other setPosition:pos2a];
		}
	}

	// remove self from other's collision list
	[[other collisionArray] removeObject:self];

	[shipAI reactToMessage:@"COLLISION"];

	return YES;
}
The main differences are:
* As detailed above, some inconsistent handling of ships with subentites (although what I wrote above was the wrong way about)
*

Code: Select all

		if (otherDestroyed)	// inelastic! - take explosion velocity damage instead
		{
			vel1a.x = -vel1a.x;	vel1a.y = -vel1a.y;	vel1a.z = -vel1a.z;
			[other adjustVelocity:vel1a];
		}
Does not make sense to move other, we know it is destroyed. Compare to code where selfDestroyed and we can see expected behaviour.
* I added code to prevent the station getting shunted around, anyone think this is a good or bad idea?

Code: Select all

		if (!otherIsStation) {
			[other setPosition:pos2a];
		}
I have not added this to svn, but I think it is right, anyone else got a view on it?
another_commander
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 6682
Joined: Wed Feb 28, 2007 7:54 am

Post by another_commander »

If you have tested this sufficiently and think it works OK, I guess you could go on and put it in SVN. As for the station staying put, I agree. I'd rather have it getting destroyed than ejected to space at high velocity.
Post Reply