Advertisement

Space Combat game AI problem

Started by June 19, 2011 12:44 AM
22 comments, last by StephanieWhite 13 years, 1 month ago
So I have some code here that is meant to find the ideal position and orientation relative to a target ship for attacking it. Here's the code:



var thisShip : GameObject;
static var hasPath : boolean=false;
var enemyTarget : GameObject;
var empty : GameObject;

function Update () {
if (hasPath==false){
var positions : Vector3[]=new Vector3[6*3*6*6*6*6*6];
var orientation : Vector3[]=new Vector3[6*3*6*6*6*6*6];
var enemyDamage : int[]=new int[3*6*6*6*6*6*6];
var damageTaken : int[]=new int[3*6*6*6*6*6*6];
var expectedGain : int[]=new int[3*6*6*6*6*6*6];
var counter : int=0;
for (var i : int=0; i<6; i++){
for (var e : int=0; e<6; e++){
for (var u : int=0; u<6; u++){
for (var n : int=0; n<3; n++){
for (var t : int=0; t<6; t++){
for (var m : int=0; m<6; m++){
for (var q : int=0; q<6; q++){
positions[counter]=findPosition(i*60, e*60, u*60, n*100);
orientation[counter]=Vector3(t*60, m*60, q*60);
enemyDamage[counter]=findDamage(enemyTarget, thisShip, positions[counter], orientation[counter], "attacker");
damageTaken[counter]=findDamage(thisShip, enemyTarget, positions[counter], orientation[counter], "defender");
expectedGain[counter]=calcGains(enemyDamage[counter], damageTaken[counter]);
counter++;
an=i;
}
}
}
}
}
}
}
var dec : int=1;
for (i=0; i<expectedGain.length; i++){
if (expectedGain>expectedGain[dec]){
dec=i;
}
}
hasPath=true;
}

if (hasPath==true){
GetComponent("ship guidance").positioning=positions[dec];
}
}

function findPosition(xangle : int, yangle : int, zangle : int, d : int){
var anobject : GameObject=Instantiate(empty, enemyTarget.transform.position, Quaternion.identity);
anobject.transform.rotation.eulerAngles.x=xangle;
anobject.transform.rotation.eulerAngles.y=yangle;
anobject.transform.rotation.eulerAngles.z=zangle;
anobject.transform.Translate(anobject.transform.forward*d);
var thepos : Vector3=anobject.transform.position;
Destroy(anobject);
return thepos;
}

// this code finds the damage that a ship will take from a resulting position
function findDamage(targetCraft : GameObject, attackingCraft : GameObject, positioning : Vector3, rotating : Vector3, dataType : String){
var totalDamage : int=0;
var initialObject : GameObject=Instantiate(empty, attackingCraft.transform.position, attackingCraft.transform.rotation);
if (dataType=="attacker"){
// there needs to be a way to move a 'ghosted' object around. How this will be done is a good question.
//this method should get it to work
initialObject.transform.position=positioning;
var totalWeps : Vector3[]=new Vector3[attackingCraft.GetComponent("attributes").weapons.length];
for (var i : int=0; i<attackingCraft.GetComponent("attributes").weapons.length; i++){
var dist : int=Vector3.Distance(attackingCraft.transform.position, attackingCraft.GetComponent("attributes").weaponsPosition);
var dir : Vector3=attackingCraft.transform.position-attackingCraft.GetComponent("attributes").weaoponsPosition;
dir=attackingCraft.transform.InverseTransformPoint(dir);
var originalRot : Vector3=initialObject.transform.rotation.eulerAngles;
initialObject.transform.rotation.eulerAngles=rotating;
dir=attackingCraft.transform.TransformPoint(dir);
var pos : Vector3=dist*dir;
totalWeps=pos;
}
for (i=0; i<attackingCraft.GetComponent("attributes").weapons.length; i++){
for (var n : int=0; n<targetCraft.GetComponent("attributes").partsListPosition.length; n++){
if (Physics.Linecast(totalWeps, targetCraft.GetComponent("attributes").partsListPosition[n])==false){
if (attackingCraft.GetComponent("attributes").weaponsDamage>=targetCraft.GetComponent("attributes").partsListHealth[n]+targetCraft.GetComponent("attributes").partsListArmor[n]){
totalDamage+=targetCraft.GetComponent("attributes").partsListExplosive[n];
}
if (attackingCraft.GetComponent("attributes").weaponsDamage<targetCraft.GetComponent("attributes").partsListHealth[n]+targetCraft.GetComponent("attributes").partsListArmor[n]){
totalDamage-=targetCraft.GetComponent("attributes").partsListArmor[n];
totalDamage+=attackingCraft.GetComponent("attributes").weaponsDamage;
}
}
}
}
Destroy(initialObject);
return totalDamage;
}
if (dataType=="defender"){
initialObject.transform.position=positioning;
initialObject.transform.rotation.eulerAngles=rotating;
for (i=0; i<targetCraft.GetComponent("attributes").weapons.length; i++){
for (n=0; n<(attackingCraft.GetComponent("attributes").bow/2)/10; n++){
if (Physics.Linecast(targetCraft.GetComponent("attributes").weaponsPosition, (initialObject.transform.position+(initialObject.transform.forward*n*10)))==false){
totalDamage+=targetCraft.GetComponent("attributes").weaponsDamage;
}
}
}
Destroy(initialObject);
return totalDamage;
}
}

