Game Development Community

AI + interpolate = very good shot

by Mr Meikel · in Torque Game Engine · 02/21/2006 (2:21 pm) · 3 replies

Hi,

(skip to bold if you want :P )

I've been working on aiPlayer.cs for about a week now (pretty new at torque), in an attempt to both learn the language and make a sem-decent bot. Up til now I've been trying to get it to follow the player using waypoints (A* precompiled navnets from a very nice resource :) ), as well as dodge, choose targets intelligently and have "characteristics" which can be different for each bot I spawn.

Tonight I tackled the actual aiming of the bot, as my current .setAimObject(%target, "0 0 2.8") was not up to scratch. I had heard of interpolation, and decided to have a go at making my own interpolate function for my bots. Basicly, my bot takes the position of the player, the speed of the bots current projectile, and the velocity of the player, and attempts to "guess" where the player will be in the time taken for the projectile to reach him.

The real reason I posted this thread was for a little advice, and to show off my nice interpolate function :)

(skip to bold again if you just want the code, and to help me with my problem!)

So, the bot works out where the player will be in x seconds (x being the time taken for proj to get to his position), however, where the player will be in x seconds might mean it will take y seconds for the projectile to get there, not x - this conundrum I think I have solved :)

I played around with an offset, adjusting %projectileTimeToGetThere by 0.1 though to 1. I collected echo()'ed out my distance from the bot whilst circling it - and to cut a long story short got some data, of which I had a correlation of 0.97ish - I was very happy :)

Anyway, I worked out the linear regression line of my data, and now my bot hits me ALOT of the time - seriously 9 times out of 10 at least! He really is an excellent shot now!

On with the code! Although I recomend you read my badly written post anyway!

No idea how you want to implement this, and I don't want to restrict you, so I'll just post the main bit of my interpolate function (doesn't check to see if we have a target, if we are dead etc etc)

function AIPlayer::InterpolateAim(%this, %cancel)
{
	if (%cancel == true)
	{
		cancel(%this.interpolateSchedule);
		return 0;
	}
	if (!isObject(%this.curTarget["Player"]))
	{
		//target has died
		cancel(%this.interpolateSchedule);
		return 0;
	}
	if (%this.getState() $= "dead")		// check we are not dead
	{
		cancel(%this.interpolateSchedule);
		return 0;
	}
	//%targetPosition, %targetDistance, %targetVelocity, %projSpeed
	[b]%projectileSpeed = 20; //need help here!!! [/b]
	%targetVelocity = %this.curTarget["Player"].getVelocity();
	%targetPosition = %this.curTarget["Player"].getPosition();
	%targetDistance = vectorDist(%this.getPosition(), %targetPosition);
	%projTTL = %targetDistance / %projectileSpeed;
	[b]%offset = 0.35 + 0.03742 * (%targetDistance - 10.8333); //!!!!!!! the magic bit! [/b]
	%projTTL = %projTTL - %offset;
	%interpolatedTargetPosition = 
		getWord(%targetPosition,0) + (%projTTL * getWord(%targetVelocity,0)) SPC
		getWord(%targetPosition,1) + (%projTTL * getWord(%targetVelocity,1)) SPC
		getWord(%targetPosition,2) + (%projTTL * getWord(%targetVelocity,2)) + 2.8;
		//2.8 is required to make it aim at my head!
	%this.setAimLocation(%interpolatedTargetPosition);
	%this.interpolateSchedule = %this.schedule(100, InterpolateAim);

}

the bit I have bolded is where I need help myself - I have no idea how to get the projectile speed at runtime, so I just looked it up in crossbow.cs (still using default crossbow) and put in muzzleVelocity.

Anyway, to summerise a (stupidly) long post, have a go with this interpolate function, %this.curTarget["Player"] is just the handle of my current target as a player object - you could of course add a parameter which is the %player. I think everything else is self-explanatory - and I'd be very grateful if someone could help me with my problem (see above)!!!

#1
02/21/2006 (2:53 pm)
Nice work!

You should be able to get the muzzleVelocity by doing something like this:

// Grab the ShapeBaseImage of our gun (this assumes it is in slot 0...you could point
// this at a dynamic variable on your AIPlayer like AIPlayer.gunSlot
%weaponImage = %this.getMountedImage(0);

// Now snag the projectile datablock from that image
// This is a dynamic field set up in the ShapeBaseImageData (for example in
// CrossbowImage in crossbow.cs
%projectileDatablock = %weaponImage.projectile;

// Last grab the muzzleVelocity from this
%projectileSpeed = %projectileDatablock.muzzleVelocity

// This could all be consolidated into:
%projectileSpeed =  %this.getMountedImage(0).projectile.muzzleVelocity;

I'm curious why you used setAimLocation() instead of setAimObject(%target, %offset). Just don't add in the %targetPosition and you should have a nice offset/lead which will be a little more accurate b/c it can track some of the secondary motions of the %target (it'll also look a little smoother) and you can tick your interpolate function little less often (this function is going to be somewhat costly being ticked every 100ms...especially if you add more bots). You can also vary the tick time to easily simulate different skill levels of your bots.
#2
02/21/2006 (11:47 pm)
Wow thanks very much! I noticed the projectile field in the Image, but had no idea how I could use that to get the datablock of that projectile!

I had been using setAimObject, but once I compiled my data and found "%offset = 0.35 + 0.03742 * (%targetDistance - 10.8333);" I was outstanded by my bots accuracy!

Whether you are circle strafing or attempting to dodge, it will hit you 9 times out of 10. Please don't take my word for it - I implore you all to try it for yourself!
#3
02/22/2006 (1:59 pm)
This sounds really neat. I've bookmarked it so I'll check it out whenever I get to work AI again.