How to add a missile in game?

Hi people;

Honestly I have been working on this program for months and have gotten next to no where. So far I have an intro screen, game screen and game over screen no problem. Also moving a couple of sprites about and selected desired sprite not a problem but I have looked all over internet and through many text books but just can't seem to find some good example code to help me integrate firing missiles from my game sprites. My code is really messy I know but I'm learning. Can anyone help me out please? The bullets are to be fired from each side along the x-axis by the opposing sides (each sprite). There will be five units either side. If any more information is needed please just ask; I'm really in a spot of bother here.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//main.cpp

#include <windows.h>		
#include <windowsx.h>		// include useful macros
#include <stdlib.h>			
#include <stdio.h> 
#include <math.h>
#include <mmsystem.h>

#include "resource.h"
#include "game_state.h"
#include "soldiers.h"
#include "bullets.h"
#include "score.h"

//Globals//////////////////////////////////
HBITMAP		theOldFrontBitMap, theOldBackBitMap;
HDC			backHDC, frontHDC, bitmapHDC, maskHDC;	//Hardware device contexts for the Buffers
HINSTANCE   hInstance;
HWND		ghwnd;
RECT		screenRect;

bool	keys[256];  

//Game variable globals/////////////////
int ticker =0;

//Macros//////////////////////////////////
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

//types/////////////////////////////////////
typedef struct Mouse
{
	int x, y;
}Mouse;
Mouse MousePos;

typedef struct Background
{
	int x, y;		// top left of sprite
	HBITMAP bitmap;
} Background;
Background TestBackground;

typedef struct Title
{
	HBITMAP bitmap;
} Title;
Title TestTitle;

typedef struct BritishMachineGun
{
	bool alive;   // is alive TRUE/FALSE
	int x, y;		// top left of sprite
	int xFront, yCentre; // front centre of sprite
	HBITMAP bitmap;
} BritishMachineGun;
BritishMachineGun TestBritishMachineGun;

typedef struct BritishMachineGun2
{
	int x, y;		// top left of sprite
	HBITMAP bitmap;
} BritishMachineGun2;
BritishMachineGun2 TestBritishMachineGun2;

typedef struct
{
   bool alive;      // is alive TRUE/FALSE
   int xPos;   // x position of bullet
   int yPos;   // y position of bullet
   int xmove;     // x movement direction (x vector)
   int duration;    // duration of bullet  
} BULLET_STRUCT;
BULLET_STRUCT Bullets[MAX_BULLETS];

typedef struct Poppies
{
	int x, y;
	HBITMAP bitmap;
} Poppies;
Poppies TestPoppies;

//Win Proc////////////////////////////////
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

//Function prototypes//////////////////////////
BOOL waitFor(unsigned long delay);

Last edited on
There is obviously more to the code but I'm not sure what to post in order to get anyone's help. Little bit sceptical anyone can at such short notice and also people have been quite harsh in the past on other sites.
Make a struct to represent the bullets.

When they're created, give them an initial position and a speed.

Every update, add their speed to their position to move them.

Check their position related to enemy/object positions to see if they "hit" anything

etc
etc

You should be able to figure it out if you've done basic animated movement. Nothing really complicated here.

If you want more help you'll need to be more specific about what you need and/or what problems you're having.
closed account (D80DSL3A)
I'd be happy to share my shot and rocket classes with you. Are you familiar with using classes?
Sorry you have met with harsh responses before (and hope I don't find out why).

I have a basic space shooter game working well.
I use an array of shots for the ships to use when it is time for them to fire.
The tasks of firing a shot, animating its motion, hit testing and responding to a hit are split between the shot and ship classes, so I'd have to go over the relevant parts of each class.
Disch covered the basics in a general way, but the devil, of course, is in the details...

Here are some of the data members from my base shot class, just to show what's involved:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
imageSet* pimgSet;// related to drawing. I organize my animation frames in an "image set" object
bool inAir;// shot is animated and hit tested against if true, available for firing if false

int hitval;// amount of damage done to target by shot
int setNum;// which shot image to use (mine are animated so that's a frame set)
int frIndex;// for cycling through animation frames
char target;// 'e' if target is enemy ship, 'g' if good guy is target. This prevents fratricide.

float szx;// width of shot (not a point )
float szy;// height of shot (usually same so shot is a square shape)
float posx;// position of shot for the frame being rendered
float posy;// 2D motion

float velx;// speed of shot in pixels per frame (so posx += velx each frame = nice and simple)
float vely;// speed in y-direction 


Here are 2 of the shot class functions. These are from the simplest class (for constant velocity shots - no accelerated motion, no "homing" on target - I have these types of shot classes though too)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// moves shot each frame
void cvShot::repos( RECT* pGR )// GR = "game rectangle"
{
	if( inAir)// shot is animated only if inAir is true
	{
		posx += velx;// quite simple really!
		posy += vely;				
	
                // if shot leaves the screen bounds ("Game Rectangle") then stop animating it (assign inAir = false)
		if( (posx > (float)pGR->right) || (posx < (float)pGR->left) || (posy > float)pGR->bottom) || (posy < (float)pGR->top)  )
		inAir = FALSE;// 2nd way is if shot hits a ship. ship::check4Hit()
	}		

	return;
}


Ships do the hit testing. When a ship finds it has been hit it calls shot::onHit(). Very simple for cvShots:
1
2
3
4
5
void cvShot::onHit( void )
{
	inAir = FALSE;
	return;
}

The onHit() is more involved for other shot classes though. For the rocket class a detonation must be triggered here.

Here is the hittest function from a ship class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool ship::check4Hit( shot** ppShot, int dumpSz )// ship checks through array of shots in use
	{	
		int j = 0;// for looping		

		if( hitsLeft > 0 )// to prevent hits during kill ani (which starts it over)
			for( j=0; j<dumpSz; j++)
				if( ppShot[j]->inAir  && ( ppShot[j]->target == 'e' ) )// enemy ship hittest		
					if(  ppShot[j]->overme( posx, posy, szx, szy )  )// shot actually does the position comparison. I didn't include that function above
					{
						ppShot[j]->onHit();// shots response to hit
						onHit( ppShot[j]->hitval );// ships response to hit ( health reduced, switch to "hit" animation frame set, etc. )
					}			

		return(hit);// hit is a data member of the ship classes
	}// end of check4Hit() 


The above methods can be simplified if simple constant motion, non-detonating shots are all you are after. Let me know if you wish to know more.
closed account (3pj6b7Xj)
Please tell me those aren't globals.
closed account (D80DSL3A)
They aren't globals.
Ok I've used classes before but I'm going to go with the stuct idea I think for now; probably tackle the class method next.

I've made a bullet struct but I'm trying to initialise a start point for each bullet from each sprite; probably the long winded way.

1
2
3
4
5
6
7
8
9
typedef struct
{
   bool alive;      // is alive TRUE/FALSE
   int xPos;   // x position of bullet
   int yPos;   // y position of bullet
   int xmove;     // x movement direction (x vector)
   int duration;    // duration of bullet  
} BULLET_STRUCT;
BULLET_STRUCT Bullets[MAX_BULLETS];


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void InsertBullet()
{
   int i;  // for count loop
   
   if (bullet_countdown > 0)
   {
      bullet_countdown--;
      return;
   }

   for (i = 0; i < MAX_BULLETS; i++)
   {
      if (!Bullets[i].alive)  // if bullet is dead (free), insert one here
      {
         
         Bullets[i].alive = TRUE;
         
		 Bullets[i].xPos = BritishMachineGun.xFront;
		 Bullets[i].yPos = BritishMachineGun.yCentre;
         
         Bullets[i].xmove = bmg_xPos++ * BULLET_SPEED;
         Bullets[i].duration = DURATION_FOR_MACHINE_GUN_BULLET;
         
         bullet_countdown = TIME_BETWEEN_BULLETS;
         
         return;
         
      } // end of if

   } // end of for

} // END OF InsertBullet 


I'm getting 2 warning C4832 and 2 error C2275.

Can anyone help me with this function before I make a FireBullet function please?

I'm getting 2 warning C4832 and 2 error C2275


I don't know what those errors are. Can you post the full errors and tell us what lines they're on?
Sure,

1>------ Build started: Project: take5, Configuration: Debug Win32 ------
1>Compiling...
1>main.cpp
1>c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(309) : warning C4832: token '.' is illegal after UDT 'BritishMachineGun'
1> c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(53) : see declaration of 'BritishMachineGun'
1>c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(309) : error C2275: 'BritishMachineGun' : illegal use of this type as an expression
1> c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(53) : see declaration of 'BritishMachineGun'
1>c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(310) : warning C4832: token '.' is illegal after UDT 'BritishMachineGun'
1> c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(53) : see declaration of 'BritishMachineGun'
1>c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(310) : error C2275: 'BritishMachineGun' : illegal use of this type as an expression
1> c:\users\graeme\documents\visual studio 2008\projects\take5\take5\main.cpp(53) : see declaration of 'BritishMachineGun'
1>Build log was saved at "file://c:\Users\Documents\Visual Studio 2008\Projects\take5\take5\Debug\BuildLog.htm"
1>take5 - 2 error(s), 2 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

it appears to be a problem with:

1
2
Bullets[i].xPos = BritishMachineGun.xFront;
Bullets[i].yPos = BritishMachineGun.yCentre;


I have been on MSDN but I can't seem to make sense of this, if I remove this function from the code the program is fine again so it there is definitely something wrong with the bullet struct or InsertBullet function I would guess. Any light on the subject?


Last edited on
BritishMachineGun is a struct name, not a variable. You probably meant 'TestBritishMachineGun.xFront'



Also, you're doing the weird C style struct definitions so I thought you were using C (which is why I recommended structs), but if you're doing C++ you don't have to do it that way:

1
2
3
4
5
6
7
// the weird C way
typedef struct
{ } structname;

// the nearly-equivilent C++ way:
struct structname
{ };
Last edited on
Almost got this I think now the program is running again but when I press fire the bullets fire along the top of the screen and the BritishMachineGun sprite moves along to the right. The idea is have the sprite stay still in this case with the bullets coming from the front, centre of it. This sprite should only move up and down with cursor keys. Here's the two functions:-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void InsertBullet()
{
   int i;  // for count loop
   
   if (bullet_countdown > 0)
   {
      bullet_countdown--;
      return;
   }

   for (i = 0; i < MAX_BULLETS; i++)
   {
      if (!Bullets[i].alive)  // if bullet is dead (free), insert one here
      {
         
         Bullets[i].alive = TRUE;
         
		 Bullets[i].xPos = TestBritishMachineGun.xFront;
		 Bullets[i].yPos = TestBritishMachineGun.yCentre;
         
         Bullets[i].xmove = bmg_xPos++ * BULLET_SPEED;
         Bullets[i].duration = DURATION_FOR_MACHINE_GUN_BULLET;
         
         bullet_countdown = TIME_BETWEEN_BULLETS;
         
         return;
         
      } // end of if

   } // end of for

} // END OF InsertBullet 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void FireBullet()
{

   int i, xi, yi;
   int x, y;
   
   for (i = 0; i < MAX_BULLETS; i++)
   {
      if (Bullets[i].alive)
      {
         x = Bullets[i].xPos; y = Bullets[i].yPos; // bullet x y
         x += Bullets[i].xmove;					   // move bullet
         
         Bullets[i].xPos = x; Bullets[i].yPos = y;
         xi = (int)x; yi = (int)y;
         
         SelectObject(backHDC, white_pen);
         SelectObject(backHDC, white_brush);
         Ellipse(backHDC, xi - 1, yi - 1, xi + 1, yi + 1);
         
         Bullets[i].duration--;
         if (Bullets[i].duration == 0) Bullets[i].alive = FALSE;
         
      } // end of if
      
   } // end of for
   
} // END OF FireBullet 


One other thing should both these functions be called here?

1
2
3
4
5
6
7
8
9
10
11
12
switch(soldier_select)
	{
		case BRITISH_MACHINE_GUN:
			{	
if (KEY_DOWN(VK_SPACE))
			{
				InsertBullet();
				FireBullet();
				break;
			}
                        }
       }



Hi again; have been experimenting with the code and now manage to fire a projectile from the designated point. However more problems; now when I fire the projectile moves very slowly and I can't seem to speed it up plus when I let go of the space bar the projectile disappears and reappears when I hold the space bar again. Also can't think of a way to move the point of fire with the sprite; thinking it must be simple enough but have been staring at this for a while and wondered if anyone could give me some advice?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
void InsertBullet()
{
   int i;  // for count loop
   
   if (bullet_countdown > 0)
   {
      bullet_countdown--;
      return;
   }

   for (i = 0; i < MAX_BULLETS; i++)
   {
      if (!Bullets[i].alive)  // if bullet is dead (free), insert one here
      {
         
         Bullets[i].alive = TRUE;
         
		 Bullets[i].xPos = TestBritishMachineGun.xFront+100;
		 Bullets[i].yPos = TestBritishMachineGun.yCentre+50;
         
         Bullets[i].xmove = TestBritishMachineGun.xFront++ && TestBritishMachineGun.yCentre * BULLET_SPEED;
         Bullets[i].duration = DURATION_FOR_MACHINE_GUN_BULLET;
         
         bullet_countdown = TIME_BETWEEN_BULLETS;
         
         return;
         
      } // end of if

   } // end of for
  
} // END OF InsertBullet

void FireBullet()
{
 
   int i, xi, yi;
   int x, y;
   
   for (i = 0; i < MAX_BULLETS; i++)
   {
      if (Bullets[i].alive)
      {
         x = Bullets[i].xPos; y = Bullets[i].yPos; // bullet x y
         x += Bullets[i].xmove;					   // move bullet
         
         Bullets[i].xPos = x; Bullets[i].yPos = y;
         xi = (int)x; yi = (int)y;
         
         SelectObject(backHDC, white_pen);
         SelectObject(backHDC, white_brush);
         Ellipse(backHDC, xi - 5, yi - 5, xi + 5, yi + 5);
         
         Bullets[i].duration--;
         if (Bullets[i].duration == 0) Bullets[i].alive = FALSE;
         
      } // end of if
      
   } // end of for
   
} // END OF FireBullet 

Last edited on
Topic archived. No new replies allowed.