function calcGains(damageDealed : int, damageTaken : int){
//let's toss in a calcRisk function some time from now
var totalGain : int=damageDealed-damageTaken;
return totalGain;
}


All those nested loops cycle through angles and distances for different positions and store data for each position/orientation set. The findPosition function simply finds the position from a distance from an orientation from the target ship. Then the calcDamage function finds how much damage is dealed to the enemy ship and how much damage is taken. The thing is that this function involves the use of instantiating objects. These objects should be deleted upon completion of the program, but instead, Unity keeps on drawing them, and the position data is not delivered to the ship guidance system. Anyone have any idea hat is causing this? I've even tried separating the loops into separate scripts, and even that yields the same result. Thanks for any assistance you can render (in advance)!

No one expects the Spanish Inquisition!

Is this an AI question or a Unity question? Does your solution work? I couldn't quite work out whats going on, some more info on your game would be helpful. Is it 2d/3d, what affects damage. Can the ideal position/orientation be anything or does it have a limit. Can you accept non-optimal solutions?

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Advertisement
I suppose this is an AI question (mainly a what am I doing wrong question, but not limited to that), and no, my solution simply makes a seemingly inifinte amount of empty game objects (as points I believe), so I just end the program after five minutes or so. It doesn't come up with a position/orientation while running. Damage is basically a function of the damage a weapon can deal (which is just a number arbitrarily assigned by me) minus the armor of the part (another arbitrary number). If this value exceeds the health value of the part, the part explodes, which has a seperate damage value (this explosive value becomes the damage). The game is also 3d, and the ideal position/orientation can be anything. However, the problem lies here that the code does not come up with an ideal position/orientation and simply continues to instantiate empty game objects. By non-optimal, I assume you mean below standards? There really is no standard, just whichever one has the best expected value (calculated via calcGains function).

Essentially, each loop is for a euler angle, with one loop for distance. There are two sets of euler angle loops, as the one is for positioning from the target ship (ie; think of it as casting a line from a ship in different directions to get a position at a certain distance) and the other set is orientations for this ship. Once it finds the best position/orientation from the list, it proceeds to update the ship's guidance component (which for some reason does not happen).

The game is essentially a space combat sim (the way I see it at least), and involves the player controling a ship (can be selected from various classes). It's got more to it, but essentially, I'm just trying to build a system that can pick a point/orientation that is best for attacking the player.

I hope this helps you to understand my code.

No one expects the Spanish Inquisition!

var dist : int=Vector3.Distance(attackingCraft.transform.position, attackingCraft.GetComponent("attributes").weaponsPosition);
var dir : Vector3=attackingCraft.transform.position-attackingCraft.GetComponent("attributes").weaoponsPosition;





possible typo here?

OpenGL fanboy.
Yes, that's definitely a typo, I'll give it another look, with the typo fixed....

No one expects the Spanish Inquisition!

No change in the result with the typo fixed, it simply continues to instantiate many more empty gameObjects without any returns being given. Any other possibilities?

No one expects the Spanish Inquisition!

Advertisement
I've isolated the problem to be within the calcDamage function. Looks like I need a new algorithm. If anyone wants to add their suggestions or something, feel free to do so.

No one expects the Spanish Inquisition!

How good is your calculus?

The typical approach to this is to formulate a multivariate function that accepts various angles as inputs and produces a scoring value, perhaps on the interval [0,1]. You then find the zeroes of the first-order derivative of the function to find local minima and maxima, which represent optimal solutions to the problem. There will be a number of constants and various coefficients which must be fed in beforehand; these you can leave abstract initially and just fill in the blanks in the differentiated version later once you work it out on paper.

Ideally, you could do this as a vector equation and eliminate Euler angles altogether, but that changes the nature of the mathematics somewhat. Depends on whether your trig or your linear algebra is stronger smile.gif

The best approach though is probably to toss optimal solutions to the wind and just do some heuristics to guess at a good attack angle. Real pilots don't sit down with a calculator and sort out the perfect angle of attack and such before entering a dogfight; they rely on instinct and rapid reactions to dynamic situations. All the math in the world won't save your ass if you're busy computing while the other guy loops in behind your six and drops a missile into your tailpipe.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I have managed to teach myself calculus actually (I can derive and integrate, I haven't really tried multi-variate functions, but hey, I'll give it a shot :) ). My trig and linear algebra are probably better though, so I might want to look into the vector equation.....although I'm not entirely sure I follow.

I see what you mean by the heuristics though, and that does seem like it would work. I'll give all of these a look I guess, and look at multi-variate derivation.....

No one expects the Spanish Inquisition!

Quick questions: does raycasting a lot slow down/possibly freeze a game program?

No one expects the Spanish Inquisition!

This topic is closed to new replies.

Advertisement