Allegro pong collision problems - c++

I have just recently started working with allegro 5 and decided to start with a basic pong game. I found one and decided to add some extras to it. After adding two more paddles and the needed variables and controls, I copied and pasted the collision code from the original two and added the needed variables. However, if I move the new paddles from the originals, they no longer bounce off the ball. The code is huge I know, but I have no idea whats causing the problem.
`
#include <stdio.h>
#include <cstdlib>
#include <sstream>
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_color.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
/* constants and definitions */
const int SCREEN_W = 960;
const int SCREEN_H = 720;
const float FPS = 60;
const int paddle_height = 96;
const int paddle_width = 16;
const int bouncer_size = 16;
enum MYKEYS{
KEY_UP,KEY_DOWN,KEY_W,KEY_S,KEY_E,KEY_D,KEY_O,KEY_L
};
/* functions */
void draw_paddle(float x,float y){
// fill
al_draw_filled_rounded_rectangle(x,y,x+paddle_width,y+paddle_height,3,3,al_color_html("729fcf"));
// outline
al_draw_rounded_rectangle(x,y,x+paddle_width,y+paddle_height,3,3,al_color_html("b5edff"),1.0);
// shine
al_draw_filled_rounded_rectangle(x,y,x+paddle_width/2,y+paddle_height-10,3,3,al_color_html("8abbef"));
}
void draw_ball(float x,float y){
// fill
al_draw_filled_circle(x,y,bouncer_size,al_color_html("6be97d"));
// shadow
al_draw_filled_circle(x+bouncer_size/4,y+bouncer_size/4,bouncer_size/3*2,al_color_html("59ce76"));
// shine
al_draw_filled_circle(x-bouncer_size/3,y-bouncer_size/3,bouncer_size/4,al_color_html("9bffaa"));
}
void draw_score(int l,int r){
std::ostringstream ostr;
ostr << l;
std::ostringstream ostr1;
ostr1 << r;
ALLEGRO_FONT *font = al_load_font("arial.ttf",72,0);
al_draw_filled_rectangle(SCREEN_W/2-5,SCREEN_H,SCREEN_W/2+5,-SCREEN_H,al_color_html("ffffff"));
al_draw_text(font,al_color_html("ffffff"),SCREEN_W/2-50,0,ALLEGRO_ALIGN_CENTRE,ostr.str().c_str());
al_draw_text(font,al_color_html("ffffff"),SCREEN_W/2+50,0,ALLEGRO_ALIGN_CENTER,ostr1.str().c_str());
al_destroy_font(font);
}
int main(){
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_BITMAP *right_paddle = NULL;
ALLEGRO_BITMAP *left_paddle = NULL;
ALLEGRO_BITMAP *right_sub_paddle = NULL;
ALLEGRO_BITMAP *left_sub_paddle = NULL;
ALLEGRO_BITMAP *bouncer = NULL;
float right_paddle_x =(SCREEN_W*4/5)-(paddle_width/2.0);
float right_paddle_y =(SCREEN_H/2.0)-(paddle_height/2.0);
float left_paddle_x =(SCREEN_W*1/5)-(paddle_width/2.0);
float left_paddle_y =(SCREEN_H/2.0)-(paddle_height/2.0);
float right_sub_paddle_x = (SCREEN_W*4/5)-(paddle_width/2.0)-100;
float right_sub_paddle_y =(SCREEN_H/2.0)-(paddle_height/2.0);
float left_sub_paddle_x = (SCREEN_W*1/5)-(paddle_width/2.0)+100;
float left_sub_paddle_y = (SCREEN_H/2.0)-(paddle_height/2.0);
float bouncer_x = SCREEN_W/2.0-bouncer_size/2.0;
float bouncer_y = SCREEN_H/2.0-bouncer_size/2.0;
float bouncer_dx = 8.0,bouncer_dy = -8.0;
float paddle_speed = 8.0;
bool key[8] = {false,false,false,false,false,false,false,false};
bool redraw = true;
bool doexit = false;
bool pause = false;
int left_score = 0;
int right_score = 0;
if(!al_init()){
fprintf(stderr,"failed to initialized allegro\n");
return -1;
}
if(!al_install_keyboard()){
fprintf(stderr,"failed to install keyboard\n");
return -1;
}
al_init_primitives_addon();
al_init_font_addon();
al_init_ttf_addon();
al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS,1,ALLEGRO_SUGGEST);
al_set_new_display_option(ALLEGRO_SAMPLES,4,ALLEGRO_SUGGEST);
//initialize display(w,h)
display = al_create_display(SCREEN_W,SCREEN_H);
if(!display){
fprintf(stderr,"failed to create display\n");
return -1;
}
timer = al_create_timer(1.0/FPS);
if(!timer){
fprintf(stderr,"failed to create timer\n");
return -1;
}
right_paddle = al_create_bitmap(paddle_width,paddle_height);
if(!right_paddle){
fprintf(stderr,"failed to create right paddle bitmap\n");
return -1;
}
left_paddle = al_create_bitmap(paddle_width,paddle_height);
if(!left_paddle){
fprintf(stderr,"failed to create left paddle bitmap\n");
return -1;
}
right_sub_paddle = al_create_bitmap(paddle_width,paddle_height);
if(!right_sub_paddle){
fprintf(stderr,"failed to create right sub paddle bitmap\n");
return -1;
}
left_sub_paddle = al_create_bitmap(paddle_width,paddle_height);
if(!left_sub_paddle){
fprintf(stderr,"failed to create left sub paddle bitmap\n");
return -1;
}
bouncer = al_create_bitmap(bouncer_size,bouncer_size);
if(!bouncer){
fprintf(stderr,"failed to create bouncer bitmap\n");
return -1;
}
al_set_target_bitmap(left_paddle);
al_clear_to_color(al_map_rgb(0,255,0));
al_set_target_bitmap(right_paddle);
al_clear_to_color(al_map_rgb(0,255,0));
al_set_target_bitmap(left_sub_paddle);
al_clear_to_color(al_map_rgb(0,255,0));
al_set_target_bitmap(right_sub_paddle);
al_clear_to_color(al_map_rgb(0,255,0));
al_set_target_bitmap(bouncer);
al_clear_to_color(al_map_rgb(0,0,255));
al_set_target_bitmap(al_get_backbuffer(display));
event_queue = al_create_event_queue();
if(!event_queue){
fprintf(stderr,"failed to create event queue\n");
return -1;
}
al_register_event_source(event_queue,al_get_display_event_source(display));
al_register_event_source(event_queue,al_get_timer_event_source(timer));
al_register_event_source(event_queue,al_get_keyboard_event_source());
al_clear_to_color(al_map_rgb(0,0,0));
al_flip_display();
al_start_timer(timer);
while(!doexit){
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue,&ev);
if(ev.type == ALLEGRO_EVENT_TIMER && !pause){
//logic for moving the paddles on input
if(key[KEY_UP] && right_paddle_y >= 4.0){
right_paddle_y -= paddle_speed;
}
if(key[KEY_DOWN] && right_paddle_y <= SCREEN_H-paddle_height-4.0){
right_paddle_y += paddle_speed;
}
if(key[KEY_W] && left_paddle_y >= 4.0){
left_paddle_y -= paddle_speed;
}
if(key[KEY_S] && left_paddle_y <= SCREEN_H-paddle_height-4.0){
left_paddle_y += paddle_speed;
}
if(key[KEY_E] && left_sub_paddle_y >= 4.0){
left_sub_paddle_y -= paddle_speed;
}
if(key[KEY_D] && left_sub_paddle_y <= SCREEN_H-paddle_height-4.0){
left_sub_paddle_y += paddle_speed;
}
if(key[KEY_O] && right_sub_paddle_y >= 4.0){
right_sub_paddle_y -= paddle_speed;
}
if(key[KEY_L] && right_sub_paddle_y <= SCREEN_H-paddle_height-4.0){
right_sub_paddle_y += paddle_speed;
}
//logic for the bouncer
if(bouncer_x < 0 || bouncer_x > SCREEN_W-bouncer_size){
if(bouncer_x < 0){
left_score += 1;
}else if(bouncer_x > SCREEN_W-bouncer_size){
right_score += 1;
}
paddle_speed = 8.0;
bouncer_x = SCREEN_W/2.0-bouncer_size/2.0;
bouncer_y = SCREEN_H/2.0-bouncer_size/2.0;
bouncer_dx = -bouncer_dx;
bouncer_dy = -bouncer_dx;
}
if(bouncer_y < 0 || bouncer_y > SCREEN_H-bouncer_size){
bouncer_dy = -bouncer_dy;
}
if(bouncer_x == left_paddle_x+(paddle_width/1.0)){
if(bouncer_y >= left_paddle_y+paddle_height || bouncer_y+bouncer_size < left_paddle_y){
}else{
paddle_speed += 1;
bouncer_dx = -bouncer_dx;
}
}
if(bouncer_x == right_paddle_x-(paddle_width/2.0)){
if(bouncer_y >= right_paddle_y+paddle_height || bouncer_y+bouncer_size < right_paddle_y){
}else{
paddle_speed += 1;
bouncer_dx = -bouncer_dx;
}
}
if(bouncer_x == left_sub_paddle_x+(paddle_width/1.0)){
if(bouncer_y >= left_sub_paddle_y+paddle_height || bouncer_y+bouncer_size < left_sub_paddle_y){
}else{
paddle_speed +=1;
bouncer_dx = -bouncer_dx;
}
}
if(bouncer_x == right_sub_paddle_x+(paddle_width/1.0)){
if(bouncer_y >= right_sub_paddle_y+paddle_height || bouncer_y+bouncer_size < right_sub_paddle_y){
}else{
paddle_speed +=1;
bouncer_dx = -bouncer_dx;
}
}
bouncer_x += bouncer_dx;
bouncer_y += bouncer_dy;
redraw = true;
}else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE){
break;
}else if(ev.type == ALLEGRO_EVENT_KEY_DOWN){
switch(ev.keyboard.keycode){
case ALLEGRO_KEY_UP:
key[KEY_UP] = true;
break;
case ALLEGRO_KEY_DOWN:
key[KEY_DOWN] = true;
break;
case ALLEGRO_KEY_W:
key[KEY_W] = true;
break;
case ALLEGRO_KEY_S:
key[KEY_S] = true;
break;
case ALLEGRO_KEY_E:
key[KEY_E] = true;
break;
case ALLEGRO_KEY_D:
key[KEY_D] = true;
break;
case ALLEGRO_KEY_O:
key[KEY_O] = true;
break;
case ALLEGRO_KEY_L:
key[KEY_L] = true;
break;
}
}else if(ev.type == ALLEGRO_EVENT_KEY_UP){
switch(ev.keyboard.keycode){
case ALLEGRO_KEY_UP:
key[KEY_UP] = false;
break;
case ALLEGRO_KEY_DOWN:
key[KEY_DOWN] = false;
break;
case ALLEGRO_KEY_W:
key[KEY_W] = false;
break;
case ALLEGRO_KEY_S:
key[KEY_S] = false;
break;
case ALLEGRO_KEY_E:
key[KEY_E] = false;
break;
case ALLEGRO_KEY_D:
key[KEY_D] = false;
break;
case ALLEGRO_KEY_O:
key[KEY_O] = false;
break;
case ALLEGRO_KEY_L:
key[KEY_L] = false;
break;
case ALLEGRO_KEY_ESCAPE:
doexit = true;
break;
case ALLEGRO_KEY_P:
if(pause){
pause = false;
}else{
pause = true;
}
break;
}
}
if(redraw && al_is_event_queue_empty(event_queue)){
redraw = false;
al_clear_to_color(al_map_rgb(0,0,0));
draw_score(right_score,left_score);
draw_paddle(right_sub_paddle_x,right_sub_paddle_y);
draw_paddle(left_sub_paddle_x,left_sub_paddle_y);
draw_paddle(right_paddle_x,right_paddle_y);
draw_paddle(left_paddle_x,left_paddle_y);
draw_ball(bouncer_x,bouncer_y);
//al_draw_bitmap(right_paddle,right_paddle_x,right_paddle_y,0);
//al_draw_bitmap(left_paddle,left_paddle_x,left_paddle_y,0);
//al_draw_bitmap(right_sub_paddle,right_sub_paddle_x,right_sub_paddle_y,0);
//al_draw_bitmap(left_sub_paddle,left_sub_paddle_x,left_sub_paddle_y,0);
//al_draw_bitmap(bouncer,bouncer_x,bouncer_y,0);
al_flip_display();
}
}
al_destroy_bitmap(bouncer);
al_destroy_bitmap(right_paddle);
al_destroy_bitmap(left_paddle);
al_destroy_bitmap(right_sub_paddle);
al_destroy_bitmap(left_sub_paddle);
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(event_queue);
return 0;
}`
Any help is greatly appreciated.

