Studio2: More Bots

Following on from the previous post, this post is going to be about more vector math and prediction.

As it turns out, it was quite easy to predict where the enemy was going to be in the next update. As I suspected, I had all the information, I just had to use it correctly. I simply needed to add their velocity to their position and multiply that by the time passed.

enemyTempPos = newEnemyPos + enemyVelocity * deltaTime;//future enemy pos
playerTempPos = input.position + input.velocity * deltaTime;//future player pos

Next, I wanted into implement functionality to shoot more than once after discovering the enemy. This would prove slightly more challenging, as the current setup worked with only one shot. To do this I needed to refactor my code to utilise a statemachine so that I could more easily keep track of what the bot was doing. The bot logic can be in 3 states: Searching, Thinking, and Shooting. Searching was simply scanning in a circular direction until an enemy was found. Thinking is when an enemy is found, and their speed, velocity etc need to be calculated. THEN once this state is done, the bot will shoot.

Now that there was a working statemachine, I could properly implement my predictive shooting.

What I originally made and implemented was a hard coded value to utilise three shots. This occurred in the thinking stage:

//First shot
toShoot1 = FindInterceptVector(input.position, input.bulletSpeed, newEnemyPos, enemyVelocity);

//get info for second shot
enemyTempPos = newEnemyPos + enemyVelocity * deltaTime;//future enemy pos
playerTempPos = input.position + input.velocity * deltaTime;//future player pos

Do the same as the first shot, except use the new data
toShoot2 = FindInterceptVector(playerTempPos, input.bulletSpeed, enemyTempPos, enemyVelocity);
enemyTempPos2 = enemyTempPos + enemyVelocity * deltaTime;
playerTempPos2 = playerTempPos + input.velocity * deltaTime;
//and finally last shot
toShoot3 = FindInterceptVector(playerTempPos2, input.bulletSpeed, enemyTempPos2, enemyVelocity);

And in shooting, the code looked like this:

//this code is the same for the other two shots
if (shots == 3)
{
–shots;
output.lookDirection = toShoot1;
output.action = BotOutput::shoot;
//std::cout << “Shot1” << std::endl;
}

//start searching again when run out of bullets
else
{
output.lookDirection = toShoot3;
m_angle = atan2(output.lookDirection.y, output.lookDirection.x);
currState = CyborgTurtle::ebsSearching;
output.action = BotOutput::scan;
}

This worked fully as intended. However, I wasn’t happy with it. As we had been looking into genetic algorithms this week, I’m interested to see how I could improve my bot behaviour using it. And one of the things I want to test is the number of bullets being fired per scan. With this set up, that isn’t possible, as the values are hardcoded. So I came up with an alternative solution that allows the bot to dynamically shoot a given number of bullets accurately. The code turned a lot shorter, and a lot easier to manage in the process:

//starting positions
playerTempPos = input.position;
enemyTempPos = newEnemyPos;

for (int index = 0; index < toShoot.size(); ++index)//for each shot
{
//give the angle for the first shot
toShoot[index] = FindInterceptVector(playerTempPos, input.bulletSpeed, enemyTempPos, enemyVelocity);

//set up data for the next update cycle
enemyTempPos = enemyTempPos + enemyVelocity * deltaTime;
playerTempPos = playerTempPos + input.velocity * deltaTime;
}
And repeat until all targets identified

Then the Shooting stage looked like this:

if (!isShooting && shotCount == 0)
{
isShooting = true;//to keep track if the bot should still be shooting
}

if (isShooting)
{
//look at the appropriate target
output.lookDirection = toShoot[shotCount];/
output.action = BotOutput::shoot;
//increase the count so the next target is used
++shotCount;

if (shotCount > toShoot.size() – 1)//check if we’re out of targets
{
isShooting = false;
return;//this is needed becausethe bot can’t scan and shoot in the same update.
}
}

if (!isShooting && shotCount > 0)//should only trigger after shots are done
{
output.lookDirection = toShoot.back();//aim at last known position
shotCount = 0;
m_angle = atan2(output.lookDirection.y, output.lookDirection.x);
currState = CyborgTurtle::ebsSearching;
output.action = BotOutput::scan;
}

The result is a much more scalable code that can be tested for when I get into genetic algorithms. The idea being that the algorithm tester will randomly add or subtract a bullet, and hopefully the ideal bullet count will be selected. I expect the number will be two or three, as shooting longer than that means that the target bot could have moved and be out of harms way.

I think the next move for this killbot will be implementing some form of complex movement, so try and confuse other bots targeting. Alternitevly, I was thinking about looking at pathfinding systems to get a headstart on the tournament happening week 6, which will be in a maze environment;

Leave a comment