Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Mouse Click Inside Timer Function

This thread is locked; no one can reply to it. rss feed Print
Mouse Click Inside Timer Function
Scooter
Member #16,799
January 2018

Hi all:
I was wondering if it was legal in allegro5 to have a

MOUSE DOWN inside a Timer function. The code below works

as far as the Timer, but allegro5 does NOT recognize when

I click the mouse button.

#SelectExpand
1 if(ev.type == ALLEGRO_EVENT_TIMER && play == true) 2 { 3 if(ev.timer.source == game_timer) 4 { 5 if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) 6 { 7 if(ev.mouse.button == 1) 8 { 9 pos_x = ev.mouse.x; 10 pos_y = ev.mouse.y; 11 angle = atan2(pos_y - ball_y, pos_x - ball_x); 12 13 for(i=0; i < 30; i++) 14 { 15 ball_x += cos(angle) * speed; 16 ball_y += sin(angle) * speed; 17 al_clear_to_color(al_map_rgb(20, 20, 20)); 18 al_draw_filled_circle(ball_x, ball_y, 15, al_map_rgb(255, 0, 0)); 19 al_flip_display(); 20 update(); 21 } 22 } 23 } 24 } 25code

Sorry code got kind of chopped off, but you can see the code.

If this is NOT legal, how could it be written to work.

Thanks for your time!

DanielH
Member #934
January 2001
avatar

The EVENT object is a union of specialized events. In a timer event, the mouse event data is invalid. You need to get mouse data elsewhere. Personally I keep variables that get updates during mouse events.

Scooter
Member #16,799
January 2018

Hi Daniel:

Thank you for the info! I was afraid I had hit another

bump in the road! I will have to try something else!

Thanks again!

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I think what you're looking for is something slightly different than what you tried. Your condition is impossible because if the event type is a TIMER event, then it can't be a MOUSE_DOWN event.

#SelectExpand
1//vars 2bool mb1 = false; 3 4if (ev.type == ALLEGRO_EVENT_MOUSE_DOWN) { 5 if (ev.mouse.button == 1) {mb1 = true;} 6} else if (ev.type == ALLEGRO_EVENT_MOUSE_UP) { 7 if (ev.mouse.button == 1) {mb1 = false;} 8} 9 10if (ev.type == ALLEGRO_EVENT_TIMER) { 11 if (ev.timer.source == logic_timer) { 12 if (mb1) { 13 /// Check if the mouse is held down during our logic timer 14 } 15 } 16}

Scooter
Member #16,799
January 2018

Thanks Edgar:

I am looking over your post. I am still having trouble

understanding how the mouse click is connected to the timer

function. I will work on the info you posted and maybe I can

see how it is connected.

Thanks for the information!

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

In allegro 5, we no longer use callbacks with timer functions. You process the event and then handle it at your leisure.

I am in effect replicating the ALLEGRO_MOUSE_STATE by using the mouse button up and down events to get the pressed state of the button. Then inside our reaction to the timer event, we process our mouse state so it only happens when the timer has a tick on it. This makes the rate steady with your timer.

8-)

Scooter
Member #16,799
January 2018

Hi Edgar:

That was the answer I was looking for.

Thanks again. Have a great day

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Scooter said:

for(i=0; i < 30; i++) {
   ball_x += cos(angle) * speed;
   ball_y += sin(angle) * speed;
   al_clear_to_color(al_map_rgb(20, 20, 20));
   al_draw_filled_circle(ball_x, ball_y, 15, al_map_rgb(255, 0, 0));
   al_flip_display();
   update();
}

Hey Scooter, just checking, does this code do what you want it to? Typically we only flip the display when we draw everything else on a timer event.

Scooter
Member #16,799
January 2018

