Sign in to follow this  
v0rtexza

Limiting Bullets and stopping spamming - DirectX

Recommended Posts

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

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
In addition to Madhed's suggestion, your access violation is a buffer overrun:

[code]
if (CurrentBullet >= MAX_BULLETS) CurrentBullet = 0;
CurrentBullet++;
[/code]

Recall that an array of N elements is named from 0 to N-1. If [tt]CurrentBullet == MAX_BULLETS-1[/tt], then the tested condition is false in the first line of this snippet. After executing the next line, [tt]CurrentBullet == MAX_BULLETS[/tt], which is an invalid index in the array [tt]bullets[/tt].

Share this post


Link to post
Share on other sites
(Can't edit my post?!)

Any attempt to write to past the end of [tt]bullets[/tt] 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[/tt], which is a dynamically resizing array with additional safety checks in your debug build.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
You'll need to move from this sort of logic:
[code]
if ( isKeyPressed( KEY_SPACE ) ) {
// ...
}
[/code]

To this (quickfix):
[code]
// Assume: bool keySpaceIsHeld = false;
if ( isKeyPressed( KEY_SPACE ) ) {
if ( !keySpaceIsHeld ) {
keySpaceIsHeld = true;
// ...
}
} else
keySpaceIsHeld = false;
[/code]

However, this approach is tedious and the OS already provides this functionality. Since you're using win32, you can handle the [url=http://msdn.microsoft.com/en-us/library/windows/desktop/ms646280%28v=vs.85%29.aspx][tt]WM_KEYDOWN[/tt][/url] message in your event loop and signal the object responsible for firing the bullet:

[code]
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 ); //
}
[/code]

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this