Animate surface in SDL/SDL_gfx library - c

I'm recreating the game 'super hexagon' in c using sdl2 library.
I have drawn the circle in the middle of the application and the little cursor(not the mouse but the triangle around the circle) that is supposed to move around it when the player interact with the keyboard (left and right keys) like so:
void Game_run(struct Game *game)
{
//Previous rendering are cleared.
SDL_RenderClear(game->renderer);
//-------------------------------------------------------
if (filledCircleRGBA(game->renderer,SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 10,255, 255, 255, 255) != 0)
{
fprintf(stderr, "Error: the circle was not rendered\n");
SDL_DestroyRenderer(game->renderer);
}
arcRGBA( game->renderer, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, 100, 0, 80, 255, 255, 255, 255 );
filledTrigonRGBA (game->renderer, CURSOR_POSITION_X-10, CURSOR_POSITION_Y, CURSOR_POSITION_X+10, CURSOR_POSITION_Y, CURSOR_POSITION_X, CURSOR_POSITION_Y+10, 255, 255, 255, 255);
SDL_RenderPresent(game->renderer);
//-------------------------------------------------------
//We are payng
game->state = PLAYING;
SDL_Event event;
SDL_bool GameRunning = SDL_TRUE;
while (GameRunning) //while the player didnt loose, the game is running
{
while (SDL_PollEvent(&event))
{
/* code */
switch (event.type)
{
//when a key is pressed
case SDL_KEYDOWN:
//Detecting the pressed key
switch (event.key.keysym.sym)
{
case SDLK_LEFT:
printf("Left key pressed\n");
break;
case SDLK_RIGHT:
printf("Right key pressed\n");
break;
default:
break;
}
break;
//when a key is unpressed
case SDL_KEYUP:
switch (event.key.keysym.sym)
{
case SDLK_LEFT:
printf("Left key up\n");
break;
case SDLK_RIGHT:
printf("Right key up\n");
break;
default:
break;
}
break;
//if the user quit the game
case SDL_QUIT:
//The game is over
GameRunning = SDL_FALSE;
game->state = GAME_OVER;
break;
default:
break;
}
}
}
}
I have already implemented the event listener to detect the user input.
But I have no idea how to animate those elements.
How should I approach the problem? I want to understand how animation works when i render elements using gfx functions..do i need to load the drawn elements into a SDL_Surface first?

Related

OpenGL using mouse for FPS Style movement

When i run my program and start moving mouse nothing really happens at all. I have wasd working fine but like mentioned am having problems with mouse movement.
I believe my issue is that it always resets to center but im not sure.
#define FPS 60
#define TO_RADIANS 3.14/180.0
float pitch = 0.0, yaw= 0.0;
float cX=0.0,cZ=0.0;
const int width = 16*50;
const int height = 9*50;
struct Motion
{
bool Forward,Backward,Left,Right;
}motion = {false,false,false,false};
void init()
{
glutSetCursor(GLUT_CURSOR_NONE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glutWarpPointer(width/2,height/2);
}
void camera()
{
if(motion.Forward)
{
cX += cos((yaw+90)*TO_RADIANS)/5.0;
cZ -= sin((yaw+90)*TO_RADIANS)/5.0;
}
if(motion.Backward)
{
cX += cos((yaw+90+180)*TO_RADIANS)/5.0;
cZ -= sin((yaw+90+180)*TO_RADIANS)/5.0;
}
if(motion.Left)
{
cX += cos((yaw+90+90)*TO_RADIANS)/5.0;
cZ -= sin((yaw+90+90)*TO_RADIANS)/5.0;
}
if(motion.Right)
{
cX += cos((yaw+90-90)*TO_RADIANS)/5.0;
cZ -= sin((yaw+90-90)*TO_RADIANS)/5.0;
}
/*limit the values of pitch
between -60 and 70
*/
if(pitch>=70)
pitch = 70;
if(pitch<=-60)
pitch=-60;
glRotatef(-pitch,1.0,0.0,0.0); // Along X axis
glRotatef(-yaw,0.0,1.0,0.0); //Along Y axis
glTranslatef(-cX,0.0,-cZ);
}
void timer()
{
glutPostRedisplay();
glutWarpPointer(width/2,height/2);
glutTimerFunc(1000/FPS,timer,0);
}
void keyboard(unsigned char key,int x,int y)
{
switch(key)
{
case 'W':
case 'w':
motion.Forward = true;
break;
case 'A':
case 'a':
motion.Left = true;
break;
case 'S':
case 's':
motion.Backward = true;
break;
case 'D':
case 'd':
motion.Right = true;
break;
}
}
void keyboard_up(unsigned char key,int x,int y)
{
switch(key)
{
case 'W':
case 'w':
motion.Forward = false;
break;
case 'A':
case 'a':
motion.Left = false;
break;
case 'S':
case 's':
motion.Backward = false;
break;
case 'D':
case 'd':
motion.Right = false;
break;
}
}
int main(int argc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(width, height);
glutCreateWindow("Jameson Marzak FPS");
glutFullScreen();
sky[0] = LoadTexBMP("sky0.bmp");
sky[1] = LoadTexBMP("sky1.bmp");
sky[2] = LoadTexBMP("grass.bmp");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
//glutPassiveMotionFunc(passive_motion);
glutTimerFunc(0,timer,0); //more info about this is given below at definition of timer()
glutKeyboardFunc(keyboard);
glutKeyboardUpFunc(keyboard_up);
glutMainLoop();
return 0;
}
You need to set up a callback with glut to handle mouse inputs:
glutMouseFunc
then, figure out how to calculate the proper yaw/pitch from the mouse x and mouse y that glut will call your callback with

How do I enable SDL2 to allow all key_down events and not just the quit event?

My SDL Window displays a bitmap on top of another bitmap however I am not able to control the bitmap image using SDL_KeyDown events. The only event that works is SDL_QUIT.
I attempted to map using the ASWD keys and the Up Down Left and Right arrow keys, however the SDL Window doesn't process any of those events. The only event that occurs is when I click the X button to close the window or when I press the q or escape keys to close the window. Also, none of the printf statements are appearing on the console so I am not sure exactly where the problem is because the program compiles and runs without any errors.
I am using C not C++
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_timer.h>
#include <SDL_image.h>
#define WINDOW_WIDTH (640)
#define WINDOW_HEIGHT (480)
// Speed in Pixels/Seconds
#define SCROLL_SPEED (300)
// Spirte Size
#define SPRITE_SIZE 32
int main(int argc, const char * argv[]) {
// Attempt to initialize graphics library
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
return 1;
}
//Initialize Key Variables
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Surface *windowSurface = NULL;
SDL_Surface *imageSurface = NULL;
// Creating Surfaces and Addresses
SDL_Surface *temp = NULL;
SDL_Surface *sprite = NULL;
// set sprite position
SDL_Rect dstSprite = {0, 0, 32, 32};
// Attempt to create SDL Window
window = SDL_CreateWindow("Atari Lunar Lander", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, 0);
// Print an Error if the window fails to initialize
if (window == NULL) {
printf("Could not create window: %s\n", SDL_GetError());
return 1;
}
// Create The Title of the Window
SDL_SetWindowTitle(window, "Atari Lunar Lander");
// Create SDL Render Window
Uint32 render_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE;
renderer = SDL_CreateRenderer(window, -1, render_flags);
// if rendering the window fails
if (!renderer) {
printf("error creating render: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
windowSurface = SDL_GetWindowSurface(window);
// Load A bitmap image as an Surface
windowSurface = SDL_LoadBMP("/Users/jeremiahonwubuya/Desktop/AtariLunarLander/outerspace.bmp");
if (!windowSurface) {
printf("error creating surface: %s\n", SDL_GetError());
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
//Load Image data into graphics hardware memory
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, windowSurface);
if (!texture) {
printf("error creating texture: %s\n", SDL_GetError());
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// load bitmap image into an SDL_Surface "temp" and store "temp" into the SDL_Surface "sprite" that is optimized for Blitting
temp = SDL_LoadBMP("/Users/jeremiahonwubuya/Desktop/AtariLunarLander/player.bmp");
sprite = SDL_ConvertSurface(temp, temp->format, 0);
SDL_FreeSurface(temp);
SDL_Texture *playerTexture = SDL_CreateTextureFromSurface(renderer, sprite);
if (!sprite) {
printf("error creating sprite: %s\n", SDL_GetError());
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
// updating the Window Surface to be the BitMap Image
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderCopy(renderer, playerTexture, NULL, &dstSprite);
SDL_RenderPresent(renderer);
bool isRunning = true;
SDL_Event event;
while (isRunning) {
while (SDL_PollEvent(&event) != 0 ) {
if (event.type == SDL_QUIT) {
// close button clicked
isRunning = false;
break;
}
if (event.type == SDL_KEYDOWN) {
// close program upon buttons pressed
switch(event.key.keysym.sym){
case SDLK_q:
printf("program stopped");
isRunning = false;
break;
case SDLK_ESCAPE:
printf("programm stopped");
isRunning = false;
break;
}
// Animating the Sprite
if (event.key.keysym.sym == SDLK_a || event.key.keysym.sym == SDLK_LEFT) {
dstSprite.x -= 5;
dstSprite.w = 32;
dstSprite.h = 32;
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderCopy(renderer, playerTexture, NULL, &dstSprite);
SDL_RenderPresent(renderer);
printf("sprite moved leftt to position %d \n", dstSprite.x);
}
if (event.key.keysym.sym == SDLK_d || event.key.keysym.sym == SDLK_RIGHT) {
dstSprite.x += 5;
dstSprite.w = 32;
dstSprite.h = 32;
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderCopy(renderer, playerTexture, NULL, &dstSprite);
SDL_RenderPresent(renderer);
printf("sprite moved right to position %d \n", dstSprite.x);
}
if (event.key.keysym.sym == SDLK_w || event.key.keysym.sym == SDLK_UP) {
dstSprite.y -= 5;
dstSprite.w = 32;
dstSprite.h = 32;
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderCopy(renderer, playerTexture, NULL, &dstSprite);
SDL_RenderPresent(renderer);
printf("sprite moved up to position %d \n", dstSprite.y);
}
if (event.key.keysym.sym == SDLK_s || event.key.keysym.sym == SDLK_DOWN) {
dstSprite.y += 5;
dstSprite.w = 32;
dstSprite.h = 32;
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderCopy(renderer, playerTexture, NULL, &dstSprite);
SDL_RenderPresent(renderer);
printf("sprite moved down to position %d \n", dstSprite.y);
}
}
// Prevent Sprite from colliding with the edges of the screen
if ( dstSprite.x < 0 ) {
dstSprite.x = 0;
}
else if ( dstSprite.x > WINDOW_WIDTH-SPRITE_SIZE ) {
dstSprite.x = WINDOW_WIDTH-SPRITE_SIZE;
}
if ( dstSprite.y < 0 ) {
dstSprite.y = 0;
}
else if ( dstSprite.y > WINDOW_HEIGHT-SPRITE_SIZE ) {
dstSprite.y = WINDOW_HEIGHT-SPRITE_SIZE;
}
// Draw the Sprite
SDL_BlitSurface(sprite, NULL, windowSurface, &dstSprite);
SDL_UpdateWindowSurface(window);
}
}
SDL_Delay(5000);
// Clean Up
// Free SDL Surfaces
SDL_FreeSurface(sprite);
sprite = NULL;
SDL_FreeSurface(windowSurface);
windowSurface = NULL;
SDL_FreeSurface(imageSurface);
imageSurface = NULL;
// Destroy Texture and Window
texture = NULL;
SDL_DestroyTexture(texture);
playerTexture = NULL;
SDL_DestroyTexture(playerTexture);
window = NULL;
SDL_DestroyWindow(window);
SDL_Quit();
}
Your OR'ing your cases thus producing different integers than what are in .sym. You should split your ORs and let them fallthrough or use an if condition. For example:
case SDLK_a:
case SDLK_LEFT:
printf("sprite moved leftt");
break;
case SDLK_d:
case SDLK_RIGHT:
printf("sprite moved right");
break;
case SDLK_w:
case SDLK_UP:
printf("sprite moved up");
break;
case SDLK_s:
case SDLK_DOWN:
printf("sprite moved down");
break;
Or
if (event.key.keysym.sym == SDLK_a || event.key.keysym.sym == SDLK_LEFT)
// do something..
So a few things, first your code is "working", I get printed the text out when I press the correct keys but you have another error, those breaks in the ifs are making you skip the bliting section, remember that breaks break the execution flow in switch, for, and while loops, you don't need them on ifs.
Also If you press a key and then don't press anything you should be getting your screen updated. I tested with this program. Tell me if it is receiving your keys..
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
SDL_Init(SDL_INIT_VIDEO);
bool isRunning = true;
SDL_Event event;
SDL_Rect dstSprite = {0, 0, 0, 0};
while (isRunning) {
while (SDL_PollEvent(&event) != 0) {
if (event.type == SDL_QUIT) {
// close button clicked
isRunning = false;
break;
}
if (event.type == SDL_KEYDOWN) {
// close program upon buttons pressed
switch (event.key.keysym.sym) {
case SDLK_q:
printf("program stopped");
isRunning = false;
break;
case SDLK_ESCAPE:
printf("programm stopped");
isRunning = false;
break;
}
// Animating the Sprite
if (event.key.keysym.sym == SDLK_a ||
event.key.keysym.sym == SDLK_LEFT) {
dstSprite.x -= 5;
printf("sprite moved leftt to position %d \n", dstSprite.x);
break;
}
if (event.key.keysym.sym == SDLK_d ||
event.key.keysym.sym == SDLK_RIGHT) {
dstSprite.x += 5;
printf("sprite moved right to position %d \n", dstSprite.x);
break;
}
if (event.key.keysym.sym == SDLK_w ||
event.key.keysym.sym == SDLK_UP) {
dstSprite.y -= 5;
printf("sprite moved up to position %d \n", dstSprite.y);
break;
}
if (event.key.keysym.sym == SDLK_s ||
event.key.keysym.sym == SDLK_DOWN) {
dstSprite.y += 5;
printf("sprite moved down to position %d \n", dstSprite.y);
break;
}
}
printf("update graphics\n");
}
}
}

Creating a FIFO Queue with Keypad Inputs

I'm trying to implement a FIFO queue for keypad inputs but cannot seem to get it to work. I'm able to get the keypad inputs to appear on an LCD screen but that is all I'm able to do. I think the code is supposed to read a keypad input and push it into a queue, then pop the keypad input and read the value onto an LCD screen. Could anyone advise on why it doesn't display all the values I've pressed? Thank you.
#include "project.h"
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
// Keypad Variables
char KeyPad[4][4] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'},
};
char ReadKeyPad();
// FIFO Variables
struct FIFO {
char key;
struct FIFO *next;
};
struct FIFO KeyQueue[] = {
{0, &KeyQueue[1]}, //[0]
{0, &KeyQueue[2]}, //[1]
{0, &KeyQueue[3]}, //[2]
{0, &KeyQueue[4]}, //[3]
{0, &KeyQueue[5]}, //[4]
{0, &KeyQueue[6]}, //[5]
{0, &KeyQueue[7]}, //[6]
{0, &KeyQueue[8]}, //[7]
{0, &KeyQueue[0]} //[8]
};
struct FIFO *Head;
struct FIFO *Tail;
int KeyQueue_Size=0;
bool KeyQueue_IsEmpty();
bool KeyQueue_IsFull();
void KeyQueue_Push(char key);
char KeyQueue_Pop();
char ReadKeyPad();
int delay = 10;
int main(void)
{
Head = Tail = &KeyQueue[0];
char key;
CyGlobalIntEnable; /* Enable global interrupts. */
/* Place your initialization/startup code here (e.g. MyInst_Start()) */
LCD_Start();
LCD_ClearDisplay();
LCD_Enable();
for(;;)
{
/* Place your application code here. */
key = ReadKeyPad();
LCD_Position(1,8);
LCD_PutChar(key);
if (key !=0)
{
if (!KeyQueue_IsFull())
KeyQueue_Push(key);
}
//task for poping key
delay --;
if(delay <= 0 && !KeyQueue_IsEmpty())
{
KeyQueue_Pop();
switch (key)
{
case '1':
LCD_Position(0,1);
LCD_PrintString("You pressed 1");
break;
case '2':
LCD_Position(0,1);
LCD_PrintString("You pressed 2");
break;
case '3':
LCD_Position(0,1);
LCD_PrintString("You pressed 3");
break;
case '4':
LCD_Position(0,1);
LCD_PrintString("You pressed 4");
break;
case '5':
LCD_Position(0,1);
LCD_PrintString("You pressed 5");
break;
case '6':
LCD_Position(0,1);
LCD_PrintString("You pressed 6");
break;
case '7':
LCD_Position(0,1);
LCD_PrintString("You pressed 7");
break;
case '8':
LCD_Position(0,1);
LCD_PrintString("You pressed 8");
break;
case '9':
LCD_Position(0,1);
LCD_PrintString("You pressed 9");
break;
case 'A':
LCD_Position(0,1);
LCD_PrintString("You pressed A");
break;
case 'B':
LCD_Position(0,1);
LCD_PrintString("You pressed B");
break;
case 'C':
LCD_Position(0,1);
LCD_PrintString("You pressed C");
break;
case 'D':
LCD_Position(0,1);
LCD_PrintString("You pressed D");
break;
case '*':
LCD_Position(0,1);
LCD_PrintString("You pressed *");
break;
case '#':
LCD_Position(0,1);
LCD_PrintString("You pressed #");
break;
case '0':
LCD_Position(0,1);
LCD_PrintString("You pressed 0");
break;
delay = 10;
}
CyDelayUs(100);
}
}
}
bool KeyQueue_IsEmpty()
{
if(KeyQueue_Size == 0) return true;
return false;
}
bool KeyQueue_IsFull()
{
//if (Head == Tail) return truel
if(KeyQueue_Size ==9) return true;
return false;
}
void KeyQueue_Push(char key)
{
Head->key=key;
Head = Head->next;
KeyQueue_Size ++;
}
char KeyQueue_Pop()
{
char key;
key = Tail->key;
Tail = Tail->next;
KeyQueue_Size --;
return key;
}
char ReadKeyPad()
{
int i;
char key;
uint8_t col;
for (i=0; i<4; i++)
{
key = 0;
ROW_Write(1<<i);
col=COL_Read();
//LCD_Position(1,0);
//LCD_PrintNumber(key);
if (col & 0x01) key=KeyPad[i][0];
if (col & 0x02) key=KeyPad[i][1];
if (col & 0x04) key=KeyPad[i][2];
if (col & 0x08) key=KeyPad[i][3];
if (key != 0) break;
}
return key;
}
Some problems in your code:
As pointed before, delay = 10; is not well placed
key variable of main function is set only at the beginning of for loop.
So a corrected code could be:
for(;;)
{
key = ReadKeyPad();
LCD_Position(1,8);
LCD_PutChar(key);
if (key !=0)
{
if (!KeyQueue_IsFull())
KeyQueue_Push(key);
}
//task for poping key
delay --;
if(delay <= 0 && !KeyQueue_IsEmpty())
{
/* don't forget to store what have been poped from fifo */
key = KeyQueue_Pop();
switch (key)
{
case '1':
LCD_Position(0,1);
LCD_PrintString("You pressed 1");
delay = 10;
break;
case '2':
LCD_Position(0,1);
LCD_PrintString("You pressed 2");
delay = 10;
break;
/*
.
.
.
*/
case '0':
LCD_Position(0,1);
LCD_PrintString("You pressed 0");
delay = 10;
break;
}
CyDelayUs(100);
}
}
Maybe you can write it shorter:
for(;;)
{
key = ReadKeyPad();
LCD_Position(1,8);
LCD_PutChar(key);
if (key !=0)
{
if (!KeyQueue_IsFull())
KeyQueue_Push(key);
}
//task for poping key
delay --;
if(delay <= 0 && !KeyQueue_IsEmpty())
{
/* don't forget to store what have been poped from fifo */
key = KeyQueue_Pop();
/* print what have been pressed */
LCD_Position(0,1);
LCD_PrintString("You pressed ");
LCD_Position(0,12);
LCD_PutChar(key);
delay = 10;
CyDelayUs(100);
}
}

sdl getting continuously key pressing

I am currently programming a simple game in SDL (PONG clone) where i must have a continuously key pressing.
The problem I have is that when i press a button it reacts, waits a short period and then continues to continuously key pressing.
I wonder how i get that little delay to go away.
Here is my code:
while (running)
{
while (SDL_PollEvent(&event))
{
//update the game
if (event.type == SDL_QUIT)
{
quit_game();
running = false;
}
if(event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_DOWN:
move_paddle(UP);
break;
case SDLK_UP:
move_paddle(DOWN);
break;
default:
break;
}
}
}
draw_game();
move_ball();
SDL_Delay(15);
}
The first thing i did was i wanted to remove the small delay and get the movement of the paddle smoother. I introduced 2 new global bool variables to keep track on which key that was pressed down.
bool key_up = false;
bool key_down = false;
I initiate them with the value false because no key is currently pressed.
In my switch I set the value for these boolean variables to match what is currently pressed down.
if(event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_DOWN:
key_up = true;
key_down = false;
break;
case SDLK_UP:
key_down = true;
key_up = false;
break;
default:
break;
}
}
Then in the first while-loop i make two if-cases for the two keys that can be pressed and call the movement function in these if-cases.
if (key_up)
move_paddle(UP);
else if (key_down)
move_paddle(DOWN);
When i did this the delay disappeared and the paddle movement was smooth but it also generated another probelm, the paddle could not stay still in one place (except the boundraries). I then realised that the code is only looking for a key that is pressed down and does not react to a key that is released.
I then figured out that if a key is released (in this case the UP key or the DOWN key) the two boolean values had to be set to false because no key was pressed down.
What I did was that I made another if-statement after the if(event.type == SDL_KEYDOWN) that would disable the movement of the paddle if no key was pressed down.
if (event.type == SDL_KEYUP)
{
key_down = false;
key_up = false;
}
When I implemented all of this in my code the game worked like a charm.
For those who are interested, here is my new final code:
int gameloop()
{
SDL_Event event;
bool running = true;
bool key_up = false;
bool key_down = false;
while (running)
{
while (SDL_PollEvent(&event))
{
//update the game
if (event.type == SDL_QUIT)
{
quit_game();
running = false;
}
if(event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_DOWN:
key_up = true;
key_down = false;
break;
case SDLK_UP:
key_down = true;
key_up = false;
break;
default:
break;
}
}
if (event.type == SDL_KEYUP)
{
key_down = false;
key_up = false;
}
}
if (key_up)
move_paddle(UP);
else if (key_down)
move_paddle(DOWN);
move_ball();
ai_paddle_move();
draw_game();
printf("Player: %d | AI: %d\n", player, ai);
SDL_Delay(15);
}
return 1;
}

SDL - Why moving the mouse changes button state?

I'm having a problem with the Simple Directmedia Layer library. The following code draws a block on the screen when a mouse button is pressed:
SDL_Event event;
while(running){
while(SDL_PollEvent(&event)){
while(event.button.state == SDL_PRESSED){
SDL_PollEvent(&event);
//where to draw
boxRect.x = event.motion.x;
boxRect.y = event.motion.y;
//Draw to screen
SDL_FillRect(display,&boxRect,boxColor);
SDL_Flip(display);
}
// ...
}
// ...
}
It works fine until I move the mouse, why moving the mouse makes event.button.state untrue?
How can I work with both simultaneously (i.e. keep drawing while the button is pressed)?
The problem with your code is that you're calling SDL_PollEvent (documented here) twice. As said in the documentation:
If event is not NULL, the next event is removed from the queue and
stored in the SDL_Event structure pointed to by event.
Rearranging your code a bit, like getting rid of the second SDL_PollEvent, creating the proper flow for clicking, moving, releasing and extracting rendering from the input pumping should give you something like this:
SDL_Event Event;
while(running)
{
while(SDL_PollEvent(&Event))
{
switch(Event.type)
{
// Handle your drawing with a simple state machine:
case SDL_MOUSEBUTTONDOWN:
{
if(Event.button.button == SDL_BUTTON_LEFT)
{
if(stateMachine == Released)
{
// ... begin drawing
stateMachine = Dragging
}
}
break;
}
case SDL_MOUSEMOTION:
{
if(stateMachine == Dragging)
{
// ... update the extends of your rect
}
}
case SDL_MOUSEBUTTONUP:
{
if(Event.button.button == SDL_BUTTON_LEFT)
{
if(stateMachine != Released)
{
// ... finalize drawing... add the rect to a list? flush it?
stateMachine = Released;
}
}
}
case SDL_QUIT:
{
running = false;
break;
}
}
}
// Outside of your event pumping, update the graphics
SDL_FillRect(display,&boxRect,boxColor);
SDL_Flip(display);
}
event.button.state is a bit mask. It is declared as a char which can hold eight bits representing different states of the buttons.
typedef struct{
Uint8 type;
Uint8 state;
Uint16 x, y;
Sint16 xrel, yrel;
} SDL_MouseMotionEvent;
More information here,
http://www.libsdl.org/docs/html/sdlgetmousestate.html
http://www.libsdl.org/docs/html/sdlmousemotionevent.html
Thanks to emartel's answer, it's working as expected, here's the code:
SDL_Event event;
int drawing = 0;
while(running){
while(SDL_PollEvent(&event)){
switch(event.type){
//starts drawing when any mouse button is pressed
case SDL_MOUSEBUTTONDOWN:
drawing = 1;
boxRect.x = event.button.x;
boxRect.y = event.button.y;
break;
//keeps drawing while no button is released
case SDL_MOUSEMOTION:
if(drawing == 1){
boxRect.x = event.motion.x;
boxRect.y = event.motion.y;
}
break;
//stops drawing when any button is released
case SDL_MOUSEBUTTONUP:
drawing = 0;
break;
case SDL_QUIT:
running = 0;
break;
}
}
//draws to screen
if(drawing == 1){
SDL_FillRect(display,&boxRect,boxColor);
SDL_Flip(display);
}
}

Resources