allegro 5 performing events at a certain interval - c++

I'm making my first game in allegro 5, it's a snake game. In order to move the snake game I'd want to use a squared grid which I made, so the snake moves at regular intervals.
How can I use timers to make an event happen at a certain amount of time?
For example, I want my snake to move every second in the direction set, I know how to control him but I don't know how to create an event which happens at a certain interval. I'm using Codeblocks IDE with Windows XP SP3

Most people who create games with Allegro used a fixed interval timing system. This means X times per second (often 60 or 100), you process input and run a logic cycle. Then, if you have time left over, you draw a frame of graphics.
To create a timer that ticks at 60 FPS and register it with an event queue:
ALLEGRO_TIMER *timer = al_create_timer(1 / 60.0);
ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
al_register_event_source(queue, al_get_timer_event_source(timer));
Now somewhere in your main event loop:
al_start_timer(timer);
while (playingGame)
{
bool draw_gfx = false;
do
{
ALLEGRO_EVENT event;
al_wait_for_event(queue, &event);
if (event.type == ALLEGRO_EVENT_TIMER)
{
do_logic();
draw_gfx = true;
}
else if (event.type == ... )
{
// process keyboard input, mouse input, whatever
// this could change the direction the snake is facing
}
}
while (!al_is_event_queue_empty(queue));
if (draw_gfx)
{
do_gfx();
draw_gfx = false;
}
}
So now in do_logic(), you can move your snake one unit in the direction it is facing. This means it would move 60 units per second. You can use fractional units if you need more granularity.
You may want to take a look at some of the demos that come with Allegro, as they have full featured event loops. It's too much to include as a single SO answer.

Related

SDL2 "skip" frames when mouse no moving

