Rotating square with mouse

I wanted to ask, how can i make a square rotate in base of

event.mouse.x
event.mouse.y

The square is al_draw_rectangle(x-15,y-15,x+15,y+15,al_map_rgb(0,0,255),3.0);

Is there any way to do that? The square cannot move with mouse, only with keyboard.

SiegeLord

Your question is a bit incomplete... let me use my A5 mind reading addon and guess what you actually want.

You can do that using transformations:

```ALLEGRO_TRANSFORM trans;
al_identity_transform(&trans);
al_translate_transform(&trans, -cx, -cy); //cx,cy are set to the mouse coordinates in the mouse event
al_rotate_transform(&trans, theta);
al_translate_transform(&trans, cx, cy);
al_use_transform(&trans);
al_draw_rectangle(x - 15, y - 15, x + 15, y + 15, al_map_rgb(0, 0, 255), 3.0);
/* Reset transform */
al_identity_transform(&trans);
al_use_transform(&trans);
```

Your code works perfect. But i need to rotate the square.
Here is what i want to do:
The square must be at the center and wont move. If i move the mouse, it wont move again.
It will only rotate in base of the mouse e.mouse.x and e.mouse.y

Edgar Reynaldo

Sorry, what? You need to be clearer.

What I gather so far :
1) The square is centered on the center of the screen.
2?) You want to rotate the square according to the direction from the center of the square to the mouse position?

```double theta_radians = atan2(event.mouse.y - square_center_y , event.mouse.x - square_center_x);
```

Then use a transform to center on the center of the square, then add in a rotate transform to rotate by theta_radians, then draw the square.

I have used the AMCerasoli video of networking, because it is clearer.
You see the player rotates when he moves the mouse?
I want to make the same thing, just with a square.

Also, the code of siege worked, but the center was not the square, but the top left corner of the screen. How to change the center?

SiegeLord

```ALLEGRO_TRANSFORM trans;
al_identity_transform(&trans);
al_rotate_transform(&trans, theta);
al_translate_transform(&trans, x, y);
al_use_transform(&trans);
al_draw_rectangle(-15, -15, 15, 15, al_map_rgb(0, 0, 255), 3.0);
/* Reset transform */
al_identity_transform(&trans);
al_use_transform(&trans);
```

You'd compute the theta using the formula Edgar posted.

Same thing again, it just moved a little

Who in the world understands this from the manual

"Apply a translation to a transformation."

Also, i tried scale transform and it didnt work at all with the mouse.

atan2 is wrong in my configuration after including math.h which wasnt even mentioned to use:
double theta_radians = atan2(e.mouse.y - (x + 15) , e.mouse.x - (y - 15));

SiegeLord

Same thing again, it just moved a little

Then you're doing something wrong, as this example shows that it works fine:

1#include <stdio.h> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_primitives.h> 4#include <math.h> 5int main() 6{ 7 al_init(); 8 ALLEGRO_DISPLAY* d = al_create_display(800, 600); 9 al_init_primitives_addon(); 10 al_install_mouse(); 11 al_install_keyboard(); 12 ALLEGRO_TIMER* t = al_create_timer(1.0 / 60); 13 ALLEGRO_EVENT_QUEUE* q = al_create_event_queue(); 14 al_register_event_source(q, al_get_mouse_event_source()); 15 al_register_event_source(q, al_get_keyboard_event_source()); 16 al_register_event_source(q, al_get_timer_event_source(t)); 17 18 int x = 200; 19 int y = 200; 20 int vx = 0; 21 int vy = 0; 22 int mx = 0; 23 int my = 0; 24 float theta = 0; 25 26 al_start_timer(t); 27 bool quit = false; 28 bool redraw = true; 29 while(!quit) 30 { 31 ALLEGRO_EVENT e; 32 al_wait_for_event(q, &e); 33 switch(e.type) 34 { 35 case ALLEGRO_EVENT_MOUSE_AXES: 36 mx = e.mouse.x; 37 my = e.mouse.y; 38 break; 39 case ALLEGRO_EVENT_KEY_DOWN: 40 switch(e.keyboard.keycode) 41 { 42 case ALLEGRO_KEY_ESCAPE: 43 quit = true; 44 break; 45 case ALLEGRO_KEY_RIGHT: 46 vx += 1; 47 break; 48 case ALLEGRO_KEY_LEFT: 49 vx -= 1; 50 break; 51 case ALLEGRO_KEY_UP: 52 vy -= 1; 53 break; 54 case ALLEGRO_KEY_DOWN: 55 vy += 1; 56 break; 57 } 58 break; 59 case ALLEGRO_EVENT_KEY_UP: 60 switch(e.keyboard.keycode) 61 { 62 case ALLEGRO_KEY_RIGHT: 63 vx -= 1; 64 break; 65 case ALLEGRO_KEY_LEFT: 66 vx += 1; 67 break; 68 case ALLEGRO_KEY_UP: 69 vy += 1; 70 break; 71 case ALLEGRO_KEY_DOWN: 72 vy -= 1; 73 break; 74 } 75 break; 76 case ALLEGRO_EVENT_TIMER: 77 x += vx; 78 y += vy; 79 theta = atan2(my - y, mx - x); 80 redraw = true; 81 break; 82 } 83 84 if(al_is_event_queue_empty(q) && redraw) 85 { 86 al_clear_to_color(al_map_rgb_f(0, 0, 0)); 87 88 ALLEGRO_TRANSFORM trans; 89 al_identity_transform(&trans); 90 al_rotate_transform(&trans, theta); 91 al_translate_transform(&trans, x, y); 92 al_use_transform(&trans); 93 al_draw_rectangle(-15, -15, 15, 15, al_map_rgb(0, 0, 255), 3.0); 94 /* Reset transform */ 95 al_identity_transform(&trans); 96 al_use_transform(&trans); 97 98 al_flip_display(); 99 } 100 } 101 102 return 0; 103}

