Limiting Bullets and stopping spamming - DirectX

Started by
7 comments, last by v0rtexza 11 years, 9 months ago
Hey all, I am making a simple sidescroller space shooter and have encountered a problem. I do not know how to limit the amount of bullets adequately or control the difference between input times.

Here is the relevant code that I know is the problem.

I create space in memory for my bullet sprites and I set their default properties (according to my own class):

[source lang="cpp"]//bullet sprites
const int MAX_BULLETS = 20;
SPRITE bullets [MAX_BULLETS];

//set default properties
for (int j = 0; j < MAX_BULLETS;j++)
{
bullets[j].alive = false;
bullets[j].startframe = 0;
bullets[j].endframe = 1;
bullets[j].delay = 10;
bullets[j].x = 0;
bullets[j].y = 0;
bullets[j].height = 55;
bullets[j].width = 16;
bullets[j].columns = 1;
bullets[j].vely = 6.0f;
}
imgBullet = LoadTexture("purplefire.tga");
if (!imgBullet) return false;
player_shoot_timer = 0;[/source]

I then go onto set bullets to alive when I click space bar like so:

[source lang="cpp"]if (Key_Down(DIK_SPACE)) {
//limit firing rate
if ((int)timeGetTime() < player_shoot_timer + 100) return;
player_shoot_timer = timeGetTime();

if (CurrentBullet >= MAX_BULLETS) CurrentBullet = 0;
CurrentBullet++;
bullets[CurrentBullet].alive = true;
bullets[CurrentBullet].x = player.x + (player.width/2);
bullets[CurrentBullet].y = player.y;
}[/source]
But the above code is not adequately stopping me from shooting if I hold down for example space bar, any ideas on that?

Finally in my actual game loop, I render the bullets that are deemed "alive" or have been shot already:

[source lang="cpp"]for (int k = 0;k < MAX_BULLETS;k++)
{

if (bullets[k].isAlive() == true)
{

bullets[k].y -= bullets[k].vely;
// Sprite_Animate(bullets[k].frame,bullets[k].startframe,bullets[k].endframe,1,bullets[k].starttime,bullets[k].delay);
Sprite_Draw_Frame(imgBullet,bullets[k].x,bullets[k].y,bullets[k].frame,bullets[k].width,bullets[k].height,bullets[k].columns);

}
}[/source]

However the problem is that I can hold down spacebar and it will just keep rendering the bullets to that spot and once I finish the program/close it, I get the following error:

Unhandled exception at 0x61a659da (msvcr100d.dll) in Tile_Dynamic_Scroll.exe: 0xC0000005: Access violation reading location 0x4424aac2.

I am guessing this is because I am not resetting the bullets adequately but I can't figure out:

a) how to create a time between each fired bullet so that the user cannot spam spacebar, my current implementation does not work
b) Limit the amount of bullets fired and reset them accordingly.

(if any more code is needed, I will supply upon request as the entire project is largeish)

I do not want the complete answer but merely a nudge in the right direction, any help is appreciated.

Thanks, v0rtex
Advertisement
In the second code snippet you are always creating a bullet every 100ms even if MAX_BULLETS are already alive, that means the bullet are constantly being reset to the player's position.
As for the exception: Have you tried running the program in debug mode and pause when the exception happens?
In addition to Madhed's suggestion, your access violation is a buffer overrun:


if (CurrentBullet >= MAX_BULLETS) CurrentBullet = 0;
CurrentBullet++;


Recall that an array of N elements is named from 0 to N-1. If CurrentBullet == MAX_BULLETS-1, then the tested condition is false in the first line of this snippet. After executing the next line, CurrentBullet == MAX_BULLETS, which is an invalid index in the array bullets.
(Can't edit my post?!)

Any attempt to write to past the end of bullets will either cause your program to crash (best case), an unrelated bug to appear elsewhere (unfavorable), or behave exactly as expected (worst case).

Addendum to Madhed's suggestion:
You may want to consider searching for a dead bullet to create your new bullet as you may overwrite an existing living bullet.

Another consideration:
You might want to consider using [url=http://www.cplusplus.com/reference/stl/vector/]std::vector, which is a dynamically resizing array with additional safety checks in your debug build.
Wow lol, was focusing so much on the graphics and DirectX that I forgot something as simple as that. Thanks! My only last problem is that I do not know how to space input, so that for example when you click space. Only 1 shot is registered, at the moment whenever space is held down, my variable CurrentBullet (as seen in the listing above) continually increases as much as I click instead of only registering one click. Any ideas?
You'll need to move from this sort of logic:

if ( isKeyPressed( KEY_SPACE ) ) {
// ...
}


To this (quickfix):

// Assume: bool keySpaceIsHeld = false;
if ( isKeyPressed( KEY_SPACE ) ) {
if ( !keySpaceIsHeld ) {
keySpaceIsHeld = true;
// ...
}
} else
keySpaceIsHeld = false;


However, this approach is tedious and the OS already provides this functionality. Since you're using win32, you can handle the WM_KEYDOWN message in your event loop and signal the object responsible for firing the bullet:


LRESULT CALLBACK wndproc( HWND h, INT msg, WPARAM wParam, LPARAM lParam ) { // (Guessing this declaration here)
switch ( msg ) {
case WM_KEYDOWN: {
switch ( wParam ) {
case VK_SPACE:
player->fireBullet();
break;
// etc...
}
} break;

// etc...
}

return DefWndProc( h, msg, wParam, lParam ); //
}
Thanks fastcall22, I tried your first solution:

[source lang="cpp"] if (Key_Down(DIK_SPACE))
{
//limit firing rate
// if (GetTickCount() - player_shoot_timer > 100) return;
//player_shoot_timer = GetTickCount();
if (!keySpaceIsHeld)
keySpaceIsHeld = true;
if (keySpaceIsHeld)
{
if (CurrentBullet == MAX_BULLETS -1) return; //CurrentBullet = Max Ammo, So Exit
if (CurrentBullet < MAX_BULLETS) //If there are bullets available
{
bullets[CurrentBullet].alive = true;
bullets[CurrentBullet].x = player.x + (player.width/2);
bullets[CurrentBullet].y = player.y;
}
}

}
[/source]

But It still does what it did and increases CurrentBullet a lot instead of by 1 upon each keypress. Editing my windows code to work with my main code sounds like a massive hassle as I would have to rewrite ALOT of my code... Sorry to bother man, you've been a lot of help!
Sorry as an addendum to my last post (as I can't edit!?)
After the second last bracket, I had:
[source lang="cpp"]}
}
else
keySpaceIsHeld = false;
}[/source]
Nevermind, got it working with the following:

I set a long variable to 0 that would hold the last time the player shot and then I did the following

[source lang="cpp"] if ((int)timeGetTime() < lastShot + 100) return;
else
{
//shoot bullet
}[/source]
Thanks everyone, for all your help!

This topic is closed to new replies.

Advertisement