I'm trying to make some animation with SDL2.
SDL2 has some bad performance, and my simple chess game was running at 10fps.
I don't want to redraw the whole screen every frames, it takes way to long. So in order to optimize my game I decided to code an Animation class ( a simple fade in/out effect) which only redraw some part of the screen everyframe (basicly redraw the selected piece)
void myGame::sdlLoop() {
SDL_Event events;
bool quit = false;
while (!quit) {
bool redraw = false; //We assume we don't want to redraw everything (yet)
while (SDL_PollEvent(&events)) {
switch (events.key.keysym.scancode) {
....
}
if(redraw) draw(); // Only redraw whole screen IF NEEDED
else drawAnimations(); // Better use that for better performance
}
}
}
void myGame::drawAnimations(){
int i = 0;
while(i < arr.size()){
....
drawThingsAtCertainsPixels(now_time, animation_start_time, animation_duration); //Basicly a simple fade effect, something like
//pixelColor = color1 * advancement + color2 * (1 - advancement)
}
// Show the window
SDL_RenderPresent( m_renderer );
}
So far so good, but I noticed a weird behavior.
The animation is "jerky", most of the frames are skipped
I ended up avec all of my fadeout unfinished because the last frame where skipped.
But, when I constantly move the mouse, everything goes right and no frame are dropped
I think it is linked to SDL wanting to optimize performance, and only run at 100% speed when someting important is going on (user inputting things or windows interacted).
Do you know why is this happening, and how to fix that ?
I mean how to have SDL2 computing every frame even if I don't move the mouse.
I feel a bit guilty for finding the solution right after posting this question (but I swear I tore my hair out a lot)
The solution is quite simple
while (!quit) {
bool redraw = false; //We assume we don't want to redraw everything (yet)
while (SDL_PollEvent(&events)) {
switch (events.key.keysym.scancode) {
....
}
if(redraw) draw(); // Only redraw whole screen IF NEEDED
else drawAnimation(); // Better use that for better performance
}
}
Just move the drawAnimations() function a bit lower, out of the while (SDL_PollEvent(&events)) {
while (!quit) {
bool redraw = false; //We assume we don't want to redraw everything (yet)
while (SDL_PollEvent(&events)) {
switch (events.key.keysym.scancode) {
....
}
}
if(redraw) draw(); // Only redraw whole screen IF NEEDED
else drawAnimation(); // Better use that for better performance
}

SFML 2.1 Full Explanation of using Vectors to create multiple Sprites

I am using SFML 2.1 in Code Blocks and I can't figure out how to use Vectors to make clones of my asteroid sprite. It keeps saying that asteroid_V hasn't been declared, and a warning box pops up saying it is "using characters that are illegal in the selected coding" and that they "were changed to protect [me] from losing data".
The objective of this program is to continuously create asteroid sprites that will spawn at random points above the screen before dropping straight down. There were other sprites and aspects in the program but I removed them from this post to properly condense it. This appears to be the only problem after all.
int n;
int main()
{
RenderWindow window;
window.setFramerateLimit(30);
RenderWindow mainMenu;
srand( time(0));
Texture asteroid_Pic;
asteroid_Pic.loadFromFile("Asteroid.png");
std::vector<sf::Sprite> asteroid(n, Sprite(asteroid_Pic));
for (int i = 0; i < asteroid.size(); i++){
asteroid[n].setOrigin(15, 15);
asteroid[n].getPosition();
asteroid[n].setPosition(x = rand() % 790 + 10, y = rand() % -10 - 50);
}
// run the program as long as the window is open
while (window.isOpen())
{
// check all the window's events that were triggered since the last iteration of the loop
Event event;
while (window.pollEvent(event))
{
// "close requested" event: we close the window
if (event.type == Event::Closed){
window.close();
}
asteroid[n].setPosition(x, y+=1);
asteroid[n].rotate(1);
// clear the window with black color
window.clear(Color::Black);
// draw everything here...
// window.draw(...);
window.draw(player1);
window.draw(asteroid[n]);
// end the current frame
window.display();
}
return 0;
}
You have another while (window.isOpen()) inside your main loop. Your program will enter the main loop and then never get out of that inner loop. It will never get to drawing at least once.
You need to get rid of the inner while (window.isOpen()) loop and find another way.
Although the original question was about timers, you can find a basic explanation of a game loop here. You have to handle time in you loop if you want to do something (move sprites, create new ingame entities) based on time.

bullet movement SDL/c++

I want a bullet to move when I click Space. First the bullet image is blitted when space is pressed, at the same time a timer starts and when it reaches 5000 ms ticks the x-value of the image should change. This is my code:
SDL_Rect bulletRect;
bulletRect.x = dstX+31; //dstX/Y is the source destination of another image where the bullet should be drawn
bulletRect.y = dstY+10.5;
SDL_Surface *bullet = IMG_Load(bullet.png");
if (drawBullet) //bool set to true in the space key event.
{
SDL_BlitSurface(bullet, NULL, screen, &bulletRect);
//timer
my_timer.start(); //starts the timer
if (SDL_GetTicks() == 5000) //if 5 sec
{
bulletRect.x += 10;
}
}
The image is only blitted but nothing happens after 5 sec. What is wrong?
Your conditional statement
if (SDL_GetTicks() == 5000) //if 5 sec
{
bulletRect.x += 10;
}
is inside the statement
if (drawBullet) //bool set to true in the space key event
which means you only check the timer once when the spacebar is pressed. Move this outside the if(drawBullet)
You should have SDL_GetTicks() >= 5000, instead of checking for ==5000, otherwise you'll only enter the condition if you happen to hit 5000 by pure luck.
from SDL's documentation, SDL_GetTicks function: Returns the number of milliseconds since SDL library initialization. This value wraps around if the program runs for more than 49.7 days
so if you're checking that it's been 5 seconds since it moved last (not sure what else you could be trying to do here) you want to store the current number of ticks and use that to compare against during the next loop (check that the difference between previous and current is > 5000)

how should i use glutPostRedisplay in a loop to call display multiple times when an event occures?

i am new to opengl.
i want to draw my scene a few times when the user presses some key, i have called glutPostRedisplay in a for loop when the key is pressed but it just redraws my scene one time. how should i handle this problem?
First off, glutPostRedisplay is a function that belongs to GLUT, which is not part of OpenGL but a 3rd party library/framework. There are other frameworks, or you can do everything from scratch (heck, I just remembered, that when I began learning OpenGL some 14 years ago, GLUT won't properly work for me, so I did write my framework from scratch then).
i want to draw my scene a few times when the user presses some key
Never mix drawing and animation logic with event processing. If the user pressed a key that triggers some animation, set a flag (=some variable), that the animation should be played and then iterate through the animation in your render/animation loop.
i have called glutPostRedisplay in a for loop when the key is pressed but it just redraws my scene one time
glutPostRedisplay won't trigger a redraw immediately. It sets a flags, that the GLUT message loop shouls issue a redraw instead of going idle after all message processing. Of course this flag doesn't accumulate.
So here's a layout using GLUT. Unfortunately GLUT is subobtimal for this kind of things, because it doesn't give you control over the event loop, which makes precise timing cumbersome to achieve.
time_t rendertimer;
void stopwatch(time_t); // some external helper function that reports time between calls
typedef enum {stop, play} animstate;
struct animation {
float time;
float duration;
animstate state;
};
animation animations[...];
void keyboard(key, x, y)
{
if(key == ...) {
animations[0].time = 0;
animations[0].state = play;
}
glutPostRedisplay();
}
void idle()
{
float deltaT = stopwatch(rendertimer);
if( animation[...].state == play ) {
animation[...].time += deltaT;
if( animation[...].duration <= animation[...].time ) {
animation[...].state = stop;
}
}
glutPostRedisplay();
}
void display()
{
draw_objects_according_to_animation();
}

How to programmatically move a window slowly, as if the user were doing it?

I am aware of the MoveWindow() and SetWindowPos() functions. I know how to use them correctly. However, what I am trying to accomplish is move a window slowly and smoothly as if a user is dragging it.
I have yet to get this to work correctly. What I tried was getting the current coordinates with GetWindowRect() and then using the setwindow and movewindow functions, incrementing Right by 10 pixels each call.
Any ideas?
Here is what I had beside all my definitions.
while(1)
{
GetWindowRect(notepad,&window);
Sleep(1000);
SetWindowPos(
notepad,
HWND_TOPMOST,
window.top - 10,
window.right,
400,
400,
TRUE
);
}
If you want smooth animation, you'll need to make it time-based, and allow Windows to process messages in between movements. Set a timer, and respond to WM_TIMER notifications by moving the window a distance based on the elapsed time since your animation started. For natural-looking movement, don't use a linear function for determining the distance - instead, try something like Robert Harvey's suggested function.
Pseudocode:
//
// animate as a function of time - could use something else, but time is nice.
lengthInMS = 10*1000; // ten second animation length
StartAnimation(desiredPos)
{
originalPos = GetWindowPos();
startTime = GetTickCount();
// omitted: hwnd, ID - you'll call SetTimer differently
// based on whether or not you have a window of your own
timerID = SetTimer(30, callback);
}
callback()
{
elapsed = GetTickCount()-startTime;
if ( elapsed >= lengthInMS )
{
// done - move to destination and stop animation timer.
MoveWindow(desiredPos);
KillTimer(timerID);
}
// convert elapsed time into a value between 0 and 1
pos = elapsed / lengthInMS;
// use Harvey's function to provide smooth movement between original
// and desired position
newPos.x = originalPos.x*(1-SmoothMoveELX(pos))
+ desiredPos.x*SmoothMoveELX(pos);
newPos.y = originalPos.y*(1-SmoothMoveELX(pos))
+ desiredPos.y*SmoothMoveELX(pos);
MoveWindow(newPos);
}
I found this code which should do what you want. It's in c#, but you should be able to adapt it:
increment a variable between 0 and 1 (lets call it "inc" and make it global) using small increments (.03?) and use the function below to give a smooth motion.
Math goes like this:
currentx=x1*(1-smoothmmoveELX(inc)) + x2*smoothmmoveELX(inc)
currenty=y1*(1-smoothmmoveELX(inc)) + y2*smoothmmoveELX(inc)
Code:
public double SmoothMoveELX(double x)
{
double PI = Atn(1) * 4;
return (Cos((1 - x) * PI) + 1) / 2;
}
http://www.vbforums.com/showthread.php?t=568889
A naturally-moving window would accelerate as it started moving, and decelerate as it stopped. The speed vs. time graph would look like a bell curve, or maybe the top of a triangle wave. The triangle wave would be easier to implement.
As you move the box, you need to steadily increase the number of pixels you are moving the box each time through the loop, until you reach the halfway point between point a and point b, at which you will steadily decrease the number of pixels you are moving the box by. There is no special math involved; it is just addition and subtraction.
If you are bored enough, you can do loopback VNC to drag the mouse yourself.
Now, as for why you would want to I don't know.