I'm pretty sure this is your problem:
float bouncer_dx = 8.0,bouncer_dy = -8.0;
^ notice it's always moving at 8px per game tick...
Further down in the code, you are checking if bouncer_x (and bouncer_y) is landing on a pixel that is exactly divisible by 8, and while it seems to work for the two original paddles, i'm willing to bet the bouncer_x value never equals the value to trigger this 'if' statement:
if(bouncer_x == left_sub_paddle_x+(paddle_width/1.0)) { ... }
because your new sub paddles have different width and math (divided by 1.0 and not 2.0)
Check it and see... this is just from looking over the code for a minute so i dunno for sure :)
Good luck!

Related

'Object': 'struct/class' type redefinition WITH header guards. How to fix?

In spite of separate compilation, I made a header and source file of an object. However, when I compile the code, I get the error
error C2011: 'Snake' : 'struct' type redefinition
I have looked at the resolutions for this error online, and all say it is due to not adding header guards to prevent multiple inclusions. However, the plot-twist is that even when I add these guards, the error still persists. Obviously there is something I am not realizing. So what is the problem? Here is my code.
Snake.h
#ifndef GUARD_SNAKE_H
#define GUARD_SNAKE_H
#include "variables.h"
#include "SFML/Graphics.hpp"
struct Snake
{
public:
sf::RectangleShape rect;
bool goingUp;
bool goingDown;
bool goingLeft;
bool goingRight;
//
bool realUp;
bool realDown;
bool realLeft;
bool realRight;
//
bool secInput;
bool secUp;
bool secDown;
bool secLeft;
bool secRight;
int x[allDots];
int y[allDots];
void changeDirection(int);
void input();
void moveUpdate();
void checkReals();
std::vector<sf::RectangleShape> draw();
bool goingHorizontal();
bool goingVertical();
};
#endif
Snake.cpp
#include "Snake.h"
#include "variables.h"
#include "SFML/Graphics.hpp"
#include <iostream>
#include <array>
struct Snake {
sf::RectangleShape rect;
bool goingUp;
bool goingDown;
bool goingLeft;
bool goingRight;
//
bool realUp;
bool realDown;
bool realLeft;
bool realRight;
//
bool secInput;
bool secUp;
bool secDown;
bool secLeft;
bool secRight;
int x[allDots];
int y[allDots];
//Snake Constructor: int coordinates for position
Snake::Snake(){
for (int z = 0; z < dots; z++){
this->x[z] = windowWidth / 2 - z * dotSize;
this->y[z] = windowHeight / 2;
}
//Default direction
goingUp = false;
goingDown = false;
goingLeft = false;
goingRight = true;
realUp = false;
realDown = false;
realLeft = false;
realRight = false;
secUp = false;
secDown = false;
secLeft = false;
secRight = false;
secInput = false; //Variable indicating first input has changed and able to declare to second input variables.
}
/*Changing direction member function*/
void Snake::changeDirections(int dir){
if(secInput == false){
if(secUp) {
goingUp = true;
secUp=false;
}
else if(secDown) {
goingDown=true;
secDown=false;
}
else if (secLeft) {
goingLeft=true;
secLeft = false;
}
else if (secRight) {
goingRight=true;
secRight=false;
} else{
switch (dir){
case 1:
goingUp = true;
goingDown = false;
goingLeft = false;
goingRight = false;
break;
case 2:
goingUp = false;
goingDown = true;
goingLeft = false;
goingRight = false;
break;
case 3:
goingUp = false;
goingDown = false;
goingLeft = true;
goingRight = false;
break;
case 4:
goingUp = false;
goingDown = false;
goingLeft = false;
goingRight = true;
break;
}
}
secInput = true;
} else {
switch (dir){
case 1:
secUp = true;
secDown = false;
secLeft = false;
secRight = false;
break;
case 2:
secUp = false;
secDown = true;
secLeft = false;
secRight = false;
break;
case 3:
secUp = false;
secDown = false;
secLeft = true;
secRight = false;
break;
case 4:
secUp = false;
secDown = false;
secLeft = false;
secRight = true;
break;
}
}
}
void Snake::input(){
//std::cout<<"Keyboard Input Called" <<std::endl;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W) && !realDown)
changeDirections(1);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S) && !realUp)
changeDirections(2);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A) && !realRight)
changeDirections(3);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D) && !realLeft)
changeDirections(4);
}
/*Frame by frame update*/
void Snake::moveUpdate(){
for (int z = dots; z > 0; z--){
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
/*Movement actions*/
if (goingUp)
y[0] -= dotSize;
else if (goingDown)
y[0] += dotSize;
else if (goingLeft)
x[0] -= dotSize;
else if (goingRight)
x[0] += dotSize;
}
void Snake::checkReals(){
if (x[0] < x[1]){
realLeft = true;
realRight = false;
realUp = false;
realDown = false;
}
if (x[0] > x[1]){
realRight = true;
realLeft = false;
realUp = false;
realDown = false;
}
if (y[0] < y[1]){
realUp = true;
realDown = false;
realRight = false;
realLeft = false;
}
if (y[0] > y[1]){
realDown = true;
realUp = false;
realLeft = false;
realRight = false;
}
else
std::cerr << "";//"Error Mismatch" << std::endl;
//Debug Output
if(goingUp)
std::cout<< "First Direction: goingUp" << std::endl;
if(goingDown)
std::cout<< "First Direction: goingDown" << std::endl;
if(goingLeft)
std::cout<< "First Direction: goingLeft" << std::endl;
if(goingRight)
std::cout<< "First Direction: goingRight" << std::endl;
if(secUp)
std::cout<< "First Direction: secUp" << std::endl;
if(secDown)
std::cout<< "First Direction: secDown" << std::endl;
if(secLeft)
std::cout<< "First Direction: secLeft" << std::endl;
if(secRight)
std::cout<< "First Direction: secRight" << std::endl;
}
std::vector<sf::RectangleShape> Snake::draw(){
std::vector<sf::RectangleShape> recvec;
for (int z = dots; z >= 0; z--){
sf::RectangleShape r;
r.setPosition(x[z], y[z]);
r.setSize(sf::Vector2f( dotSizeF, dotSizeF ));
r.setFillColor(sf::Color::Green);
if (z == 0)
r.setFillColor(sf::Color::Yellow);
r.setOrigin(dotSize / 2.f, dotSize / 2.f);
recvec.push_back(r);
}
return recvec;
}
bool Snake::goingHorizontal(){ return goingLeft || goingRight; }
bool Snake::goingVertical(){ return goingDown || goingUp; }
};
You have the redefinition error because you indeed have a redefinition in your cpp file : the struct Snake{...}; section. This isn't the way you provide definitions for your struct's methods. Here's a simplified example:
In header:
struct Example
{
void foo();
};
In cpp:
void Example::foo()
{
//foo stuff
}
Your definition of struct Snake {} in .cpp file is redefining the earlier in .h file. That's why you are getting error.

