Best way to do Power Struggles?

Locked
MDaveUK
Posts: 11
Joined: Fri May 01, 2009 2:01 pm

Best way to do Power Struggles?

Post by MDaveUK »

I need help here, having major headaches over this :(

What Power Struggles in the game I'm working on is, is the following:

An energy ball (or missile/bolt in q3 terms) fired by the player has a certain amount of power in to it, and this energy ball can collide with other energy balls and depending on the amount of power the energy ball has, it can either push back the other ball or get pushed back.

The part I'm having problems with, is when they collide, and making them stay stuck together as they move back and forth (which is done by the player pumping in more power if the energy ball is linked to the player by a beam). They either don't stick together properly as they struggle, or their direction changes or they kinda vibrate together in place really glitchy looking :P I also have the problem of the energy balls sometimes passing through players and not blowing up on contact with them.

I guess I should post code related to this, but it's a lot.

Anybody provide examples on how I should do this in code? Or any good approaches to doing this properly in quake 3?

I can link to a copy of the c file if that helps, but be prepared to try and understand what's going on :P haha

EDIT: Here is a quick and dirty video I put together of the game, anyone that wants to help please post! :)
http://www.youtube.com/watch?v=x95sAvaUgIw
Last edited by MDaveUK on Sun Jul 05, 2009 8:42 pm, edited 1 time in total.
Silicone_Milk
Posts: 2237
Joined: Sat Mar 12, 2005 10:49 pm

Re: Best way to do Power Struggles?

Post by Silicone_Milk »

On energy ball's think() function just copy the think function for the rocket. This will keep the two colliding energy balls separate so another player can knock the front or back energy ball off their current trajectory.

The Rocket Launcher missile code will have the code you'll need to have projectile movement and non-glitchy player collision in it.
MDaveUK
Posts: 11
Joined: Fri May 01, 2009 2:01 pm

Re: Best way to do Power Struggles?

Post by MDaveUK »

Well, I've got a similar setup that thought did the same thing. But it seems the way I'm adjusting the speed and trajectory is not really working. Here is some code:

This function below gets called from the G_RunMissile function if the missile impacts with another in the G_MissileImpact function (turning on it's self->strugglingAttack qboolean). If the boolean is true it runs the function from G_RunMissile basically so it gets called every frame it's struggling. :)

This is where we try to calculate it's power (and speed) against the other missile's.

Code: Select all

void G_PowerStruggleUserWeapon(gentity_t *self, gentity_t *other, trace_t *trace) {
	int difference1,difference2,power1,power2,speed1,speed2;
	float speedScale1,speedScale2;
	speed1 = self->speed;
	speed2 = other->speed;
	power1 = self->powerLevel;
	power2 = other->powerLevel;
	difference1 = power1-power2;
	difference2 = power2-power1;
	if(difference1 > 0){
		speedScale1 = ((float)difference1 / (float)power2);
		speedScale2 = -((float)(speed1 * speedScale1) / (float)speed2);
	}
	else if(difference2 > 0){
		speedScale2 = ((float)difference2 / (float)power1);
		speedScale1 = -((float)(speed2 * speedScale2) / (float)speed1);
	}
	else{
		speedScale1 = 0;
		speedScale2 = 0;
	}
	// Don't go zipping away at light speed now!
	if(speedScale1 > 1){speedScale1 = 1;}
	if(speedScale1 < -1){speedScale1 = -1;}
	self->bounceFrac = speedScale1;
	// If both attacks are missiles and are equal in power, make them bounce off each other instead.
	if(speedScale1 == 0 && speedScale2 == 0 && self->s.eType == ET_MISSILE && other->s.eType == ET_MISSILE){
		self->bounceFrac = 1;
		self->r.ownerNum = other->s.number;
		G_BounceUserMissile(self, trace);
		self->strugglingAttack = qfalse;
	}else{
		G_StruggleUserMissile(self,other,trace);
	}
	//G_Printf("Attack Owner: %i Speed Scale %f Speed %f Power: %i Difference: %i\n", self->s.clientNum, speedScale1, self->speed, self->powerLevel, difference1);
}
And this is how we determine how to move it and stuff ... I'm sure this code could look a lot smaller and neater, but it's a mess as I try to frustratingly get it working right :P

Code: Select all

static void G_StruggleUserMissile( gentity_t *self, gentity_t *other, trace_t *trace ) {
	vec3_t	velocity;
	vec3_t	dir;
	float	dot;
	int		hitTime;

	//if(self->client->ps.bitFlags & usingBoost && self->s.eType == ET_BEAMHEAD){
	//	self->bounceFrac += 1.0 - (self->client->ps.powerLevel[plMaximum] / self->client->ps.powerLevel[plCurrent]);
	//}

	if(self->bounceFrac > other->bounceFrac){
		if(self->s.eType == ET_MISSILE){
			VectorCopy(self->s.angles,dir);
		}else{
			VectorCopy(self->client->ps.viewangles,dir);
		}
		hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction;
		BG_EvaluateTrajectoryDelta( &self->s, &self->s.pos, hitTime, velocity );
		dot = DotProduct( velocity, dir );
		VectorMA( velocity, -2 * dot, dir, self->s.pos.trDelta );

		VectorScale( self->s.pos.trDelta, self->bounceFrac, self->s.pos.trDelta );

		VectorAdd( self->r.currentOrigin, dir, self->r.currentOrigin);
		VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
	}else if(other->s.eType == ET_MISSILE || other->s.eType == ET_BEAMHEAD){
		self->r.ownerNum = other->s.number;
		VectorCopy( other->s.pos.trDelta, self->s.pos.trDelta );
		VectorCopy( other->r.currentOrigin, self->s.pos.trBase );
	}

	self->s.pos.trTime = level.time;
	// check for stop
	if ( self->s.eType == ET_MISSILE && other->s.eType == ET_MISSILE && VectorLength( self->s.pos.trDelta ) < 40 ) {
		G_ExplodeUserWeapon ( self );
		return;
	}
}
MDaveUK
Posts: 11
Joined: Fri May 01, 2009 2:01 pm

Re: Best way to do Power Struggles?

Post by MDaveUK »

Alright, fixed it!

This seems to work good enough :)

Code: Select all

void Think_NormalMissileStruggle (gentity_t *self) {
	int difference1,difference2,power1,power2,speed1,speed2;
	vec3_t forward;

	speed1 = self->speed;
	speed2 = self->enemy->speed;
	power1 = self->powerLevel;
	power2 = self->enemy->powerLevel;
	difference1 = power1-power2;
	difference2 = power2-power1;

	// If both attacks are missiles and are equal in power, make them bounce off each other instead.
	if(speedScale1 == 0 && speedScale2 == 0 && self->s.eType == ET_MISSILE && self->enemy->s.eType == ET_MISSILE){
		self->bounceFrac = 1;
		self->r.ownerNum = self->enemy->s.number;
//		G_BounceUserMissile(self, trace);
		self->strugglingAttack = qfalse;
	}else{
		// Best way to get forward vector for this rocket?
		VectorCopy(self->s.pos.trDelta, forward);
		VectorNormalize(forward);
		VectorCopy( self->r.currentOrigin, self->s.pos.trBase );
		self->s.pos.trTime = level.time;
		self->s.pos.trType = TR_LINEAR;
		VectorScale( forward, difference1, self->s.pos.trDelta );
		SnapVector( self->s.pos.trDelta );
		VectorCopy( self->s.pos.trBase, self->r.currentOrigin);
	}

	if (!self->strugglingAttack){
		self->think = Think_NormalMissile;
	}

	self->nextthink = level.time;
}
Here is a quick and dirty video I put together of the game, anyone that wants to help please post! I did this video before I fixed the problem though, so that's why we don't see the 2 attacks collide at the end of the video, hah.
http://www.youtube.com/watch?v=x95sAvaUgIw
4days
Posts: 5465
Joined: Tue Apr 16, 2002 7:00 am

Re: Best way to do Power Struggles?

Post by 4days »

MDaveUK wrote:http://www.youtube.com/watch?v=x95sAvaUgIw
not a db fan, but that looks great. nice work :up:
MDaveUK
Posts: 11
Joined: Fri May 01, 2009 2:01 pm

Re: Best way to do Power Struggles?

Post by MDaveUK »

Thanks!

Alright, been tweaking things a bit, but I can't get the attacks to remain smooth in movement, they seem to jump a bit back and forth, and the effect is seen greater when the attacks have quite a bit of speed. Any advice on how to fix that? This is my struggle code at the moment:

Note: ET_BEAMHEAD is the same as a missile type attack, except the player can have the attack power and speed increased for the duration of the struggle, and the player cannot move, in case people wonder :P

Code: Select all

/*
=====================
Think_NormalMissileStruggle
=====================
*/
void Think_NormalMissileStruggle (gentity_t *self) {
	int			powerDifference;
	int			speedDifference;
	int			power1,power2;
	int			speed1,speed2;
	int			result;
	vec3_t		forward;
	gentity_t	*missileOwner;
	trace_t		*trace;
	missileOwner = GetMissileOwnerEntity( self );
	if((missileOwner->client->ps.bitFlags & usingBoost) && self->s.eType == ET_BEAMHEAD){
		self->powerLevelTotal += 1 + ((float)missileOwner->client->ps.powerLevel[plMaximum] * 0.0003);
		self->speed += 1 + ((float)missileOwner->client->ps.powerLevel[plMaximum] * 0.0003);
	}
	if(self->strugglingAllyAttack){
		if(self->s.eType == ET_BEAMHEAD){
			self->ally->powerLevelTotal += 1 + ((float)self->powerLevelTotal * 0.0003);
			self->ally->speed += 1 + ((float)self->speed * 0.0003);
		}else{
			self->powerLevelTotal -= 1;
			self->speed -= 1;
			self->ally->powerLevelTotal += 1;
			self->ally->speed += 1;
		}
	}
	speed1 = self->speed;
	speed2 = self->enemy->speed;
	power1 = self->powerLevelTotal;
	power2 = self->enemy->powerLevelTotal;
	speedDifference = speed1-speed2;
	powerDifference = power1-power2;
	result = speedDifference + powerDifference;
	// If the other attack stopped struggling for whatever reason, resume moving forward.
	if(!self->enemy->strugglingAttack){
		self->bounceFrac = 1;
		VectorCopy(self->s.pos.trDelta,forward);
		VectorNormalize(forward);
		VectorScale(forward,self->speed,self->s.pos.trDelta);
		G_BounceUserMissile(self,trace);
		self->strugglingAttack = qfalse;
		self->strugglingAllyAttack = qfalse;
		self->think = Think_NormalMissile;
		self->nextthink = level.time;
		//G_Printf("Moving forward again!\n");
		return;
	}
	// Help ally with struggle!
	if(self->strugglingAllyAttack){
		VectorCopy(self->ally->s.pos.trBase,self->s.pos.trBase);
		VectorCopy(self->ally->s.pos.trDelta,self->s.pos.trDelta);
		if(self->s.eType != ET_BEAMHEAD){
			SnapVector(self->s.pos.trDelta);
		}
		VectorCopy(self->s.pos.trBase,self->r.currentOrigin);
		self->s.pos.trTime = level.time;
		self->s.pos.trType = TR_LINEAR;
		//G_Printf("Helping ally!\n");
	// Struggle away!
	}else{
		// Best way to get forward vector for this rocket?
		VectorCopy(self->s.pos.trDelta,forward);
		VectorNormalize(forward);
		VectorCopy(self->r.currentOrigin,self->s.pos.trBase);
		VectorScale(forward,result,self->s.pos.trDelta);
		if(self->s.eType != ET_BEAMHEAD){
			SnapVector(self->s.pos.trDelta);
			vectoangles(self->s.pos.trDelta,self->s.angles);
		}else{
			VectorCopy(self->client->ps.viewangles,self->s.angles);
		}
		self->s.pos.trTime = level.time;
		self->s.pos.trType = TR_LINEAR;
	}
	self->nextthink = level.time + FRAMETIME;
}

MDaveUK
Posts: 11
Joined: Fri May 01, 2009 2:01 pm

Re: Best way to do Power Struggles?

Post by MDaveUK »

Nevermind! Got it working smooth as silk now :D Here is the code just in case people want to know how I did it:

Code: Select all

	// Struggle away!
	}else{
		VectorCopy(self->r.currentOrigin,start);
		VectorCopy(self->s.pos.trDelta,dir);
		VectorCopy(self->r.currentAngles,dir2);
		VectorNormalize(dir);
		VectorScale(dir,0.2,dir);
		VectorAdd(dir,dir2,dir);
		VectorNormalize(dir);
		VectorCopy(start,self->s.pos.trBase);
		VectorScale(dir,result,self->s.pos.trDelta);
		VectorCopy(start,self->r.currentOrigin);
		VectorCopy(dir,self->r.currentAngles);
		self->s.pos.trType = TR_LINEAR;
		self->s.pos.trTime = level.time;
	}
I will probably come back with other questions on how to do something, and then probably figure it out myself again :P I never knew something can be fun and frustrating at the same time! Coding is a funny thing :P
User avatar
Eraser
Posts: 19174
Joined: Fri Dec 01, 2000 8:00 am

Re: Best way to do Power Struggles?

Post by Eraser »

I was reading this purely out of curiosity but have a slightly off topic remark to make.

Be careful that you don't end up like the Bid for Power TC. They were making a Dragonball Z total conversion as well but they were ordered to take it down because of infringement on intellectual property. Your TC seems to get even closer to the Dragonball Budokai games that are out right now so if they get air of what you're doing, you might be ordered to stop as well.

Bid For Power removed all Dragonball references and made their own worlds and character to replace them.
MDaveUK
Posts: 11
Joined: Fri May 01, 2009 2:01 pm

Re: Best way to do Power Struggles?

Post by MDaveUK »

Thanks for the concern, but these days (or should I say years :olo: ) I don't think it's something to worry about any more. Heck, valve are listing mods on their steam site that infringe on IP's. Even a Dragonball Z one! http://store.steampowered.com/app/90003/

Sure, that doesn't mean it's right, but it also shows they don't care any more. The way I see it, it also works in their favour by spreading the brand to those that don't know about it. But we've kept ourself's out of the radar for a good while already anyway just in case something COULD happen :)

On Topic-ish: It would be great to get bots to work right, any takers? :P I really only need them to move around in the air and move forward towards a player when they see one, and know how to charge attacks and release them. Melee would be pretty easy to do as well I think, based on what the other player is doing, make it randomly choose between a couple of actions like blocking or fighting back etc.
Locked