atan2 doesnt work. I dont know why. I am using visual studio 2012
I copy pasted your code and it doesnt work on my machine only because of atan2

Arthur Kalliokoski

Used this path
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\include;%(AdditionalLibraryDirectories)

Then i tried this other one
C:\Program Files %28x86%29\Microsoft Visual Studio 11.0\VC\include

Still the same

CodeStepper
``` theta = atan2(my - y, mx - x);
```

I have the same problem
Try this

``` theta = atan2((float)(my - y), (float)(mx - x));
```

Theta in this case must be float

I am using visual studio 2012

o.O
Visual Studio for Windows 8?
Is there Intelisense? I'm using 2008, because 2010 haven't got intelisense :/

And I think, that this is better way to do rotate something:

1#include <allegro5/allegro.h> 2#include <allegro5/allegro_primitives.h> 3#include <allegro5/allegro_font.h> 4#include <allegro5/allegro_ttf.h> 5#include <math.h> 6 7int main( void ) 8{ 9 // Inicjalizacja bibliotek 10 al_init( ); 11 al_init_primitives_addon( ); 12 al_init_font_addon( ); 13 al_init_ttf_addon( ); 14 15 // Instalowanie kontrolerów 16 al_install_mouse( ); 17 al_install_keyboard( ); 18 al_install_joystick( ); 19 20 // Zmienne allegro 21 ALLEGRO_DISPLAY *display = al_create_display( 800, 600 ); 22 ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue( ); 23 ALLEGRO_TIMER *timer = al_create_timer( 1.0 / 60 ); 24 25 // Rejestrowanie zdarzeń 26 al_register_event_source( queue, al_get_keyboard_event_source( ) ); 27 al_register_event_source( queue, al_get_mouse_event_source( ) ); 28 al_register_event_source( queue, al_get_joystick_event_source( ) ); 29 al_register_event_source( queue, al_get_display_event_source( display ) ); 30 al_register_event_source( queue, al_get_timer_event_source( timer ) ); 31 32/////////////////////////////////////////////////////////////////////////////// 33 // CREATE BITMAP 34/////////////////////////////////////////////////////////////////////////////// 35 ALLEGRO_BITMAP *bitmap = al_create_bitmap( 40, 40 ); 36 al_set_target_bitmap( bitmap ); 37 al_clear_to_color( al_map_rgb( 60, 80, 100 ) ); 38 al_set_target_bitmap( al_get_backbuffer( display ) ); 39 40 bool run = true; 41 bool render = true; 42 43 bool keys[4] = { false, false, false, false }; 44 45 int posx = 40; 46 int posy = 40; 47 float theta = 0; 48 49 al_start_timer( timer ); 50 while( run ) 51 { 52 ALLEGRO_EVENT event; 53 al_wait_for_event( queue, &event ); 54 55 switch( event.type ) 56 { 57 case ALLEGRO_EVENT_DISPLAY_CLOSE: 58 59 run = false; 60 61 break; 62 case ALLEGRO_EVENT_TIMER: 63 64 render = true; 65 66 break; 67 case ALLEGRO_EVENT_KEY_DOWN: 68 69 switch( event.keyboard.keycode ) 70 { 71 case ALLEGRO_KEY_UP: 72 keys[0] = true; 73 break; 74 case ALLEGRO_KEY_DOWN: 75 keys[1] = true; 76 break; 77 case ALLEGRO_KEY_LEFT: 78 keys[2] = true; 79 break; 80 case ALLEGRO_KEY_RIGHT: 81 keys[3] = true; 82 break; 83 } 84 85 break; 86 case ALLEGRO_EVENT_KEY_UP: 87 88 switch( event.keyboard.keycode ) 89 { 90 case ALLEGRO_KEY_UP: 91 keys[0] = false; 92 break; 93 case ALLEGRO_KEY_DOWN: 94 keys[1] = false; 95 break; 96 case ALLEGRO_KEY_LEFT: 97 keys[2] = false; 98 break; 99 case ALLEGRO_KEY_RIGHT: 100 keys[3] = false; 101 break; 102 case ALLEGRO_KEY_ESCAPE: 103 run = false; 104 break; 105 } 106 107 break; 108 case ALLEGRO_EVENT_MOUSE_AXES: 109 theta = atan2( (float)(event.mouse.y - posy + 10), (float)(event.mouse.x - posx + 10) ); 110 break; 111 } 112 113 if( render && al_is_event_queue_empty( queue ) ) 114 { 115 render = false; 116 al_clear_to_color( al_map_rgb( 250, 250, 250 ) ); 117 118 if( keys[0] ) posy -= 3; 119 else if( keys[1] ) posy += 3; 120 if( keys[2] ) posx -= 3; 121 else if( keys[3] ) posx += 3; 122 123/////////////////////////////////////////////////////////////////////////////// 124 // ROTATE BITMAP 125/////////////////////////////////////////////////////////////////////////////// 126 al_draw_rotated_bitmap( bitmap, 20, 20, posx, posy, theta, 0 ); 127 128 al_flip_display( ); 129 } 130 } 131 132 // Destruktory 133 al_destroy_display ( display ); 134 al_destroy_event_queue ( queue ); 135 al_destroy_timer ( timer ); 136 al_destroy_bitmap ( bitmap ); 137 138 return 0; 139}

SiegeLord

Theta in this case must be float

There is no integer version of atan2, that's just nonsensical.

What does this code print?

```#include <iostream>
#include <typeinfo>
#include <math.h>

int main()
{
std::cout << typeid(atan2((int)0, int(0))).name() << std::endl;
return 0;
}
```

Quote:

And I think, that this is better way to do rotate something:

My way is better for primitives and in fact works for all drawables, while your way only works for bitmaps.

CodeStepper

Oh... but there is double, long dobule and float atan2 version!

In fact, you can create bitmap from all drawable primitives and then rotate it

While I compile your code, there is error:

```error C2668: 'atan2' : ambiguous call to overloaded function
c:\program files\microsoft visual studio 9.0\vc\include\math.h(547): could be 'long double atan2(long double,long double)'
c:\program files\microsoft visual studio 9.0\vc\include\math.h(499): or       'float atan2(float,float)'
c:\program files\microsoft visual studio 9.0\vc\include\math.h(110): or       'double atan2(double,double)'
while trying to match the argument list '(int, int)'
```

I must do cast to float.

Sory, but my previous words are logical

SiegeLord

In fact, you can create bitmap from all drawable primitives and then rotate it

Inefficient and unnecessary.

Quote:

While I compile your code, there is error:

Well a compile error makes sense. It compiling without error and then not functioning does not. Either way, the original code is C not C++ .

CodeStepper

But if you using bitmaps in this case, application works better
Processor has less to count
At least I think so...

SiegeLord

But if you using bitmaps in this case, application works better

If you only need to rotate a single pre-existing bitmap, then yeah... no need for transformations.

AMCerasoli

Well, I'm currently not using transformations at all...

@codestepper
WOW THANKS! It works perfect! Can you make some notes in english to the program so i can understand it better? I mean especially the transformation, because i dont understand it well.

Visual Studio 2012 is the same as 2010, with some changes and it has intellisense.
I have had 2010 and it had intellisense, i dont know what version you had. I have worked on both for Allegro 5. I recently moved a game from VC9 to VC10 and it was very easy and fast.

I dont get it why it is a bad thing to do it like that, because it works 100%

Also, if anyone can make a pacman which opens its mouth using the al_draw_pieslice that would be great as i was trying to do it today without any success.

@cerasoli
What is your method of doing it?

CodeStepper

Hmm... i think i don't make any bugs in comments
If yes, sorry

Sorry for variable names - some of them don't reflect their roles

So, code for pac-man primitives version with comments:

1#include <stdio.h> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_primitives.h> 4#include <math.h> 5#include <iostream> 6int main() 7{ 8 const float framesPerSecond = 60; /////////////////// frames 9 10 al_init(); 11 ALLEGRO_DISPLAY* d = al_create_display(800, 600); 12 al_init_primitives_addon(); 13 al_install_mouse(); 14 al_install_keyboard(); 15 ALLEGRO_TIMER* t = al_create_timer(1.0 / framesPerSecond); 16 ALLEGRO_EVENT_QUEUE* q = al_create_event_queue(); 17 al_register_event_source(q, al_get_mouse_event_source()); 18 al_register_event_source(q, al_get_keyboard_event_source()); 19 al_register_event_source(q, al_get_timer_event_source(t)); 20 21 int x = 200; // position x 22 int y = 200; // position y 23 int vx = 0; // velocity x 24 int vy = 0; // velocity y 25 int mx = 0; // mouse x 26 int my = 0; // mouse y 27 float theta = 0; // theta ( atan2 ) 28 29 // Maximum radius ( 360 degress in radians ) - half is 3.14159, ( so, half it's PI ) 30 const float maxDelta = 6.28318; 31 // Minimum radius ( minimum radius of slice ( maxDelta - minDelta is real radius of slice ) ) 32 const float minDelta = 5.0; 33 34 // Automatic variables 35 float deltaFrame = ( maxDelta - minDelta ) / framesPerSecond; // value of delta adding in every frame per second 36 float currDelta = maxDelta; // start theta in 37 float currDelta2 = minDelta; // delta_theta 38 float halfDelta = ( maxDelta - minDelta ) / 2; // half of 39 40 // Decide, (TRUE) if currDelta is increasing and currDelta2 decreasing or vice versa (FALSE) 41 bool growing = false; 42 43 al_start_timer(t); 44 bool quit = false; 45 bool redraw = true; 46 while(!quit) 47 { 48 ALLEGRO_EVENT e; 49 al_wait_for_event(q, &e); 50 switch(e.type) 51 { 52 case ALLEGRO_EVENT_MOUSE_AXES: 53 mx = e.mouse.x; 54 my = e.mouse.y; 55 break; 56 case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: 57 al_rest( 1 ); 58 break; 59 case ALLEGRO_EVENT_KEY_DOWN: 60 switch(e.keyboard.keycode) 61 { 62 case ALLEGRO_KEY_ESCAPE: 63 quit = true; 64 break; 65 case ALLEGRO_KEY_RIGHT: 66 vx += 1; 67 break; 68 case ALLEGRO_KEY_LEFT: 69 vx -= 1; 70 break; 71 case ALLEGRO_KEY_UP: 72 vy -= 1; 73 break; 74 case ALLEGRO_KEY_DOWN: 75 vy += 1; 76 break; 77 } 78 break; 79 case ALLEGRO_EVENT_KEY_UP: 80 switch(e.keyboard.keycode) 81 { 82 case ALLEGRO_KEY_RIGHT: 83 vx -= 1; 84 break; 85 case ALLEGRO_KEY_LEFT: 86 vx += 1; 87 break; 88 case ALLEGRO_KEY_UP: 89 vy += 1; 90 break; 91 case ALLEGRO_KEY_DOWN: 92 vy -= 1; 93 break; 94 } 95 break; 96 case ALLEGRO_EVENT_TIMER: 97 x += vx; 98 y += vy; 99 theta = atan2((float)(my - y), (float)(mx - x)); 100 redraw = true; 101 break; 102 } 103 104 if(al_is_event_queue_empty(q) && redraw) 105 { 106 al_clear_to_color(al_map_rgb_f(0, 0, 0)); 107 108 // Transformation 109 ALLEGRO_TRANSFORM trans; 110 al_identity_transform(&trans); // creating transformation 111 al_rotate_transform(&trans, theta); // rotating display 112 al_translate_transform(&trans, x, y); // moving transformation ( display ) 113 al_use_transform(&trans); // using transformation 114 115 // Drawing pieslice 116 al_draw_pieslice( 0, 0, 20, currDelta + halfDelta, currDelta2, al_map_rgb( 255, 0, 0 ), 2 ); 117 118 /* Reset transform */ 119 al_identity_transform(&trans); 120 al_use_transform(&trans); 121 122 // Checking radius 123 if( currDelta >= maxDelta ) growing = false; 124 else if( currDelta <= minDelta + halfDelta ) growing = true; 125 126 // Decreasing or increasing 127 // In case variable currDelta2, value is multipled * 2, that the top line was moving 128 if( growing ) currDelta += deltaFrame, currDelta2 -= deltaFrame * 2; 129 else currDelta -= deltaFrame, currDelta2 += deltaFrame * 2; 130 131 al_flip_display(); 132 } 133 } 134 135 al_destroy_display( d ); 136 al_destroy_event_queue( q ); 137 al_destroy_timer( t ); 138 return 0; 139}

Wow, you are amazing!
Thank you very much man, it worked perfect

CodeStepper

```redraw = false;
```al_clear_to_color(al_map_rgb_f(0, 0, 0));