Array initialization effecting seemingly unrelated classes C++ SDL [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
So I'm nearly done writing my first tic tac toe in C++ and SDL, ad I've run into a slight problem. I use a state machine to switch from title screen to shape choice screen, to player one or two to winning screen and back to the choice screen etc etc. On the choice screen I have two SDL_Rect arrays that act as buttons and the buttons are the X and O sprites I use from my sprite sheet. When the mouse hovers over them, they change colors. Everything is fine and dandy until the game resets to the choice screen after a win lose or tie. When it goes back to the choice screen and the mouse hovers over the button, it does not show the highlighted or mouse hovered sprite it clipped before. I pin pointed this problem to the initialization of my "set_grid_regions()" function. But this array doesn't even interact with the choice screen class in any way. How can this be affecting my hover sprites?
Just so anyone can see, here is the whole of the program:
#include "SDL.h"
#include "SDL_ttf.h"
#include "SDL_image.h"
#include "SDL_mixer.h"
#include <string>
#include <iostream>
//constants
const int SCREEN_HEIGHT = 300;
const int SCREEN_WIDTH = 300;
const int SCREEN_BPP = 32;
const int GRID_WIDTH = 96;
const int GRID_HEIGHT = 96;
//game states
enum States
{
S_NULL,
INTRO,
CHOICE,
START_O,
START_X,
PLAYER_ONE,
PLAYER_TWO,
O_win,
X_win,
Tie,
EXIT,
};
// CLASSES //
class GameState
{
public:
virtual void events() = 0;
virtual void logic() = 0;
virtual void render() = 0;
virtual ~GameState(){};
};
class intro : public GameState
{
private:
//hover variable
bool button_hover = NULL;
//rects and surfaces
SDL_Rect button;
SDL_Surface *title_message = NULL;
public:
void events();
void logic();
void render();
intro();
~intro();
};
class choice : public GameState
{
private:
bool O_hover = NULL;
bool X_hover = NULL;
SDL_Rect shape_O_button;
SDL_Rect shape_X_button;
SDL_Surface *choice_text = NULL;
public:
void events();
void logic();
void render();
choice();
~choice();
};
class playerOne : public GameState
{
public:
void events();
void logic();
void render();
playerOne();
~playerOne();
};
class playerTwo : public GameState
{
public:
void events();
void logic();
void render();
playerTwo();
~playerTwo();
};
class win : public GameState
{
private:
int winner = NULL;
SDL_Surface *Tie = NULL;
SDL_Surface *X_win = NULL;
SDL_Surface *O_win = NULL;
public:
void events();
void logic();
void render();
win(int winner);
~win();
};
class Exit : public GameState
{
public:
void events();
void logic();
void render();
Exit();
~Exit();
};
// GLOBALS //
GameState *currentState = NULL;
int stateID = S_NULL;
int nextState = S_NULL;
//event
SDL_Event event;
//surfaces
SDL_Surface *screen = NULL;
SDL_Surface *sprites = NULL;
//ttf
TTF_Font *font = NULL;
SDL_Color color = { 0, 0, 0 };
SDL_Color win_Color = { 0, 100, 0 };
//arrays
int grid_array[9];
//rects
SDL_Rect sprite_clip[10];
SDL_Rect grid_region[9];
int number_elements = sizeof(grid_region) / sizeof(grid_region[0]);
//bools
bool shape = NULL;
bool invalid = NULL;
bool winner = NULL;
//ints
int highlight = NULL;
int shape_winner = NULL;
// FUCNTIONS //
//load image
SDL_Surface *load_image(std::string filename)
{
//loaded image
SDL_Surface* loadedImage = NULL;
//optimized surface
SDL_Surface* optimizedImage = NULL;
//load image
loadedImage = IMG_Load(filename.c_str());
//if image loaded
if (loadedImage != NULL)
{
//Create optimized image
optimizedImage = SDL_DisplayFormat(loadedImage);
//free old image
SDL_FreeSurface(loadedImage);
//if optimized
if (optimizedImage != NULL)
{
//map color key
Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 255, 255, 0);
//set all pixles of color 0,0,0 to be transparent
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
}
}
return optimizedImage;
}
//apply image
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL)
{
//temp rect
SDL_Rect offset;
//offsets
offset.x = x;
offset.y = y;
//blit
SDL_BlitSurface(source, clip, destination, &offset);
}
//initiate SDL etc
bool init()
{
//initialize all SDL subsystems
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
return false;
}
//set up screen
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
if (screen == NULL)
{
return false;
}
//check screen
if (screen == NULL)
{
return false;
}
//init TTF
if (TTF_Init() == -1)
{
return false;
}
//set window caption
SDL_WM_SetCaption("Tic-Tac-Toe", NULL);
//if evetything worked
return true;
}
//load files
bool load_files()
{
//sprite sheet
sprites = load_image("Sprites.png");
if (sprites == NULL)
{
return false;
}
font = TTF_OpenFont("font.ttf", 45);
if (font == NULL)
{
return false;
}
return true;
}
//quit
void clean_up()
{
//delete game state
delete currentState;
//free image
SDL_FreeSurface(sprites);
//quit ttf
TTF_CloseFont(font);
TTF_Quit();
//quit SDL
SDL_Quit();
}
void set_clip_regions()
{
//init clip array
//O
sprite_clip[0].x = 300;
sprite_clip[0].y = 0;
sprite_clip[0].w = 80;
sprite_clip[0].h = 82;
//X
sprite_clip[1].x = 300;
sprite_clip[1].y = 176;
sprite_clip[1].w = 80;
sprite_clip[1].h = 82;
//grid
sprite_clip[2].x = 0;
sprite_clip[2].y = 0;
sprite_clip[2].w = 300;
sprite_clip[2].h = 300;
//highlight
sprite_clip[3].x = 300;
sprite_clip[3].y = 82;
sprite_clip[3].w = 94;
sprite_clip[3].h = 94;
//left to right line
sprite_clip[4].x = 398;
sprite_clip[4].y = 188;
sprite_clip[4].w = 234;
sprite_clip[4].h = 12;
//diag up
sprite_clip[5].x = 393;
sprite_clip[5].y = 0;
sprite_clip[5].w = 188;
sprite_clip[5].h = 186;
//up down line
sprite_clip[6].x = 591;
sprite_clip[6].y = 0;
sprite_clip[6].w = 11;
sprite_clip[6].h = 208;
//Diag down line
sprite_clip[7].x = 0;
sprite_clip[7].y = 300;
sprite_clip[7].w = 188;
sprite_clip[7].h = 186;
//start button
sprite_clip[8].x = 202;
sprite_clip[8].y = 300;
sprite_clip[8].w = 94;
sprite_clip[8].h = 32;
//intro and choice background
sprite_clip[9].x = 300;
sprite_clip[9].y = 300;
sprite_clip[9].w = 300;
sprite_clip[9].h = 300;
//start hover
sprite_clip[10].x = 202;
sprite_clip[10].y = 332;
sprite_clip[10].w = 94;
sprite_clip[10].h = 32;
//X hover
sprite_clip[11].x = 202;
sprite_clip[11].y = 446;
sprite_clip[11].w = 80;
sprite_clip[11].h = 82;
//o hover
sprite_clip[12].x = 202;
sprite_clip[12].y = 364;
sprite_clip[12].w = 80;
sprite_clip[12].h = 82;
}
void set_grid_regions()
{
//set regions for images to be applied to
grid_region[0].x = 3;
grid_region[0].y = 3;
grid_region[1].x = 103;
grid_region[1].y = 3;
grid_region[2].x = 203;
grid_region[2].y = 3;
grid_region[3].x = 3;
grid_region[3].y = 103;
grid_region[4].x = 103;
grid_region[4].y = 103;
grid_region[5].x = 203;
grid_region[5].y = 103;
grid_region[6].x = 3;
grid_region[6].y = 203;
grid_region[7].x = 103;
grid_region[7].y = 203;
grid_region[8].x = 203;
grid_region[8].y = 203;
}
void init_grid()
{
//from left to right top to bottom
grid_array[0] = 0;
grid_array[1] = 0;
grid_array[2] = 0;
grid_array[3] = 0;
grid_array[4] = 0;
grid_array[5] = 0;
grid_array[6] = 0;
grid_array[7] = 0;
grid_array[8] = 0;
}
// STATE MACHINE FUNCTIONS //
void set_next_state(int newState)
{
if (nextState != EXIT)
{
nextState = newState;
}
}
void change_state()
{
if (nextState != S_NULL)
{
//change state
switch (nextState)
{
case CHOICE:
currentState = new choice();
break;
case PLAYER_ONE:
currentState = new playerOne();
break;
case PLAYER_TWO:
currentState = new playerTwo();
break;
case O_win:
currentState = new win(0);
break;
case X_win:
currentState = new win(1);
break;
case Tie:
currentState = new win(2);
break;
case EXIT:
currentState = new Exit();
break;
}
//change state
stateID = nextState;
//null nextState
nextState = S_NULL;
}
}
// CLASS DEFINITIONS //
intro::intro()
{
//button
button_hover = false;
//title
title_message = TTF_RenderText_Solid(font, "TIC TAC TOE", color);
//button bounds
button.x = 102;
button.y = 180;
button.w = 94;
button.h = 32;
}
intro::~intro()
{
SDL_FreeSurface(title_message);
}
void intro::events()
{
int x, y;
//mouse events
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
x = event.motion.x;
y = event.motion.y;
if ((x > button.x) && (x < button.x + button.w) && (y > button.y) && (y < button.y + button.h))
{
button_hover = true;
}
else
{
button_hover = false;
}
}
if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
x = event.motion.x;
y = event.motion.y;
if ((x > button.x) && (x < button.x + button.w) && (y > button.y) && (y < button.y + button.h))
{
set_next_state(CHOICE);
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void intro::logic()
{
}
void intro::render()
{
apply_surface(0, 0, sprites, screen, &sprite_clip[9]);
apply_surface((SCREEN_WIDTH - title_message->w) / 2, 100, title_message, screen);
if (button_hover == true)
{
apply_surface(102, 180, sprites, screen, &sprite_clip[10]);
}
else
{
apply_surface(102, 180, sprites, screen, &sprite_clip[8]);
}
}
choice::choice()
{
O_hover = false;
X_hover = false;
shape_O_button.x = 0;
shape_O_button.y = 130;
shape_O_button.w = 80;
shape_O_button.h = 82;
shape_X_button.x = 220;
shape_X_button.y = 130;
shape_X_button.w = 80;
shape_X_button.h = 82;
font = TTF_OpenFont("font.ttf", 34);
choice_text = TTF_RenderText_Solid(font, "CHOOSE YOUR SHAPE", color);
}
choice::~choice()
{
SDL_FreeSurface(choice_text);
O_hover = NULL;
X_hover = NULL;
}
void choice::events()
{
int x, y;
//mouse events
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
x = event.motion.x;
y = event.motion.y;
if ((x > shape_O_button.x) && (x < shape_O_button.x + shape_O_button.w) && (y > shape_O_button.y) && (y < shape_O_button.y + shape_O_button.h))
{
O_hover = true;
}
else
{
O_hover = false;
}
if ((x > shape_X_button.x) && (x < shape_X_button.x + shape_X_button.w) && (y > shape_X_button.y) && (y < shape_X_button.y + shape_X_button.h))
{
X_hover = true;
}
else
{
X_hover = false;
}
}
if (event.type == SDL_MOUSEBUTTONDOWN)
{
if (event.button.button == SDL_BUTTON_LEFT)
{
x = event.motion.x;
y = event.motion.y;
if ((x > shape_O_button.x) && (x < shape_O_button.x + shape_O_button.w) && (y > shape_O_button.y) && (y < shape_O_button.y + shape_O_button.h))
{
shape = false;
init_grid();
set_next_state(PLAYER_ONE);
}
if ((x > shape_X_button.x) && (x < shape_X_button.x + shape_X_button.w) && (y > shape_X_button.y) && (y < shape_X_button.y + shape_X_button.h))
{
shape = true;
init_grid();
set_next_state(PLAYER_TWO);
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void choice::logic()
{
}
void choice::render()
{
apply_surface( 0, 0, sprites, screen, &sprite_clip[9]);
if (O_hover == false)
{
apply_surface(shape_O_button.x, shape_O_button.y, sprites, screen, &sprite_clip[0]);
}
else
{
apply_surface(shape_O_button.x, shape_O_button.y, sprites, screen, &sprite_clip[12]);
}
if (X_hover == false)
{
apply_surface(shape_X_button.x, shape_X_button.y, sprites, screen, &sprite_clip[1]);
}
else
{
apply_surface(shape_X_button.x, shape_X_button.y, sprites, screen, &sprite_clip[11]);
}
apply_surface((SCREEN_WIDTH - choice_text->w) / 2, 60, choice_text, screen);
}
//plyer O
playerOne::playerOne()
{
set_grid_regions();
}
playerOne::~playerOne()
{
}
void playerOne::events()
{
//mouse offsets
int x = 0, y = 0;
//if mouse moves
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
//get the mouse co-ords
x = event.motion.x;
y = event.motion.y;
for (int grid = 0; grid < number_elements; grid++)
{
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//set highlight region
highlight = grid;
}
}
}
//when the player clicks on a grid_region
if (event.type == SDL_MOUSEBUTTONDOWN)
{
//mouse co-ordinates
x = event.motion.x;
y = event.motion.y;
if (event.button.button == SDL_BUTTON_LEFT)
{
//iterate
for (int grid = 0; grid < number_elements; grid++)
{
//if in region box
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//check region
//if O turn
if ((grid_array[grid] == 0) && (shape == 0))
{
//fill region
grid_array[grid] = 1;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
//if X turn
else if ((grid_array[grid] == 0) && (shape == 1))
{
if ((grid_array[grid] == 0))
{
//fill region
grid_array[grid] = 2;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
}
}
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void playerOne::logic()
{
//check O win
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 1) && (grid_array[win + 1] == 1) && (grid_array[win + 2] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 1) && (grid_array[win + 3] == 1) && (grid_array[win + 6] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
if ((grid_array[0] == 1) && (grid_array[4] == 1) && (grid_array[8] == 1))
{
winner = 0;
set_next_state(O_win);
}
if ((grid_array[2] == 1) && (grid_array[4] == 1) && (grid_array[6] == 1))
{
winner = 0;
set_next_state(O_win);
}
//check X's
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 2) && (grid_array[win + 1] == 2) && (grid_array[win + 2] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 2) && (grid_array[win + 3] == 2) && (grid_array[win + 6] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
if ((grid_array[0] == 2) && (grid_array[4] == 2) && (grid_array[8] == 2))
{
winner = 1;
set_next_state(X_win);
}
if ((grid_array[2] == 2) && (grid_array[4] == 2) && (grid_array[6] == 2))
{
winner = 1;
set_next_state(X_win);
}
//check TIE
if ((grid_array[0] != 0) && (grid_array[1] != 0) && (grid_array[2] != 0) && (grid_array[3] != 0) && (grid_array[4] != 0) && (grid_array[5] != 0) && (grid_array[6] != 0) && (grid_array[7] != 0) && (grid_array[8] != 0) && (winner == NULL))
{
set_next_state(Tie);
}
}
void playerOne::render()
{
//logic
//rendering
//background
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
//grid
apply_surface(0, 0, sprites, screen, &sprite_clip[2]);
//highlight
if (highlight != -1)
{
apply_surface(grid_region[highlight].x, grid_region[highlight].y, sprites, screen, &sprite_clip[3]);
}
//APPLY PLAYER SHAPE
for (int grid = 0; grid < number_elements; grid++)
{
//O's
if ((grid_array[grid] == 1))
{
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[0]);
}
else if ((grid_array[grid] == 2))
{
//X's
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[1]);
}
}
}
playerTwo::playerTwo()
{
set_grid_regions();
}
playerTwo::~playerTwo()
{
}
void playerTwo::events()
{
//mouse offsets
int x = 0, y = 0;
//if mouse moves
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
//get the mouse co-ords
x = event.motion.x;
y = event.motion.y;
for (int grid = 0; grid < number_elements; grid++)
{
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//set highlight region
highlight = grid;
}
}
}
//when the player clicks on a grid_region
if (event.type == SDL_MOUSEBUTTONDOWN)
{
//mouse co-ordinates
x = event.motion.x;
y = event.motion.y;
if (event.button.button == SDL_BUTTON_LEFT)
{
//iterate
for (int grid = 0; grid < number_elements; grid++)
{
//if in region box
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//check region
//if O turn
if ((grid_array[grid] == 0) && (shape == 0))
{
//fill region
grid_array[grid] = 1;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
//if X turn
else if ((grid_array[grid] == 0) && (shape == 1))
{
if ((grid_array[grid] == 0))
{
//fill region
grid_array[grid] = 2;
shape = (!shape);
}
else if (grid_array[grid] != 0)
{
//raise "error"
invalid = true;
}
}
}
}
}
}
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void playerTwo::logic()
{
//check O win
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 1) && (grid_array[win + 1] == 1) && (grid_array[win + 2] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 1) && (grid_array[win + 3] == 1) && (grid_array[win + 6] == 1))
{
winner = 0;
set_next_state(O_win);
}
}
if ((grid_array[0] == 1) && (grid_array[4] == 1) && (grid_array[8] == 1))
{
winner = 0;
set_next_state(O_win);
}
if ((grid_array[2] == 1) && (grid_array[4] == 1) && (grid_array[6] == 1))
{
winner = 0;
set_next_state(O_win);
}
//check X's
for (int win = 0; win <= 6; win += 3)
{
if ((grid_array[win] == 2) && (grid_array[win + 1] == 2) && (grid_array[win + 2] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
for (int win = 0; win < 3; win++)
{
if ((grid_array[win] == 2) && (grid_array[win + 3] == 2) && (grid_array[win + 6] == 2))
{
winner = 1;
set_next_state(X_win);
}
}
if ((grid_array[0] == 2) && (grid_array[4] == 2) && (grid_array[8] == 2))
{
winner = 1;
set_next_state(X_win);
}
if ((grid_array[2] == 2) && (grid_array[4] == 2) && (grid_array[6] == 2))
{
winner = 1;
set_next_state(X_win);
}
//check TIE
if ((grid_array[0] != 0) && (grid_array[1] != 0) && (grid_array[2] != 0) && (grid_array[3] != 0) && (grid_array[4] != 0) && (grid_array[5] != 0) && (grid_array[6] != 0) && (grid_array[7] != 0) && (grid_array[8] != 0) && (winner == NULL))
{
set_next_state(Tie);
}
}
void playerTwo::render()
{
//logic
//rendering
//background
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
//grid
apply_surface(0, 0, sprites, screen, &sprite_clip[2]);
//highlight
if (highlight != -1)
{
apply_surface(grid_region[highlight].x, grid_region[highlight].y, sprites, screen, &sprite_clip[3]);
}
//APPLY PLAYER SHAPE
for (int grid = 0; grid < number_elements; grid++)
{
//O's
if ((grid_array[grid] == 1))
{
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[0]);
}
else if ((grid_array[grid] == 2))
{
//X's
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[1]);
}
}
}
win::win(int winner)
{
shape_winner = winner;
font = TTF_OpenFont("font.ttf", 45);
X_win = TTF_RenderText_Solid(font, "X WINS", win_Color);
O_win = TTF_RenderText_Solid(font, "O wins", win_Color);
Tie = TTF_RenderText_Solid(font, "Tie", win_Color);
}
win::~win()
{
TTF_CloseFont(font);
SDL_FreeSurface(X_win);
SDL_FreeSurface(O_win);
}
void win::events()
{
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
set_next_state(EXIT);
}
}
}
void win::logic()
{
if (shape_winner == 3)
{
SDL_Delay(2000);
set_next_state(CHOICE);
winner = NULL;
}
}
void win::render()
{
//background
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
//grid
apply_surface(0, 0, sprites, screen, &sprite_clip[2]);
//highlight
if (highlight != -1)
{
apply_surface(grid_region[highlight].x, grid_region[highlight].y, sprites, screen, &sprite_clip[3]);
}
//APPLY PLAYER SHAPE
for (int grid = 0; grid < number_elements; grid++)
{
//O's
if ((grid_array[grid] == 1))
{
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[0]);
}
else if ((grid_array[grid] == 2))
{
//X's
apply_surface(grid_region[grid].x + 7, grid_region[grid].y + 6, sprites, screen, &sprite_clip[1]);
}
}
if (shape_winner == 1)
{
apply_surface((SCREEN_WIDTH - X_win->w) / 2, (SCREEN_HEIGHT - X_win->h) / 2, X_win, screen);
//enable delay and reset
shape_winner = 3;
}
if (shape_winner == 0)
{
apply_surface((SCREEN_WIDTH - O_win->w) / 2, (SCREEN_HEIGHT - O_win->h) / 2, O_win, screen);
//enable delay and reset
shape_winner = 3;
}
if (shape_winner == 2)
{
apply_surface((SCREEN_WIDTH - Tie->w) / 2, (SCREEN_HEIGHT - Tie->h) / 2, Tie, screen);
//enable delay and reset
shape_winner = 3;
}
}
Exit::Exit()
{
}
Exit::~Exit()
{
}
void Exit::events()
{
}
void Exit::logic()
{
}
void Exit::render()
{
}
//MAAAAAAAAAAAAAAAAAAIN//
int main(int argc, char* args[])
{
//init SDL
init();
//load files
load_files();
//set clips
set_clip_regions();
//set state
stateID = INTRO;
//set game object
currentState = new intro();
while (stateID != EXIT)
{
//handle state events
currentState->events();
// do state logic
currentState->logic();
//change state if needed
change_state();
//render state
currentState->render();
if (SDL_Flip(screen) == -1)
{
return 1;
}
}
clean_up();
return 0;
}
It's pretty strange. But I'm 99% sure that it's the "set_grid_regions()" that is effecting the rendering inside the choice::render() or choice::event() class fucntions. Can anyone help with this?
The error causing the clipping problem is an incorrect declaration for sprite_clip. You've declared it as sprite_clip[10], but you have 13 sprites. Change this to sprite_clip[13].
Other things I noticed:
You allocate all these state objects with new, but you never delete them. You need to delete them when you change states. Otherwise you will leak memory.
The font font.ttf seems to be a global resource but is haphazardly managed by a mixture of global and local methods. Load it once in load_files() and release it once in clean_up().
While your project may be complete, you might tinker around with it and work on improving the implementation now that you have something working. (If this was a homework, keep a copy of a working version to hand in. ;-) )
Consider packaging all of your global state (your fonts, sprites, clipping arrays, etc.) into a single class for the game. Your init_xxx and load_xxx functions move to its constructor. Your clean_up moves to its destructor.
Consider converting your dynamic state objects into statically allocated state objects. They could even be members of the same global state class I mentioned in the previous bullet. Now you've encapsulated the whole game in one class.
Consider merging playerOne and playerTwo into a single class. Distinguish them at construction time, just as you did with win(0), win(1), win(2).

Weird visual error with drawing Allegro primitives

I am using the allegro_primitives.h header file, and when I go to draw a rectangle with al_draw_filled_rectangle, and I move the rectangle with the keys, the outline of the rectangle in the direction that the rectangle is going is changing colors. Here's the code:
#include <allegro5\allegro5.h>
#include <allegro5\allegro_primitives.h>
#include <iostream>
#include "Globals.h"
using namespace std;
bool keys[5] = {false, false, false, false, false};
enum KEYS {UP, DOWN, LEFT, RIGHT, SPACE};
const int WINDOW_WIDTH = 600;
const int WINDOW_HEIGHT = 600;
int main()
{
bool done = false;
bool redraw = true;
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
if(!al_init())
return -1;
al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);
al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);
display = al_create_display(WINDOW_WIDTH,WINDOW_HEIGHT);
if(!display)
return -1;
al_init_primitives_addon();
al_install_keyboard();
event_queue = al_create_event_queue();
timer = al_create_timer(1.0 / 60);
if(!timer)
return -1;
if(!event_queue)
return -1;
al_register_event_source(event_queue,al_get_keyboard_event_source());
al_register_event_source(event_queue,al_get_timer_event_source(timer));
al_register_event_source(event_queue,al_get_display_event_source(display));
Character player;
Character lover;
player.x1 = 100;
player.x2 = player.x1 + 40;
player.y1 = (WINDOW_HEIGHT / 2) - 20;
player.y2 = player.y1 + 40;
lover.x1 = WINDOW_WIDTH - 140;
lover.x2 = lover.x1 + 40;
lover.y1 = (WINDOW_HEIGHT / 2) - 20;
lover.y2 = lover.y1 + 40;
al_start_timer(timer);
while(!done)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue,&ev);
if(ev.timer.source == timer)
{
if(keys[UP])
{
player.y1 -= 5;
player.y2 -= 5;
}
if(keys[DOWN])
{
player.y1 += 5;
player.y2 += 5;
}
if(keys[LEFT])
{
player.x1 -= 5;
player.x2 -= 5;
}
if(keys[RIGHT])
{
player.x1 += 5;
player.x2 += 5;
}
if(player.x1 <= 0)
{
player.x1 = 0;
player.x2 = 40;
}
if(player.x2 >= WINDOW_WIDTH)
{
player.x1 = WINDOW_WIDTH - 40;
player.x2 = WINDOW_WIDTH;
}
if(player.y1 <= 0)
{
player.y1 = 0;
player.y2 = player.y1 + 40;
}
if(player.y2 >= WINDOW_HEIGHT)
{
player.y1 = WINDOW_HEIGHT - 40;
player.y2 = WINDOW_HEIGHT;
}
}
if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
{
done = true;
}
if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = true;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = true;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = true;
break;
case ALLEGRO_KEY_UP:
keys[UP] = true;
break;
}
}
if(ev.type == ALLEGRO_EVENT_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_ESCAPE:
done = true;
break;
case ALLEGRO_KEY_LEFT:
keys[LEFT] = false;
break;
case ALLEGRO_KEY_RIGHT:
keys[RIGHT] = false;
break;
case ALLEGRO_KEY_UP:
keys[UP] = false;
break;
case ALLEGRO_KEY_DOWN:
keys[DOWN] = false;
break;
}
}
if(redraw && al_is_event_queue_empty(event_queue))
{
al_draw_filled_rectangle(player.x1,player.y1,player.x2,player.y2,al_map_rgb(0,0,127));
al_draw_filled_rectangle(lover.x1,lover.y1,lover.x2,lover.y2,al_map_rgb(127,0,0));
al_flip_display();
al_clear_to_color(al_map_rgb(255,255,255));
}
}
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(event_queue);
return 0;
}
Can anybody help me out here? "Globals.h" is just a small header file which contains a struct for Character defining their x1, x2, y1, and y2 variables. Thanks.
As your code currently is, your redraw is not being controlled by your timer. Your redraw variable is being initialized to true, but it makes more sense to set it to false, and let your timer set it to true when appropriate. When your timer event fires, set redraw to true.
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue,&ev);
if(ev.timer.source == timer)
{
redraw = true;
}
Then when you check for redraw, set it back to false.
if(redraw && al_is_event_queue_empty(event_queue))
{
redraw = false;
al_draw_filled_rectangle(player.x1,player.y1,player.x2,player.y2,al_map_rgb(0,0,127));
al_draw_filled_rectangle(lover.x1,lover.y1,lover.x2,lover.y2,al_map_rgb(127,0,0));
al_flip_display();
al_clear_to_color(al_map_rgb(255,255,255));
}