Hi Edgar:
I had a few minutes and thought I would check in and you had
replied. Actually you solved the problem but I have many more
problems on top of that. This is the first time I have tried
to run two different things at the same time and it is NOT
going well at all. It is a very simple game I was trying my
hand at. I got the idea off the internet. I am trying to run
two timers at the same time.
I tried to post a picture of what I was trying to do, but couldn't
fine a way to do it. You used to be able to upload but not
anymore I guess.
Anyway, I have a round disc with a slot in it that rotates. You
then bounce a ball off the side and try to get the ball into the
slot. That's about it. Very simple I thought.
I can't seem to get the ball to move correctly and the rotating
disc seems to disappear. Then I would have to get involved in
collision detection. I was going to continue trying to figure it
out and get back with you later,
Thanks for the reply.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Most likely you only need one timer and two variables for ticks that increment on different rates.

As for collision detection, keep it simple as you can. A slot in a disc can be represented by a line segment on the radii of the disc. Then you test if the ball is at a certain angle to the center of the disc and see if it is close enough to be inside.

Scooter
Member #16,799
January 2018

Edgar:
I now have something that kinda works. I cut out the mouse and angles.
I now shoot the ball straight into the rotating disc. One problem still
remains: when I shoot the ball the rotating disc disappears. I am still
running two timers with update function for each timer.
What I still don't understand is how to connect each timer to its update
function and keep everything on the screen. I have a timer that rotates
the disc and a timer that shoots the ball. Are these functions declared
outside of main and the update functions declared inside main?
I don't know how this is done. I forgot to tell you I am using the space
bar to shoot the ball.

Thanks

DanielH
Member #934
January 2001
avatar

The event variable gives you the timer that triggered the event. Use that to determine which update is needed.

That being said, you don't need a timer for each object. You really just need one timer and update all objects when triggered.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

An example of what DanielH and I are saying :

#SelectExpand
1 2double FPS = 60; 3double SPF = 1.0/FPS; 4ALLEGRO_TIMER* mtimer = al_create_timer(SPF);/// Or as fast as you need for more precision 5 6/// Vary the tick rate here for the disc and the ball 7double bticks = 0.0; 8double dticks = 0.0; 9/// Next we have tick rates for the individual counters 10const double BTICKRATE = 0.5;/// Tick half as fast as master timer 11const double DTICKRATE = 1.0;/// Tick as fast as the master timer 12 13if (ev.type == ALLEGRO_EVENT_TIMER && ev.timer.source == mtimer) { 14 /// Our master timer ticked, add partial or whole ticks to the counters 15 bticks += BTICKRATE*SPF; 16 dticks += DTICKRATE*SPF; 17}

Scooter
Member #16,799
January 2018

Hi Daniel and Edgar:

#SelectExpand
1 2 this of course using two timers 3 code works perfect by themselves, NOT TOGETHER 4 problem is how these should interact with only one timer 5 operating at two different speeds 6 7 // this rotates the disc 8 if(ev.type == ALLEGRO_EVENT_TIMER) 9 { 10 if(ev.timer.source == disc_timer && start == true) 11 { 12 double angleX = (angle * PI) / 180.0; //convert angle to radians 13 al_clear_to_color(al_map_rgb(20, 20, 20)); 14 al_draw_scaled_rotated_bitmap(image, 40, 40, 637, 170, 1, 1, -angleX, 0); 15 al_draw_bitmap(image2, 500, 727, 0); 16 al_draw_bitmap(image3, 383, 20, 0); 17 al_draw_bitmap(image4, 582, 495, 0); 18 al_flip_display(); 19 update_angle(angle); 20 } 21 } 22 23 // this shoots the ball 24 if (ev.type == ALLEGRO_EVENT_TIMER) 25 { 26 if(al_key_down(&keyState, ALLEGRO_KEY_SPACE)) 27 { 28 ball_x = 638; 29 ball_y = 524; 30 31 for(i = 0; i < 45; i++) 32 { 33 al_clear_to_color(al_map_rgb(0,0,0)); 34 al_draw_bitmap(image2, 500, 727, 0); 35 al_draw_bitmap(image3, 383, 20, 0); 36 al_draw_bitmap(image4, 582, 495, 0); 37 al_draw_filled_circle(ball_x, ball_y, ball_dia, al_map_rgb(255, 0, 0)); 38 al_flip_display(); 39 update(10); 40 } 41 } 42 } 43 44 45 // these are for the updates 46 double update_angle() // update rotating disc 47 { 48 angle += 2.0; 49 if(angle >= 360) angle = 2.0; 50 } 51 52 int update(int value) // update shooting the ball 53 { 54 ball_y -= value; 55 }

DanielH
Member #934
January 2001
avatar

Just a suggestion, but input, logic and drawing should ALL be separated.

1. process input
2. process logic
3. process drawing

What are the speeds of your timers, can't you adjust to use one? Or adjust ball velocity to match the speed of one timer.

#SelectExpand
1int logic_counter = 0; 2 3void main_loop() 4{ 5 while (true) 6 { 7 if (process_input() < 0) break; 8 9 while (logic_counter > 0) 10 { 11 process_input(); 12 --logic_counter; 13 } 14 15 process_drawing(); 16 } 17} 18 19int process_input() 20{ 21/// get event info 22 if (ev.type == ALLEGRO_EVENT_TIMER) ++logic_counter; 23 if (ev.type == ALLEGRO_EVENT_KEYBOARD && ev.keycode == ALLEGRO_KEY_ESCAPE) return -1; 24 25 return 0; 26} 27 28 29void process_logic() 30{ 31} 32 33void process_drawing() 34{ 35}

torhu
Member #2,727
September 2002
avatar

You have to check which timer it is in both cases:

 // this shoots the ball
if (ev.type == ALLEGRO_EVENT_TIMER && ev.timer.source == ball_timer)

Scooter
Member #16,799
January 2018

Edgar:
Here is what I have now. I think everything is here. I have no
idea how the timing flows in the program. I wanted to upload all
the bitmaps but never found a way to upload the zip file. I wanted
you to look at my file and tell me where the timing should be placed.
No hurry, just when you have the time. Thanks!

#SelectExpand
1 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_primitives.h> 4#include <allegro5/allegro_image.h> 5#include <stdio.h> 6#include <stdlib.h> 7#include <allegro5/allegro_font.h> 8#include <allegro5/allegro_ttf.h> 9#include <math.h> 10#include <time.h> 11#include <stdbool.h> 12 13#define PI 3.1415927 14 15float screen_width = 1280; 16float screen_height = 750; 17 18float image_height; 19float image_width; 20 21int i; 22 23bool done = false; 24bool draw = false; 25bool start = false; 26 27//double FPS = 60.0; 28double SPF = 1.0/60.0; 29double bticks = 0.0; 30double dticks = 0.0; 31const double BTICKRATE = 0.5;/// Tick half as fast as master timer 32const double DTICKRATE = 1.0;/// Tick as fast as the master timer 33 34float ball_x = 636; 35float ball_y = 588; 36int ball_dia = 6; 37 38float new_x, new_y; 39int pos_x, pos_y; 40double angle = 2.0; 41double angleX; 42 43int i; 44int speed; 45 46int update(int value); 47double update_angle(); 48 49int main() 50 { 51 ALLEGRO_DISPLAY *display = NULL; 52 ALLEGRO_BITMAP *image = NULL; 53 ALLEGRO_BITMAP *image2 = NULL; 54 ALLEGRO_BITMAP *image3 = NULL; 55 ALLEGRO_BITMAP *image4 = NULL; 56 ALLEGRO_TIMER *timer; 57 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 58 59 if(!al_init()) 60 { 61 fprintf(stderr,"Couldn't initialize allegro!\n"); 62 return -1; 63 } 64 65 if(!al_install_mouse()) 66 { 67 fprintf(stderr, "failed to initialize the mouse!\n"); 68 return -1; 69 } 70 71 if(!al_init_primitives_addon()) 72 { 73 fprintf(stderr,"Couldn't initialize primitives addon!\n"); 74 return -1; 75 } 76 77 if(!al_install_mouse()) 78 { 79 fprintf(stderr, "failed to initialize the mouse!\n"); 80 return -1; 81 } 82 83 display = al_create_display(screen_width, screen_height); 84 85 if(!display) 86 { 87 fprintf(stderr,"Couldn't create allegro display!\n"); 88 return -1; 89 } 90 91 if(!al_init_image_addon()) 92 { 93 fprintf(stderr,"Couldn't display image!\n"); 94 return -1; 95 } 96 97 al_install_keyboard(); 98 99 al_init_font_addon(); 100 al_init_ttf_addon(); 101 102 timer = al_create_timer(1.0 / 60); 103 104 event_queue = al_create_event_queue(); 105 106 al_register_event_source(event_queue, al_get_display_event_source(display)); 107 al_register_event_source(event_queue, al_get_mouse_event_source());; 108 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 109 al_register_event_source(event_queue, al_get_keyboard_event_source()); 110 111 image = al_load_bitmap("disc.png"); 112 // al_draw_bitmap(image, 637, 170, 0); 113 114 image2 = al_load_bitmap("menu.png"); 115 al_draw_bitmap(image2, 500, 727, 0); 116 image3 = al_load_bitmap("new_frame.png"); 117 al_draw_bitmap(image3, 383, 20, 0); 118 image4 = al_load_bitmap("ship.png"); 119 al_draw_bitmap(image4, 582, 495, 0); 120 // al_draw_line(637, 50, 637, 710, al_map_rgb(255, 0, 0), 1); 121 122 al_flip_display(); 123 124 if(!image) 125 { 126 fprintf(stderr,"Couldn't display image!\n"); 127 return -1; 128 } 129 130 ALLEGRO_KEYBOARD_STATE keyState; 131 al_start_timer(timer); 132 done = false; 133 134 while(!done) 135 { 136 ALLEGRO_EVENT ev; 137 al_wait_for_event(event_queue, &ev); 138 al_get_keyboard_state(&keyState); 139 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 140 { 141 done = true; 142 } 143 144 if (ev.type == ALLEGRO_EVENT_TIMER && ev.timer.source == timer) 145 { 146 /// Our master timer ticked, add partial or whole ticks to the counters 147 bticks += BTICKRATE*SPF; 148 dticks += DTICKRATE*SPF; 149 } 150 151 152 if(ev.type == ALLEGRO_EVENT_TIMER && start == true) 153 { 154 if(ev.timer.source == timer) 155 { 156 float angleX = (angle * PI) / 180.0; //convert angle to radians 157 al_clear_to_color(al_map_rgb(20, 20, 20)); 158 al_draw_rotated_bitmap(image, 40, 40, 637, 170, -angleX, 0); 159 al_draw_bitmap(image2, 500, 727, 0); 160 al_draw_bitmap(image3, 383, 20, 0); 161 al_draw_bitmap(image4, 582, 495, 0); 162 al_flip_display(); 163 angle += 2.0; 164 if(angle >= 360) angle = 2.0; 165 } 166 } 167 168 if (ev.type == ALLEGRO_EVENT_TIMER && start == true) 169 { 170 if(al_key_down(&keyState, ALLEGRO_KEY_SPACE)) 171 { 172 ball_x = 638; 173 ball_y = 524; 174 175 for(i = 0; i < 60; i++) 176 { 177 al_clear_to_color(al_map_rgb(0,0,0)); 178 al_draw_bitmap(image2, 500, 727, 0); 179 al_draw_bitmap(image3, 383, 20, 0); 180 al_draw_bitmap(image4, 582, 495, 0); 181 al_draw_filled_circle(ball_x, ball_y, ball_dia, al_map_rgb(255, 0, 0)); 182 al_flip_display(); 183 update(10); 184 } 185 } 186 } 187 188 if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) 189 { 190 if( ev.mouse.button == 1) 191 { 192 pos_x = ev.mouse.x; 193 pos_y = ev.mouse.y; 194 195 if ((pos_x > 727 && pos_x < 765) && (pos_y > 727 && pos_y < 750)) // EXIT 196 { 197 start = false; 198 draw = false; 199 done = true; 200 break; 201 } 202 203 if ((pos_x > 510 && pos_x < 565) && (pos_y > 727 && pos_y < 750)) // START 204 { 205 start = true; 206 draw = true; 207 } 208 209 } 210 } 211 212 } 213 214 al_destroy_display(display); 215 al_destroy_bitmap(image); 216 al_destroy_bitmap(image2); 217 al_destroy_bitmap(image3); 218 al_destroy_timer(timer); 219 al_destroy_event_queue(event_queue); 220 221 return 0; 222 } 223 224double update_angle() // update rotating disc 225 { 226 angle += 2.0; 227 if(angle >= 360) angle = 2.0; 228 } 229 230int update(int value) // update shooting the ball 231 { 232 ball_y -= value; 233 }

DanielH
Member #934
January 2001
avatar

Oh, where to start?

You only have one timer now. You won't need to check if the timer source matches anymore.

You can also consolidate it all under one allegro_event_timer if statement

#SelectExpand
1if (ev.type == ALLEGRO_EVENT_TIMER) 2{ 3 /// Our master timer ticked, add partial or whole ticks to the counters 4 bticks += BTICKRATE*SPF; 5 dticks += DTICKRATE*SPF; 6 7 if(start == true) 8 { 9 float angleX = (angle * PI) / 180.0; //convert angle to radians 10 al_clear_to_color(al_map_rgb(20, 20, 20)); 11 al_draw_rotated_bitmap(image, 40, 40, 637, 170, -angleX, 0); 12 al_draw_bitmap(image2, 500, 727, 0); 13 al_draw_bitmap(image3, 383, 20, 0); 14 al_draw_bitmap(image4, 582, 495, 0); 15 al_flip_display(); 16 angle += 2.0; 17 if(angle >= 360) angle = 2.0; 18 19 if(al_key_down(&keyState, ALLEGRO_KEY_SPACE)) 20 { 21 ball_x = 638; 22 ball_y = 524; 23 24 for(i = 0; i < 60; i++) 25 { 26 al_clear_to_color(al_map_rgb(0,0,0)); 27 al_draw_bitmap(image2, 500, 727, 0); 28 al_draw_bitmap(image3, 383, 20, 0); 29 al_draw_bitmap(image4, 582, 495, 0); 30 al_draw_filled_circle(ball_x, ball_y, ball_dia, al_map_rgb(255, 0, 0)); 31 al_flip_display(); 32 update(10); 33 } 34 } 35 } 36} 37}

Why are you doing this 60 times?

                for(i = 0; i < 60; i++)
                {
                    al_clear_to_color(al_map_rgb(0,0,0));
                    al_draw_bitmap(image2, 500, 727, 0);
                    al_draw_bitmap(image3, 383, 20, 0);
                    al_draw_bitmap(image4, 582, 495, 0);
                    al_draw_filled_circle(ball_x, ball_y, ball_dia, al_map_rgb(255, 0, 0));
                    al_flip_display();
                    update(10);
                }

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Scooter
Member #16,799
January 2018

Hi Daniel:
I tried what you posted and I still have the same problem.
The disc disappears while the ball is moving. I am not sure,
but I think this is something I have already tried before.
Any yes, Edgar is right. This gave me more control of the ball,
mainly to be sure it stopped moving.
Please take another look to see what is wrong.

Thanks guys!!!!!!!!!

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You can do animation this way, but be aware it is blocking your program from getting input. You need to draw the disc in the same section of code you draw your ball. That's why it disappears. Track the state of the 'start' variable. bticks and dticks do no good if you don't use them. You need variables to track the accumulated time. Then check if one of the variables has ticked or not.

What you should try to achieve is freeing your logic from drawing. Always draw the whole screen, based on what is visible. And use your logic to determine what is where and when.

Hope this helps.

Go to: