Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Bitmap Rotation

This thread is locked; no one can reply to it. rss feed Print
Bitmap Rotation
moon_rabbits
Member #8,469
March 2007
avatar

Here's the source:

tank.cpp

#SelectExpand
1/******************** 2 * Tank Source File * 3 ********************/ 4 5#include <math.h> 6#include <allegro.h> 7#include "tank.h" 8 9CTank::CTank() 10/* Sets up tank object */ 11{ 12 x = (SCREEN_W/2); // init player 13 y = SCREEN_H - (SCREEN_H/6); 14 health = 100; 15 reload = 0; 16 score = 0; 17 speed = TANK_SPEED; 18 19 canx = x + TANK_W/2 - CANNON_W/2; 20 cany = y - CANNON_H + (CANNON_H/4); 21 22 tank = create_bitmap(TANK_W, TANK_H); 23 cannon = create_bitmap(CANNON_W, CANNON_H); 24 25 // draw tank to tank bitmap 26 clear_to_color(tank, makecol(255, 0, 255)); 27 rectfill(tank, 10, 0, (TANK_W-10), TANK_H-(TANK_H/4), makecol(45, 200, 60)); 28 rect(tank, 10, 0, (TANK_W-10), TANK_H-(TANK_H/4), makecol(60, 230, 70)); 29 30 ellipsefill(tank, (TANK_W/2), TANK_H-(TANK_H/4)-1, (TANK_W/2)-1, 31 (TANK_H/4), makecol(160, 160, 160)); 32 ellipse(tank, (TANK_W/2), TANK_H-(TANK_H/4)-1, (TANK_W/2)-1, 33 (TANK_H/4), makecol(120, 120, 120)); 34 35 // draw cannon to cannon bitmap 36 clear_to_color(cannon, makecol(255, 0, 255)); 37 rectfill(cannon, 0, 0, CANNON_W, CANNON_H, makecol(45, 200, 60)); 38 rect(cannon, 0, 0, CANNON_W-1, CANNON_H-1, makecol(60, 230, 70)); 39} 40//-------------------------------------------- 41 42CTank::~CTank() 43/* Deletes tank bmps */ 44{ 45 destroy_bitmap(tank); 46 destroy_bitmap(cannon); 47} 48//-------------------------------------------- 49 50void CTank::MoveTank() 51/* Moves tank */ 52{ 53 54 if((key[KEY_LEFT]) && (x > 0)){ 55 x -= speed; 56 canx -= speed; 57 } 58 59 if((key[KEY_RIGHT]) && ((x+TANK_W) < SCREEN_W)){ 60 x += speed; 61 canx += speed; 62 } 63 64 angle = atan((canx-(CANNON_W/2)-mouse_x)/(cany-(CANNON_H/2)-mouse_y))/(3.1415/180); 65 66 return; 67} 68//-------------------------------------------- 69 70void CTank::FireBullet() 71{} 72//-------------------------------------------- 73 74void CTank::DrawTank(BITMAP *surface) 75{ 76 // blit tank to *surface 77 masked_blit(tank, surface, 0, 0, x, y, TANK_W, TANK_H); 78 // blit cannon to *surface 79 rotate_sprite(surface, cannon, int(canx), int(cany), ftofix(-angle)); 80 textprintf_ex(screen, font, 0, 10, makecol(255,255,255), 0, 81 "Angle = %f", angle); 82} 83//--------------------------------------------

tank.h

#SelectExpand
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 TANK_SPEED 1 16 17#define CANNON_W 15 18#define CANNON_H 30 19 20class CTank 21{ 22public: 23 CTank(); 24 ~CTank(); 25 26 int x, y; // x and y coordinate of the player 27 int health; // health of the player 28 int reload; // reload time of the player 29 int speed; 30 31 float canx; 32 float cany; 33 float angle; // angle of cannon 34 35 int score; 36 37 BITMAP *tank, *cannon; //bitmaps to hold the tank and cannon 38 39 void MoveTank(); 40 void FireBullet(); 41 void DrawTank(BITMAP *surface); 42}; 43 44#endif

main.cpp

#SelectExpand
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 17int SetUp() 18/* Initializes allegro and screen */ 19{ 20 allegro_init(); 21 22 install_keyboard(); 23 install_mouse(); 24 install_timer(); 25 26 set_color_depth(16); 27 28 if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, WINDOW_W, WINDOW_H, 0, 0) != 0) 29 return 1; 30 31 srand(time(0)); 32 33 show_mouse(screen); 34 35 return 0; 36} 37//-------------------------------------------- 38 39void cloud_line(BITMAP *bmp, int x, int y, int color) 40/* Function called by DoLine() */ 41{ 42 putpixel(bmp, x, y, color); 43 44 return; 45} 46//-------------------------------------------- 47 48void MakeCloud(BITMAP *bmp) 49/* Draws a cloud to bmp */ 50{ 51 int height = 1 + (rand()%50); // height of cloud 52 int width = 100 + (rand()%50); // general width of cloud 53 54 int x1 = (-30) + rand()%(SCREEN_W-30); 55 int x2 = x1 + width; 56 int y = 10 + rand()%(SCREEN_H-100); // cloud coordinates 57 58 int col = makecol(255,255,255); // cloud color information 59 60 for(int i = 0; i < height; i++) // loops until entire cloud is drawn 61 { 62 do_line(bmp, x1, y, x2, y, col, *cloud_line); // draw line of cloud 63 y += 1; 64 65 if(i < (height/2)){ 66 x1 -= 3 + rand()%5; 67 x2 += 3 + rand()%5;} 68 else{ 69 x1 += 3 + rand()%5; 70 x2 -= 3 + rand()%5;} 71 } 72 73 return; 74} 75//-------------------------------------------- 76 77BITMAP* GenerateSky(BITMAP *bmp) 78/* Generates a sky on bitmap pointed 79 to by bmp */ 80{ 81 int r = 140, g = 150, b = 225; 82 int col = makecol(r, g, b); 83 84 85 floodfill(bmp, SCREEN_W/2, SCREEN_H/2, col); // fill screen w/ blue 86 87 int clouds = (rand()%(MAX_CLOUDS-MIN_CLOUDS) + MIN_CLOUDS); 88 89 for(int c = 0; c < clouds; c++) 90 MakeCloud(bmp); 91 92 return bmp; 93} 94//-------------------------------------------- 95 96int main() 97{ 98 if(SetUp() != 0) return 1; // setup + error checking for allegro 99 100 BITMAP *bg_sky = create_bitmap(SCREEN_W, SCREEN_H); // create sky bitmap 101 BITMAP *buffer = create_bitmap(SCREEN_W, SCREEN_H); // create double buffer 102 103 bg_sky = GenerateSky(bg_sky); // colour sky bitmap 104 105 CTank player; 106 107 while(!key[KEY_ESC]){ 108 109 blit(bg_sky, buffer, 0, 0, 0, 0, bg_sky->w, bg_sky->h); 110 111 player.MoveTank(); 112 player.DrawTank(buffer); 113 114 blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H); 115 }; 116 117 destroy_bitmap(bg_sky); 118 destroy_bitmap(buffer); 119 120 return(0); 121}END_OF_MAIN()

The problem lies in the tank.cpp file. In the MoveTank() function, there is a call to atan() to determine the angle of the mouse in degrees from the center of a bitmap of a cannon.

The cannon rotates to face the mouse, basically. But there are errors, it jumps around sometimes when you pass certain parts, and if you keep the mouse near the top of the window and drag it too far left or right, the cannon stops facing it (it faces too far down).

Is there any way I can improve upon the angle calculation?

Onewing
Member #6,152
August 2005
avatar

Perhaps try atan2()?

------------
Solo-Games.org | My Tech Blog: The Digital Helm

moon_rabbits
Member #8,469
March 2007
avatar

Thank you, but the problem persists.

Dustin Dettmer
Member #3,935
October 2003
avatar

#ifndef _TANK_H 
#define _TANK_H

This is bad style, never follow an underscore with an upper case letter

Ceagon Xylas
Member #5,495
February 2005
avatar

tan-1 takes the paramater y/x. You're calculating x/y.

angle=atan((cany-(CANNON_H/2)-mouse_y)/(canx-(CANNON_W/2)-mouse_x));
//or, use atan2
angle=atan2(cany-(CANNON_H/2)-mouse_y,canx-(CANNON_W/2)-mouse_x);

[edit]
Oh, and I forgot to add the proper conversion from radians to fix.
rotate_sprite(buffer,sprite,x,y,ftofix(angle*128.0/M_PI));

Onewing
Member #6,152
August 2005
avatar

Quote:

This is bad style, never follow an underscore with an upper case letter

Dustin Dettmer earlier said:

Single underscores followed by an uppercase letter are reserved for compiler usage.

What compiler? Any compiler? I've been doing this for a long time and it has never been a problem.

And if you are planning on telling all who do this to stop, you've got an uphill battle in front of you. As far as I can tell, this is the way it is taught to many. I'm not saying you are wrong, I'm just kind of floored by it.

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Kitty Cat
Member #2,815
October 2002
avatar

Quote:

What compiler? Any compiler?

Yup. Macros and symbols starting with an underscore and capital letter, and starting with two underscores and anything, are reserved for the compiler. You can use them sure.. but then it's your own fault if it happens to conflict with an undocumented portion of the compiler.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Onewing
Member #6,152
August 2005
avatar

Quote:

but then it's your own fault if it happens to conflict with an undocumented portion of the compiler.

Is it really all that likely to happen though? I mean, if you do CLASSNAME_H? Well, I guess that's why it's good practice not to do that, just for that unlikely case.

That's going to be a hard habit to break. :-/

------------
Solo-Games.org | My Tech Blog: The Digital Helm

Thomas Fjellstrom
Member #476
June 2000
avatar

Not to mention any symbol tarting with a single underscore and lower case letter is reserved for system/library internal use . Thats sortof unofficial though. Still a good style guide line. You can always tell when a symbol is out of limits.

Quote:

That's going to be a hard habit to break. :-/

Didn't take me long. I used to use _FILE_H_, I now use File_H_GUARD.. simple switch :)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Go to: