I am making a game similar to missile defence so that I can become used to Allegro and whatnot.
I wrote something up that generates a background and saves it to a bitmap, everything was going good until I added a class in a separate .cpp file.
1 | /******************** |
2 | * Tank Class Header* |
3 | ********************/ |
4 | |
5 | #ifndef _TANK_H |
6 | #define _TANK_H |
7 | |
8 | #define MAX_BULLETS 10 |
9 | #define MOVE_LEFT 0 |
10 | #define MOVE_RIGHT 1 |
11 | |
12 | #define TANK_W 100 |
13 | #define TANK_H 35 |
14 | |
15 | #define CANNON_W 25 |
16 | #define CANNON_H 50 |
17 | |
18 | class CTank |
19 | { |
20 | public: |
21 | CTank(); |
22 | ~CTank(); |
23 | |
24 | int x, y; // x and y coordinate of the player |
25 | int health; // health of the player |
26 | int reload; // reload time of the player |
27 | |
28 | int score; |
29 | |
30 | BITMAP *tank, *cannon; //bitmaps to hold the tank and cannon |
31 | |
32 | void MoveTank(int dir); |
33 | void FireBullet(); |
34 | }; |
35 | |
36 | #endif |
1 | /******************** |
2 | * Tank Source File * |
3 | ********************/ |
4 | |
5 | #include <allegro.h> |
6 | #include "tank.h" |
7 | |
8 | CTank::CTank() |
9 | /* Sets up tank object */ |
10 | { |
11 | x = (SCREEN_W/2); // init player |
12 | y = (SCREEN_H/4); |
13 | health = 100; |
14 | reload = 0; |
15 | score = 0; |
16 | tank = create_bitmap(TANK_W, TANK_H); |
17 | cannon = create_bitmap(CANNON_W, CANNON_H); |
18 | |
19 | rectfill(tank, 10, 0, (TANK_W-10), TANK_H, makecol(45, 200, 60)); |
20 | rect(tank, 10, 0, (TANK_W-10), TANK_H, makecol(60, 230, 70)); |
21 | } |
22 | //-------------------------------------------- |
23 | |
24 | CTank::~CTank() |
25 | /* Deletes tank bmps */ |
26 | { |
27 | destroy_bitmap(tank); |
28 | destroy_bitmap(cannon); |
29 | } |
30 | //-------------------------------------------- |
31 | |
32 | void CTank::MoveTank(int dir) |
33 | /* Moves tank */ |
34 | { |
35 | if((dir == MOVE_LEFT) && (x < 0)) |
36 | x -= 1; |
37 | else if((dir == MOVE_RIGHT) && ((x+TANK_W) > (SCREEN_W)) |
38 | x += 1; |
39 | |
40 | return; |
41 | } |
42 | //-------------------------------------------- |
43 | |
44 | void CTank::FireBullet() |
45 | {} |
46 | //-------------------------------------------- |
That's the tank class header and .cpp file. The program compiles fine, but this error is given when it runs:
The instruction at "0x10020efc" referenced memory at "0x00000038". The memory could not be "read".
Click on OK to terminate the program
Click on CANCEL to debug the problem.
Help, please?
How do you use the class? Make sure you don't create it until you have initiated allegro. Post some more code.
Here is the only other code I have written so far, the main.cpp file:
1 | /****************************** |
2 | * Tank Defense v.0.1 * |
3 | * March 25 2007 * |
4 | * Kelly Crawford * |
5 | ******************************/ |
6 | |
7 | #include <allegro.h> |
8 | #include <time.h> |
9 | #include "tank.h" |
10 | |
11 | #define WINDOW_W 640 |
12 | #define WINDOW_H 480 |
13 | |
14 | #define MAX_CLOUDS 14 |
15 | #define MIN_CLOUDS 7 |
16 | |
17 | int SetUp() |
18 | /* Initializes allegro and screen */ |
19 | { |
20 | allegro_init(); |
21 | |
22 | install_keyboard(); |
23 | install_mouse(); |
24 | |
25 | set_color_depth(16); |
26 | |
27 | if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, WINDOW_W, WINDOW_H, 0, 0) != 0) |
28 | return 1; |
29 | |
30 | srand(time(0)); |
31 | |
32 | return 0; |
33 | } |
34 | //-------------------------------------------- |
35 | |
36 | void cloud_line(BITMAP *bmp, int x, int y, int color) |
37 | /* Function called by DoLine() */ |
38 | { |
39 | putpixel(bmp, x, y, color); |
40 | |
41 | return; |
42 | } |
43 | //-------------------------------------------- |
44 | |
45 | void MakeCloud(BITMAP *bmp) |
46 | /* Draws a cloud to bmp */ |
47 | { |
48 | int height = 1 + (rand()%50); // height of cloud |
49 | int width = 100 + (rand()%50); // general width of cloud |
50 | |
51 | int x1 = (-30) + rand()%(SCREEN_W-30); |
52 | int x2 = x1 + width; |
53 | int y = 10 + rand()%(SCREEN_H-100); // cloud coordinates |
54 | |
55 | int col = makecol(255,255,255); // cloud color information |
56 | |
57 | for(int i = 0; i < height; i++) // loops until entire cloud is drawn |
58 | { |
59 | do_line(bmp, x1, y, x2, y, col, *cloud_line); // draw line of cloud |
60 | y += 1; |
61 | |
62 | if(i < (height/2)){ |
63 | x1 -= 3 + rand()%5; |
64 | x2 += 3 + rand()%5;} |
65 | else{ |
66 | x1 += 3 + rand()%5; |
67 | x2 -= 3 + rand()%5;} |
68 | } |
69 | |
70 | return; |
71 | } |
72 | //-------------------------------------------- |
73 | |
74 | BITMAP* GenerateSky(BITMAP *bmp) |
75 | /* Generates a sky on bitmap pointed |
76 | to by bmp */ |
77 | { |
78 | int r = 140, g = 150, b = 225; |
79 | int col = makecol(r, g, b); |
80 | |
81 | |
82 | floodfill(bmp, SCREEN_W/2, SCREEN_H/2, col); // fill screen w/ blue |
83 | |
84 | int clouds = (rand()%(MAX_CLOUDS-MIN_CLOUDS) + MIN_CLOUDS); |
85 | |
86 | for(int c = 0; c < clouds; c++) |
87 | MakeCloud(bmp); |
88 | |
89 | return bmp; |
90 | } |
91 | //-------------------------------------------- |
92 | |
93 | int main() |
94 | { |
95 | CTank player; |
96 | |
97 | if(SetUp() != 0) return 1; // setup + error checking for allegro |
98 | |
99 | BITMAP *bg_sky = create_bitmap(SCREEN_W, SCREEN_H); // create sky bitmap |
100 | BITMAP *buffer = create_bitmap(SCREEN_W, SCREEN_H); // create double buffer |
101 | |
102 | bg_sky = GenerateSky(bg_sky); // colour sky bitmap |
103 | |
104 | while(!key[KEY_ESC]){ |
105 | |
106 | blit(bg_sky, buffer, 0, 0, 0, 0, bg_sky->w, bg_sky->h); |
107 | |
108 | blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); |
109 | }; |
110 | |
111 | destroy_bitmap(bg_sky); |
112 | destroy_bitmap(buffer); |
113 | |
114 | return(0); |
115 | }END_OF_MAIN(); |
EDIT: The CTank class is used in the main() function only.
There is no semi-colon after END_OF_MAIN()
I removed the semi-colon, the problem persists.
Jonatan nailed it. The class's constructor (and thus create_bitmap() etc) is called before Allegro is initialized.
CTank is declared before Allegro is initialized. The constructor of CTank uses allegro definitions.
edit:
Darn I was ...
http://www.mmmchicago.com/Transparent%20Red%20Beet%20by%20dick.gif
Ah! It all makes sense now. Everything is working now, thanks everyone~
NEVERMIND! (Runs away crying...) {smiley}
/********************
* Tank Class Header*
********************/
#ifndef _TANK_H
#define _TANK_H
An underscore followed by an uppercase letter is undefined behavior. Adopt a new naming scheme.
An underscore followed by an uppercase letter is undefined behavior.
Actually, symbols and macros starting with an underscore are reserved for compiler/system use.
But the resulting behavior is undefined
Its perfectly defined. Expect problems when the symbol you chose happens to be used in the compiler or system headers sometime in the future.
edit:
I used to use _FILENAMEHERE_H_
I now use FileNameHere_H_GUARD
An underscore followed by an uppercase letter is undefined behavior.
No, it's definitely not. An identifier in C can start with any letter (upper- or lowercase), or an underscore, and after that, it can contain letters, underscores, and numeric digits.
Actually, symbols and macros starting with an underscore are reserved for compiler/system use.
Double underscores. Single underscores should be fine.
But the resulting behavior is undefined
Not at all.
If you happen to use a compiler-defined identifier for your own #defines, you will either prevent certain code from being read by the compiler, as in this example:
#ifndef __FILE__ #define __FILE__ // anything here will be ignored, because __FILE__ is always defined #endif
...or it will produce compiler errors due to incompatible definitions for the identifier.
Neither of these constitute undefined behaviour.
I used to use _FILENAMEHERE_H_
I now use FileNameHere_H_GUARD
Interesting... I've been using the top method since the beginning as that was the way I was taught. Never seen a problem...
I could be wrong, but I assumed it wasn't a compiler rule, but a good practice. Like root declaring environment variables in all CAPS (or was it the other way around) in a *nix environment. I think it's only a problem if that identifier is already defined, such as _FILE_.
Double underscores. Single underscores should be fine.
Single underscores followed by an uppercase letter are reserved for compiler usage.
Its perfectly defined. Expect problems when the symbol you chose happens to be used in the compiler or system headers sometime in the future.
Technically the C++ spec does not define if you will collide or not, and when that collision occurs the results are compiler specific and therefore undefined.
I agree with you , I was just saying undefined to make my sentence more english and less codelish.