NOGDUS

Articles, Tutorials, and other things. => Allegro Game Programming => Topic started by: Richard Marks on March 30, 2010, 02:40:10 PM



Title: ASK Tutorial 05 - Enemy Attack
Post by: Richard Marks on March 30, 2010, 02:40:10 PM
ASK Tutorial 05 - Enemy Attack

Guess what? Time for yet another Allegro Starter Kit tutorial! 8)

The concept: Let the enemy attack the player when moving down and before passing the Y center line.

It is assumed that you are using Visual C++ 2008 Express (MSVC9)
If you're not using MSVC9, then you will need to adjust some steps to suit your IDE.

This tutorial builds off the previous tutorial's code (http://ccpssolutions.com/nogdusforums/index.php?topic=679.0), so don't forget to add the code from the previous tutorial.


Step #1 - Create a new Empty Win32 Project (not a Console Application) in your IDE.

File -> New Project
Choose Win32 Project
Enter "ASKEnemyAttackDemo" for the Name
Click OK
Click Application Settings
Check the Empty Project check-box
Click Finish

Step #2 - Save the Empty Project

File -> Save All

Step #3 - Copy the code files from Tutorial 04 into your project's folder.

Copy all the *.cpp and *.h files from the Tutorial 04 (http://ccpssolutions.com/nogdusforums/index.php?topic=679.0) project into the folder that holds the ASKEnemyAttackDemo.vcproj file.

Step #4 - Add the files to the Project

Project -> Add Existing Item
Choose all the .h and .cpp files you just copied and click Add.

Step #5 - Add the code to the PrimaryWindow files to implement the demo concept.

We are adding a new object to our game, so we will add some new variables and some new functions.
The object we are adding, I'm calling ballShot so all variables and functions will use this name.

Our object is almost the same as the playerShot object, however we need to use both X and Y velocities, and I'm adding 2 colors and 2 different sizes to give some complexity - well really just to show another cool method. 8)

OK, so in PrimaryWindow.h add the variables. You should know where to put them by now. I'm not going to keep repeating telling you where to put things that are obvious.
Code:
bool ballShotAlive_;
bool ballShotShow_;
float ballShotSpeed_;
float ballShotX_;
float ballShotY_;
float ballShotDX_;
float ballShotDY_;
int ballShotRadius_;
int ballShotRadius2_;
int ballShotColor_;
int ballShotColor2_;

And the new function declarations:
Code:
void UpdateBallShot();
void RenderBallShot();
bool LoadContentForBallShot();

This is the last time that I will tell you what functions to add for adding a new object to the game.
From here on, I assume that you can think of how to name the function, and that you will add it properly.

You should also know how and where to call the functions in the PrimaryWindow.cpp file now.
Add the function stubs to the PrimaryWindow.cpp file, and lets talk about what they will do.

I thought about how I wanted the ball to attack the player, and decided on the following design:

The ball will be considered in Attack mode when it is moving downwards. While the ball has not yet crossed the Y center line (the screen height divided by 2), there is a random chance that the ball will fire a shot at the player.

The shot will move in a direct line at the player's position at the time of firing.
Which means, if the player is at position 30, 250 (it cannot be this in game, but for this numeric example) and the ball is at position 150, 30 then the ballShot object will move in a direct line from the ball's position to the player's position.

The ballShot will alternate between two colors and two sizes by toggling a boolean variable every update frame.

OK, so we've got that covered.
Let's fill in those function stubs now.

The LoadContentForBallShot() is as follows:
Code:
// the shot is dead by default
ballShotAlive_ = false;

// the ball's shots will alternate between 2 sizes
ballShotRadius_ = 4;
ballShotRadius2_ = 5;

// the ball fires a red to yellow shot
ballShotColor_ = makecol(255, 0, 0);
ballShotColor2_ = makecol(255, 255, 0);

// position the shot at the center of the ball
ballShotX_ = ballX_;
ballShotY_ = ballY_;

// ball shots move at 15 pixels per frame
ballShotSpeed_ = 15.0f;

// the shot has 2 displays, and we use a
// boolean to decide which display to render
ballShotShow_ = true;

// shots trajectory will be calculated when firing
ballShotDX_ = 0.0f;
ballShotDY_ = 0.0f;

Now we get to UpdateBallShot()
Code:
// if the shot is not alive, move it's position to the ball
if (!ballShotAlive_)
{
ballShotX_ = ballX_;
ballShotY_ = ballY_;
return;
}

// toggle the display
ballShotShow_ = !ballShotShow_;

// apply velocity
ballShotX_ += ballShotDX_;
ballShotY_ += ballShotDY_;

// if the shot goes off screen
if (ballShotX_ < 0 || ballShotY_ > SCREEN_H || ballShotX_ > SCREEN_W)
{
// kill the shot
ballShotAlive_ = false;

// reset the position to the ball
ballShotX_ = ballX_;
ballShotY_ = ballY_;

// exit the function
return;
}

Pretty straightforward, and shouldn't need any explanation at this point.

Lets see the RenderBallShot() function code now.
Code:
// exit the function if the shot is dead
if (!ballShotAlive_)
{
return;
}

// draw the shot
if (!ballShotShow_)
{
circlefill(_backBuffer,
(int)ballShotX_, (int)ballShotY_,
ballShotRadius_, ballShotColor_);
}
else
{
circlefill(_backBuffer,
(int)ballShotX_, (int)ballShotY_,
ballShotRadius2_, ballShotColor_);
}

Nothing new, except we are using the ballShotShow boolean to display one of the two versions of the shot.

Now, lets see how to make the ball attack the player.
The code will go into the UpdateBall() function of course.

We are going to move the bottom boundary for the ball to 18 pixels above the bottom of the screen, to prepare for a later tutorial's addition to the game. (The bottom 18 pixels are going to hold the game information displays, like the score, etc.)

Modify the ball's boundary test code to account for the new bottom boundary as follows:
Code:
if (ballY_ < ballRadius_ || ballY_ > ((SCREEN_H - 18) - ballRadius_))

Now, after the boundary tests, we will add the attacking code.
We do not want to continue into the attacking code unless certain conditions are met, so we will perform a series of tests to ensure that the attack code does not get executed unless we want it to.

The first condition to test is "am I out of ammo?".
Since the ball can only fire a single shot at a time, this is a single boolean condition test.
Code:
// can fire only if the ball shot is dead
if (ballShotAlive_)
{
// exit the function
return;
}

Next condition is "are we going to attack the player?" - This is a random chance condition.
You can tweak the value of 8 in the condition to give the enemy a greater chance of attacking or not.
Code:
// randomly attack the player
if ((rand() % 8) != 0)
{
// exit the function
return;
}

Next condition is that the ball must be traveling downwards to attack.
When the ball's Y velocity is greater than zero, it is moving downwards.
Code:
// if the ball is not traveling downwards,
if (ballDY_ <= 0.0f)
{
// exit the function
return;
}

The next condition is that the ball must be above the middle of the screen to attack.
Code:
// if the ball has passed the Y centerline
if (ballY_ > SCREEN_H / 2)
{
// exit the function
return;
}

Now that all the conditions are met, we can attack the player.
How do we attack the player? Using some basic 2D Vector math.
Don't ask me to explain how this works. I honestly don't understand it as much as I just know how to do it, and what it is used for. I'm not a mathematician. ::)

Code:
// calculate the trajectory to the player
float dx = playerX_ - ballX_;
float dy = playerY_ - ballY_;

float length = sqrt((dx * dx) + (dy * dy));

dx /= length;
dy /= length;

ballShotDX_ = dx * ballShotSpeed_;
ballShotDY_ = dy * ballShotSpeed_;

Finally, we set the ballShot object to be alive, which lets it "fire"
Code:
ballShotAlive_ = true;

OK, that is all for this tutorial.

When you compile and run the project, you should get:
1 - A window with a black background
2 - The bouncing blue ball from the first tutorial
3 - The green triangle from the second tutorial that you can move left and right using the arrow keys.
4 - A single reloading cyan bullet that you can fire using the space bar.
5 - The ball should disappear if the bullet collides with it.
6 - The ball should re-appear (re-spawn) after roughly 1 second has passed after it dies.
7 - The ball should attack the player when it is moving downwards, and above the Y center line.

I've got more planned, but I'm out of time. Thanks for reading! See you in the next tutorial!
Let me know if you were able to follow this tutorial without any trouble.



(Updated April 2, 2010 - Changed usage of underscores in regards to Redslash's notice.)