Program freezes, cannot find solution. SDL and C++

I've checked everywhere in my code and I could not find the reason why my program freezes every time I load it. The problem started happening after I included a new AI header, "schoolboy.h". I checked to make sure that attempting to blit an image wasn't the problem, and it wasn't. So, after some testing, I figured that the problem lied in "void schoolboy_action()" within "schoolboy.h". Here is the entire project's code. I spent an hour looking at that section and could not find a solution. I know that the is really long, and that there are some holes in it that I plan on filling, but please bear with me.
Main.cpp
#include "schoolboy.h"
#include "include_file.h"
int main(int argc,char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
variables();
while (quit == 1)
{
while (MARS.alive == 1)
{
SDL_WM_SetCaption("Mobile Anihilation Robot System", NULL);
applysurface(0,0,background,screen);
MARS_action();
MARS_bullet_action(1);
gunshot_explosion_action(1);
if (create_schoolboy_variable == 1)
{create_schoolboy(); create_schoolboy_variable = 0;}
else if (create_schoolboy_variable < 1)
{create_schoolboy_variable = rand() % 1;};
schoolboy_action(0,0,0);
applysurface(MARS.x-25, MARS.y-25, MARS_image, screen);
SDL_Flip(screen);
SDL_Delay(1);
};
while (MARS.alive == 0)
{
SDL_WM_SetCaption("Mobil Anihilation Robot System", NULL);
};
};
SDL_FreeSurface(screen);
SDL_Quit();
return 0;
};
include_file.h
#ifndef INCLUDE_FILE_H_INCLUDED
#define INCLUDE_FILE_H_INCLUDED
#include <map>
#include <cstdlib>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
/*structs*/
struct instance_struct
{
int gunshot_explosion;
int schoolboy_instance;
};
struct MARS_struct
{
int x;
int y;
int alive;
int bullet;
};
struct MARS_bullet_struct
{
int x;
int y;
int direction;
int exist;
int id;
bool operator<(const MARS_bullet_struct & n)const{return this->id<n.id;}
};
struct schoolboy_struct
{
int x;
int y;
int direction;
int id;
int exist;
int walk_delay;
int shoot_delay;
int walked;
SDL_Rect clip[3];
bool operator<(const schoolboy_struct&n)const{return this->id<n.id;}
};
struct gunshot_explosion_struct
{
int x;
int y;
int id;
int life;
int exist;
bool operator<(const gunshot_explosion_struct&n)const{return this->id<n.id;}
};
/*declaring structs*/
MARS_struct MARS;
instance_struct instance_body;
std::map<int, MARS_bullet_struct>MARS_bullet;
std::map<int, schoolboy_struct>schoolboy;
std::map<int, gunshot_explosion_struct>gunshot_explosion;
/*applysurface*/
void applysurface(int x, int y, SDL_Surface *source, SDL_Surface *destination, SDL_Rect* clip = NULL)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface(source,clip,destination,&offset);
};
/*declaring global variables*/
int quit;
int create_schoolboy_variable;
SDL_Event event;
SDL_Rect clip[3];
SDL_Surface *screen = NULL;
SDL_Surface *background = NULL;
SDL_Surface *gunshot_explosion_image = NULL;
SDL_Surface *MARS_image = NULL;
SDL_Surface *MARS_bullet_image = NULL;
SDL_Surface *schoolboy_image = NULL;
/*giving variables values*/
void variables()
{
quit = 1;
MARS.alive = 1;
MARS.x = 256;
MARS.y = 256;
create_schoolboy_variable = 0;
clip[0].x = 0;
clip[0].y = 0;
clip[0].w = 50;
clip[0].h = 50;
clip[1].x = 50;
clip[1].y = 50;
clip[1].w = 100;
clip[1].h = 100;
clip[2].x = 100;
clip[2].y = 100;
clip[2].w = 150;
clip[2].h = 150;
clip[3].x = 150;
clip[3].y = 150;
clip[3].w = 200;
clip[3].h = 200;
screen = SDL_SetVideoMode(512,512,32,SDL_SWSURFACE);
background = IMG_Load("images/background.png");
gunshot_explosion_image = IMG_Load("images/gunshot_explosion.png");
MARS_image = IMG_Load("images/MARS.png");
MARS_bullet_image = IMG_Load("images/MARS_bullet.png");
schoolboy_image = IMG_Load("images/schoolboy.png");
};
void gunshot_explosion_action(int instance)
{
while (instance <= instance_body.gunshot_explosion)
{
if (gunshot_explosion[instance].exist == 0)
{
gunshot_explosion[instance].life = gunshot_explosion[instance].life + 1;
if (gunshot_explosion[instance].life > 7)
{gunshot_explosion[instance].exist = 1;};
applysurface(gunshot_explosion[instance].x-6,gunshot_explosion[instance].y-6,gunshot_explosion_image,screen);
};
instance = instance + 1;
};
};
#endif // INCLUDE_FILE_H_INCLUDED
MARS.h
#ifndef MARS_H_INCLUDED
#define MARS_H_INCLUDED
#include "include_file.h"
/*character functions*/
void MARS_action()
{
if (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
MARS.alive = 2;
quit = 0;
};
if (event.type == SDL_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_a:
if(MARS.x > 0){MARS.x = MARS.x - 16;}; break;
case SDLK_d:
if(MARS.x < 512){MARS.x = MARS.x + 16;}; break;
case SDLK_w:
if(MARS.y > 0){MARS.y = MARS.y - 16;}; break;
case SDLK_s:
if(MARS.y < 512){MARS.y = MARS.y + 16;}; break;
case SDLK_LEFT:
MARS.bullet = MARS.bullet + 1;
MARS_bullet[MARS.bullet].direction = 2;
MARS_bullet[MARS.bullet].x = MARS.x-25;
MARS_bullet[MARS.bullet].y = MARS.y;
instance_body.gunshot_explosion = instance_body.gunshot_explosion+1;
gunshot_explosion[instance_body.gunshot_explosion].x = MARS.x-25;
gunshot_explosion[instance_body.gunshot_explosion].y = MARS.y;
break;
case SDLK_RIGHT:
MARS.bullet = MARS.bullet + 1;
MARS_bullet[MARS.bullet].direction = 0;
MARS_bullet[MARS.bullet].x = MARS.x+25;
MARS_bullet[MARS.bullet].y = MARS.y;
instance_body.gunshot_explosion = instance_body.gunshot_explosion+1;
gunshot_explosion[instance_body.gunshot_explosion].x = MARS.x+25;
gunshot_explosion[instance_body.gunshot_explosion].y = MARS.y;
break;
case SDLK_UP:
MARS.bullet = MARS.bullet + 1;
MARS_bullet[MARS.bullet].direction = 1;
MARS_bullet[MARS.bullet].x = MARS.x;
MARS_bullet[MARS.bullet].y = MARS.y-25;
instance_body.gunshot_explosion = instance_body.gunshot_explosion+1;
gunshot_explosion[instance_body.gunshot_explosion].x = MARS.x;
gunshot_explosion[instance_body.gunshot_explosion].y = MARS.y-25;
break;
case SDLK_DOWN:
MARS.bullet = MARS.bullet + 1;
MARS_bullet[MARS.bullet].direction = 3;
MARS_bullet[MARS.bullet].x = MARS.x;
MARS_bullet[MARS.bullet].y = MARS.y+25;
instance_body.gunshot_explosion = instance_body.gunshot_explosion+1;
gunshot_explosion[instance_body.gunshot_explosion].x = MARS.x;
gunshot_explosion[instance_body.gunshot_explosion].y = MARS.y+25;
break;
case SDLK_ESCAPE: quit = 0; MARS.alive = 2; break;
};
};
};
};
void MARS_bullet_action(int instance)
{
while (instance <= MARS.bullet)
{
if (MARS_bullet[instance].exist == 0)
{
if (MARS_bullet[instance].direction == 0)
{MARS_bullet[instance].x = MARS_bullet[instance].x + 5;};
if (MARS_bullet[instance].direction == 1)
{MARS_bullet[instance].y = MARS_bullet[instance].y - 5;};
if (MARS_bullet[instance].direction == 2)
{MARS_bullet[instance].x = MARS_bullet[instance].x - 5;};
if (MARS_bullet[instance].direction == 3)
{MARS_bullet[instance].y = MARS_bullet[instance].y + 5;};
if (MARS_bullet[instance].x < 0 or MARS_bullet[instance].x > 512 or MARS_bullet[instance].y < 0 or MARS_bullet[instance].y > 512)
{MARS_bullet[instance].exist = 1;};
applysurface(MARS_bullet[instance].x-5, MARS_bullet[instance].y-5, MARS_bullet_image, screen);
};
instance = instance + 1;
};
};
#endif // MARS_H_INCLUDED
schoolboy.h
#ifndef SCHOOLBOY_H_INCLUDED
#define SCHOOLBOY_H_INCLUDED
#include "include_file.h"
void create_schoolboy(int positionx = 0, int positiony = 0)
{
instance_body.schoolboy_instance = instance_body.schoolboy_instance + 1;
positionx = rand() % 1;
positiony = rand() % 1;
if (positionx == 0 and positiony == 0)
{
schoolboy[instance_body.schoolboy_instance].x = 0;
schoolboy[instance_body.schoolboy_instance].y = 0;
};
if (positionx == 1 and positiony == 0)
{
schoolboy[instance_body.schoolboy_instance].x = 512;
schoolboy[instance_body.schoolboy_instance].y = 0;
};
if (positionx == 0 and positiony == 1)
{
schoolboy[instance_body.schoolboy_instance].x = 0;
schoolboy[instance_body.schoolboy_instance].y = 512;
};
if (positionx == 1 and positiony == 1)
{
schoolboy[instance_body.schoolboy_instance].x = 512;
schoolboy[instance_body.schoolboy_instance].y = 512;
};
};
void schoolboy_action(int instance, int bullet, int first_direction)
{
while (instance <= instance_body.schoolboy_instance)
{
first_direction = rand() % 1;
if (schoolboy[instance].exist == 0)
{
while (bullet <= MARS.bullet)
{
if (schoolboy[instance].x-12 >= MARS_bullet[bullet].x and MARS_bullet[bullet].x <= schoolboy[instance].x+12 and schoolboy[instance].y-12 >= MARS_bullet[bullet].y and MARS_bullet[bullet].y <= schoolboy[instance].y+12)
{
schoolboy[instance].exist = 1;
};
bullet = bullet + 1;
};
if (schoolboy[instance].walk_delay == 0)
{
if (first_direction == 0)
{
schoolboy[instance].walked = 0;
if (MARS.x > schoolboy[instance].x)
{
schoolboy[instance].x = schoolboy[instance].x + 16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[0]);
schoolboy[instance].walked = 1;
}
else if (MARS.x < schoolboy[instance].x)
{
schoolboy[instance].x = schoolboy[instance].x - 16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[2]);
schoolboy[instance].walked = 1;
};
if (schoolboy[instance].walked = 0)
{
if (MARS.y > schoolboy[instance].y)
{
schoolboy[instance].y = schoolboy[instance].y+16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[3]);
schoolboy[instance].walked = 1;
}
else if (MARS.y < schoolboy[instance].y)
{
schoolboy[instance].y = schoolboy[instance].y+16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[1]);
schoolboy[instance].walked = 1;
};
};
};
if (first_direction == 1)
{
schoolboy[instance].walked = 0;
if (MARS.y > schoolboy[instance].y)
{
schoolboy[instance].y = schoolboy[instance].y+16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[3]);
schoolboy[instance].walked = 1;
}
else if (MARS.y < schoolboy[instance].y)
{
schoolboy[instance].y = schoolboy[instance].y+16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[1]);
schoolboy[instance].walked = 1;
};
if (schoolboy[instance].walked = 0)
{
if (MARS.x > schoolboy[instance].x)
{
schoolboy[instance].x = schoolboy[instance].x + 16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[0]);
schoolboy[instance].walked = 1;
}
else if (MARS.x < schoolboy[instance].x)
{
schoolboy[instance].x = schoolboy[instance].x - 16;
applysurface(schoolboy[instance].x-25, schoolboy[instance].y-25, schoolboy_image, screen, &clip[2]);
schoolboy[instance].walked = 1;
};
};
};
schoolboy[instance].walk_delay = schoolboy[instance].walk_delay + 1;
}
else {schoolboy[instance].walk_delay = schoolboy[instance].walk_delay + 1;};
if (schoolboy[instance].walk_delay == 10){schoolboy[instance].walk_delay = 0;};
};
};
instance = instance + 1;
};
#endif // SCHOOLBOY_H_INCLUDED
All of my files are involved with each other, especially schoolboy.h, which is why I put them down. If you find the answer, can you explain why that's so. Any help appreciated!
Your instance = instance + 1 line at the end of schoolboy.h looks like it's outside the while loop that relies on it being incremented to eventually end.

Getting joystick input with Allegro 5.0.2

I'm new in Allegro 5, I've written some code with the few tutorials there are so far, but I cannot get the joystick sticks input.
Here the code, it is just two bars moving perpendicularly(and a very lazy approach, just swapped the x an y coordinates on the second bar).
#pragma comment (lib,"allegro-5.0.2-monolith-md-debug.lib")
#include <stdio.h>
#include <string>
#include <iostream>
#include <allegro5/allegro.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#define FPS 0xFF
#define SCREEN_W 1000
#define SCREEN_H 750
#define BAR_W 75
#define BAR_H 10
enum KEYS
{
KEY_LEFT, KEY_RIGHT
};
int main(int argc, char **argv)
{
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_JOYSTICK *joystick = NULL;
ALLEGRO_TIMER *timer = NULL;
ALLEGRO_BITMAP *bouncer = NULL;
float bouncer_x = SCREEN_W / 2.0 - BAR_W / 2.0;
float bouncer_y = SCREEN_H - BAR_H;
bool key[2] = {false, false};
bool redraw = true;
bool doexit = false;
if(!al_init())
{
fprintf(stderr, "failed to initialize allegro!\n");
return -1;
}
if(!al_install_keyboard())
{
fprintf(stderr, "failed to initialize the keyboard!\n");
return -1;
}
if(!al_install_joystick())
{
fprintf(stderr, "failed to initialize the joystick!\n");
}
al_reconfigure_joysticks();
joystick=al_get_joystick(al_get_num_joysticks()-1);
timer = al_create_timer(1.0 / FPS);
if(!timer)
{
fprintf(stderr, "failed to create timer!\n");
return -1;
}
display = al_create_display(SCREEN_W, SCREEN_H);
if(!display)
{
fprintf(stderr, "failed to create display!\n");
al_destroy_timer(timer);
return -1;
}
bouncer = al_create_bitmap(BAR_W, BAR_H);
if(!bouncer)
{
fprintf(stderr, "failed to create bouncer bitmap!\n");
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
al_set_target_bitmap(bouncer);
al_clear_to_color(al_map_rgb(0, 0, 255));
al_set_target_bitmap(al_get_backbuffer(display));
event_queue = al_create_event_queue();
if(!event_queue)
{
fprintf(stderr, "failed to create event_queue!\n");
al_destroy_bitmap(bouncer);
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));
al_register_event_source(event_queue, al_get_keyboard_event_source());
al_register_event_source(event_queue, al_get_joystick_event_source());
al_clear_to_color(al_map_rgb(0,0,0));
al_flip_display();
al_start_timer(timer);
while(!doexit)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
if(ev.type == ALLEGRO_EVENT_TIMER)
{
if(key[KEY_LEFT] && bouncer_x >= 2.0)
bouncer_x -= 2.0;
if(key[KEY_RIGHT] && bouncer_x <= SCREEN_W - BAR_W - 2.0)
bouncer_x += 2.0;
redraw = true;
}
else if(ev.type == ALLEGRO_EVENT_JOYSTICK_AXIS
&& ev.joystick.stick == 0
&& ev.joystick.axis == 0)
{
float joypos=ev.joystick.pos;
if(joypos<0 && bouncer_x >= 2.0)
bouncer_x-=joypos;
if(joypos>0 && bouncer_x <= SCREEN_W - BAR_W - 2.0)
bouncer_x+=joypos;
if(joypos=0)
bouncer_x=SCREEN_W/2;
}
else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE)
break;
else if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_LEFT:
key[KEY_LEFT] = true;
break;
case ALLEGRO_KEY_RIGHT:
key[KEY_RIGHT] = true;
break;
}
}
else if(ev.type == ALLEGRO_EVENT_KEY_UP)
{
switch(ev.keyboard.keycode)
{
case ALLEGRO_KEY_LEFT:
key[KEY_LEFT] = false;
break;
case ALLEGRO_KEY_RIGHT:
key[KEY_RIGHT] = false;
break;
case ALLEGRO_KEY_ESCAPE:
doexit = true;
break;
}
}
if(redraw && al_is_event_queue_empty(event_queue))
{
std::string str=al_get_joystick_name(joystick);
redraw = false;
al_clear_to_color(al_map_rgb(0,0,0));
al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0);
al_draw_bitmap(bouncer, bouncer_y, bouncer_x, 0);
std::cout << ev.joystick.pos << " ";
std::cout << str << " ";
std::cout << al_get_joystick_active(joystick) << std::endl;
al_flip_display();
}
}
al_destroy_bitmap(bouncer);
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(event_queue);
return 0;
}
Now, the trouble: ev.joystick.pos has a relatively static value (viewed trough MSVC2010 debugger), no matter if I have all the axis of my joystick at the max position.
Also, I don't know how to get the value of an specific axis of an specific stick. I managed to get the bar move only when an specific axis and stick changes, but not "how much" it changes.
Thanks in advance.
I can't see what you're doing wrong, but I got the controller working in my game, so maybe my code will shed some insight. By the way, I'm using an Xbox 360 controller. Actually, I'm using a GameStop brand 360 controller, so it's not technically official. Anyway, here's my relevant code (the full source is a monster):
if(ev.type == ALLEGRO_EVENT_JOYSTICK_AXIS){
if(ev.type == ALLEGRO_EVENT_JOYSTICK_AXIS){
if(ev.joystick.stick == 0){ //float joys[3][2]
joys[ev.joystick.stick][ev.joystick.axis] = ev.joystick.pos;
}
}
void SetPosition(){
int leftStick = 0;
int rightStick = 1;
int dPad = 2;
int x = 0;
int y = 1;
int z = 2;
bitmapX += joys[leftStick][x];
bitmapY += joys[leftStick][y];
}