Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » A program in need of analysis

Credits go to Erkle for helping out!
This thread is locked; no one can reply to it. rss feed Print
A program in need of analysis
Kikaru
Member #7,616
August 2006
avatar

OK, I wrote a program here:

#SelectExpand
1#include "allegro.h" 2#include "nl.h" 3 4//define some convenient constants 5#define MODE GFX_AUTODETECT_WINDOWED 6#define WIDTH 640 7#define HEIGHT 480 8#define S_VOLUME 25 9#define BLACK makecol (0, 0, 0) 10#define LIGHT_BLUE makecol (64, 128, 255) 11#define WHITE makecol (255, 255, 255) 12#define GRASS makecol (0, 255, 64) 13#define R 0 14#define L 1 15#define SPD 2 16#define BLOCKS 20 17#define BLOCK_FALL 2 18 19//define class: Trace 20class trace 21{ 22public: 23int x1, x2, y1, y2, active; 24}; 25 26//define class: Character 27class character 28{ 29public: 30int x, y, dir, combo, score; 31float x_spd, y_spd; 32trace trail; 33BITMAP *image; 34void move(); 35}; 36 37void character::move() 38{ 39x += int(x_spd); 40y += int(y_spd); 41return; 42} 43 44//define classes: part and thing 45class part 46{ 47public: 48int x, y, active; 49BITMAP *image; 50}; 51 52class thing 53{ 54public: 55int x, y, active, weight; 56//BITMAP *image; 57}; 58 59//define class: game_timer 60class game_timer 61{ 62public: 63int play_loop, play_sec, play_min; 64}; 65 66//variables 67BITMAP *aimer, *buffer, *resources, *player_panel, *block_pic; 68character player; 69thing block[BLOCKS]; 70part piece[(BLOCKS+1)*2]; 71int mouseisdown, dash_delay, gravity, till_next, next_block = 50; 72game_timer play_time, time_left; 73 74//it does what it says! 75void set_direction(int goto_x, int goto_y) 76{ 77//left 78if (goto_x < player.x + 12) 79{ 80player.x_spd = -SPD; 81} 82//right 83if (goto_x > player.x - 12) 84{ 85player.x_spd = SPD; 86} 87//up 88if (goto_y < player.y + 12) 89{ 90player.y_spd = -SPD; 91} 92//down 93if (goto_y > player.y - 12) 94{ 95player.y_spd = SPD; 96} 97//got diagonal? 98if ((!(player.y_spd == 0))&&(!(player.x_spd == 0))) 99{ 100player.y_spd = player.y_spd/2; 101player.x_spd = player.x_spd/2; 102} 103return; 104} 105 106//check for collisions 107int is_cut(BITMAP *obj_layer ,int obj_x, int obj_y, int obj_size) 108{ 109BITMAP *clip_board = create_bitmap(obj_size, obj_size); 110int scan_x = 0, scan_y = 0; 111blit(obj_layer, clip_board, obj_x - obj_size/2, obj_y - obj_size/2, 0, 0, obj_size, obj_size); 112while (scan_y < obj_size-1) 113{ 114 while (scan_x< obj_size-1) 115 { 116 if(getpixel(clip_board, scan_x, scan_y) == LIGHT_BLUE) 117 { 118 destroy_bitmap(clip_board); 119 return 1; 120 } 121 scan_x += 1; 122 } 123 scan_y += 1; 124 scan_x = 0; 125} 126destroy_bitmap(clip_board); 127return 0; 128} 129 130//main function 131void main(void) 132{ 133 //initialize allegro 134 allegro_init(); 135 install_keyboard(); 136 install_mouse(); 137 install_timer(); 138 set_color_depth(24); 139 if(set_gfx_mode(MODE, WIDTH, HEIGHT, 0, 0) != 0) 140 { 141 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); 142 allegro_message(allegro_error); 143 return; 144 } 145 text_mode(-1); 146 install_sound(DIGI_AUTODETECT, MIDI_NONE, ""); 147 //initialize HawkNL 148 nlInit(); 149 150 //load graphics 151 resources = load_bitmap("ninja.bmp", NULL); 152 153 //load sounds 154 155 //initalize settings 156 player_panel = create_bitmap(192, 64); 157 player.image = create_bitmap(64, 64); 158 block_pic = create_bitmap(64, 64); 159 stretch_blit(resources, block_pic, 0, 32, 32, 32, 0, 0, 64, 64); 160 int i = 0; 161 //while (i < 42) 162 //{ 163 //piece<i>.image = create_bitmap(64, 64); 164 //i += 1; 165 //} 166 buffer = create_bitmap(WIDTH, HEIGHT); 167 aimer = create_bitmap(32, 32); 168 blit(resources, aimer, 96, 0, 0, 0, 32, 32); 169 stretch_blit(resources, player_panel, 0, 0, 96, 32, 0, 0, 192, 64); 170 blit(player_panel, player.image, 64, 0, 0, 0, 64, 64); 171 rectfill(buffer, 0, 0, WIDTH, HEIGHT, WHITE); 172 destroy_bitmap(resources); 173 174 175 //main loop 176 while (!key[KEY_ESC]) 177 { 178 179 //dashing 180 if ((mouse_b & 1)&&(!mouseisdown)&&(dash_delay >= 12)) 181 { 182 //new image 183 blit(player_panel, player.image, 0, 0, 0, 0, 64, 64); 184 //change direction 185 if (mouse_x > player.x) 186 player.dir = R; 187 if (mouse_x < player.x) 188 player.dir = L; 189 //make the trail 190 player.trail.x1 = player.x; 191 player.trail.y1 = player.y; 192 player.trail.x2 = mouse_x; 193 player.trail.y2 = mouse_y; 194 player.trail.active = 1; 195 //move player 196 set_direction(mouse_x, mouse_y); 197 player.x = mouse_x; 198 player.y = mouse_y; 199 //reset 200 dash_delay = 0; 201 mouseisdown = TRUE; 202 gravity = 0; 203 } 204 205 if (!mouse_b & 1) 206 mouseisdown = FALSE; 207 208 dash_delay += 1; 209 210 //trail vanishes... now! 211 if (dash_delay >= 18) 212 player.trail.active = 0; 213 214 player.move(); 215 216 //fall 217 if (dash_delay >= 15) 218 { 219 blit(player_panel, player.image, 128, 0, 0, 0, 64, 64); 220 gravity += 1; 221 player.y += gravity/3; 222 player.x_spd = 0; 223 player.y_spd = 0; 224 } 225 226 till_next += 1; 227 //drop blocks 228 i = 0; 229 while (i < BLOCKS) 230 { 231 if ((!(block<i>.active))&&(till_next >= next_block - play_time.play_min*5)) 232 { 233 block<i>.active = 1; 234 block<i>.x = ((rand()%17)*32)+64; 235 block<i>.y = -32; 236 block<i>.weight = rand()%3 + BLOCK_FALL; 237 till_next = 0; 238 i = BLOCKS; 239 } 240 else 241 i += 1; 242 } 243 //blocks fall 244 i = 0; 245 while (i < BLOCKS) 246 { 247 block<i>.y += block<i>.weight; 248 if (block<i>.y >= 400) 249 { 250 block<i>.active = 0; 251 } 252 i += 1; 253 } 254 255 //cut blocks 256 i = 0; 257 if (dash_delay < 3) 258 { 259 while (i < BLOCKS) 260 { 261 if (is_cut(screen, block<i>.x, block<i>.y, 64)&&(block<i>.active == 1)&&(block<i>.y > 16)) 262 { 263 player.combo += 1; 264 block<i>.active = 0; 265 } 266 i += 1; 267 } 268 } 269 player.score += player.combo*player.combo; 270 player.combo = 0; 271 272 //bottom 273 if (player.y >= 400) 274 { 275 player.y = 400; 276 blit(player_panel, player.image, 64, 0, 0, 0, 64, 64); 277 } 278 279 //setup the buffer 280 rectfill(buffer, 0, 0, WIDTH, HEIGHT, WHITE); 281 //draw blocks 282 i = 0; 283 while (i < BLOCKS) 284 { 285 if (block<i>.active == 1) 286 draw_sprite(buffer, block_pic, block<i>.x-32, block<i>.y-32); 287 i += 1; 288 } 289 //draw player trail 290 if (player.trail.active == 1) 291 line(buffer, player.trail.x1, player.trail.y1, player.trail.x2, player.trail.y2, LIGHT_BLUE); 292 //draw player 293 if (player.dir == R) 294 draw_sprite(buffer, player.image, player.x-32, player.y-32); 295 else 296 draw_sprite_h_flip(buffer, player.image, player.x-32, player.y-32); 297 298 //text 299 textprintf(buffer, font, 100, 460, BLACK, "Score:%i", player.score); 300 textprintf(buffer, font, 260, 460, BLACK, "%i' ", play_time.play_min); 301 textprintf(buffer, font, 280, 460, BLACK, "%i'' ", play_time.play_sec); 302 textprintf(buffer, font, 310, 460, BLACK, "%i", play_time.play_loop); 303 304 //draw the mouse 305 draw_sprite(buffer, aimer, mouse_x, mouse_y); 306 307 //draw the screen 308 blit(buffer, screen, 0, 0, 0, 0, WIDTH, HEIGHT); 309 310 //timer 311 play_time.play_loop += 1; 312 if (play_time.play_loop >= 39) 313 { 314 play_time.play_sec += 1; 315 play_time.play_loop -= 39; 316 } 317 if (play_time.play_sec >= 60) 318 { 319 play_time.play_min += 1; 320 play_time.play_sec -= 60; 321 } 322 323 //delay 324 rest(25); 325 } 326 327 //shut down HawkNL 328 nlShutdown(); 329 //clean up 330 destroy_bitmap(player_panel); 331 destroy_bitmap(aimer); 332 destroy_bitmap(buffer); 333 return; 334} 335 336END_OF_MAIN();

I have the linker set and everything works fine, only sometimes you kill an object when its up near the top. It ONLY happens when a block is near the top. anyone see what's causing it? ???

Richard Phipps
Member #1,632
November 2001
avatar

Quote:

only sometimes you kill an object when its up near the top

What do you mean? I don't understand the problem.

Indeterminatus
Member #737
November 2000
avatar

I'm sorry, but I also don't know what the problem is. Could you elaborate on:

  • What's happening?

  • How is it reproducable?

  • What should happen if the code was well-formed?

Following are a few suggestions, which as I always point out are meant as suggestions, and are of course neither mandatory nor objective, so add a "imho" to everything I say ;)

A construct like this:

int i = 0;
while ( i < SOMETHING ) {
  /* do something */
  i += 1;
}

Is better expressed with a for loop, like here:

for ( int i = 0; i < SOMETHING; ++i ) {
  /* do something */
}

It's not wrong, mind you, both work just fine.

On a similar note, assuming you won't need i to be a specific value later on, this could be rewritten:

int i = 0;
while ( i < SOMETHING ) {
  /* break out of loop */
  i = SOMETHING; // <-- this line I'm talking about
  ...

Breaking out of the loop can be achieved by making its condition false, but what I saw in your code, you don't need to execute the rest of the loop body, and you also don't access i in any way that it'd be important that it had the value SOMETHING.
There's a keyword for exactly that situation, namely break, which I find fits better here. There's another side of the coin, though, as break tends to make analysis of program flow somewhat more complex a task, which is why you'll find some programmers opposing its use. I don't want to get political about that, so I leave it up to you to decide - just pointing out another way (if you already knew that, you can ignore this comment :P).

Some of the formatting might have been lost somewhere during the copy & paste, however I feel obliged to point out to follow at least basic indentation rules. I'm sure Google will know something about them.

In your class part, the member active is declared as int, however it is used like a boolean variable. I suggest using bool instead, because that's the data type you really want here.

edit: Fixed a typo.

_______________________________
Indeterminatus. [Atomic Butcher]
si tacuisses, philosophus mansisses

Kikaru
Member #7,616
August 2006
avatar

Sorry, I was rushed when I wrote that. During the game, blocks fall from the top of the screen. You need to draw lines through them using the mouse to cut them. For the blocks to be hit, the line needs to actually cross through the object's on-screen image. Right now, attacks will sometimes hit blocks near the top of the screen, even if the are on the opposite side of the screen form where you drew the line.

P.S. I might get a copy of the program up later.

Erkle
Member #3,493
May 2003
avatar

From what i can see, your is_cut function does the following:

  • Creates a bitmap of the same size as the object.

  • Blits a piece of the screen to the clipboard.

If obj_x > obj_size*3/2 or obj_y > obj_size*3/2 then this will be a white
square from outside the screen buffer.

  • Then check if any pixel in the buffer except those on the right or

bottom are light blue.

This doesn't seem to have anything to do with checking if a line cuts an object. My advice would be to start is_cut from scratch after asking how to do so in this thread. Try looking up do_line, it might be a good start.

If the writing above has offended you, you've read it wrong.....fool.
And if you read that wrong it means 'All of the above is opinion and is only to be treated as such.'

Kikaru
Member #7,616
August 2006
avatar

The is_cut function does the following: using its arguments, it grabs a portion of the bitmap (obj_layer), and scans it for LIGHT_BLUE pixels. LIGHT_BLUE is a color used ONLY in the slash lines. The -1 to obj_size are because position starts counting at zero. (If you have a bitmap 100 pixels wide, the far left will be 0, the far right will be 99)

However, thank you for pointing out about the size error. :)

EDIT: I changed the size, and it works now! thank you very much

EDIT2: How would do_line help at all? ???

Erkle
Member #3,493
May 2003
avatar

My bad, I got the source_x/y and dest_x/y back to front again:-[. Good thing 4.3 has a better format. I also assumed you wanted to check the line to see if an object was under it rather than check each object to see if the line is on it.

Quote:

The -1 to obj_size are because position starts counting at zero.

Then you want:
obj_y <= obj_size-1
but:
obj_y < obj_size
will be slightly more efficient.

On a side note: It would probably be more efficient to create clip_board in main() and pass it to is_cut so it doesn't have to be created and destroyed for every check.

If the writing above has offended you, you've read it wrong.....fool.
And if you read that wrong it means 'All of the above is opinion and is only to be treated as such.'

Kikaru
Member #7,616
August 2006
avatar

I worked out a way to use a do_line to eliminate the need for that. Suprise suprise? ;D

Go to: