#include "main.h"
SDL_Surface* screen; //The screen Surface
SDL_Surface* Snake_Body; //The snake surface (shape to draw)
SDL_Rect rectangle1; //Red border
SDL_Rect rectangle2; //Black Board
SDL_Event event; //Keyboard handling
direction facing;
std::vector<SDL_Rect> snake (3); //Snake body locations
SDL_Surface *LoadSnake()
{
SDL_Surface* temporary;
Uint32 rmask,gmask,bmask,amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
temporary = SDL_CreateRGBSurface(SDL_SWSURFACE,5,5,32,rmask,gmask,bmask,amask); //Make an empty surface
SDL_FillRect(temporary,NULL,SDL_MapRGB(screen->format,0,255,0)); //Fill it with color
return temporary; //return it
}
bool init()
{
if(SDL_Init(SDL_INIT_EVERYTHING) == -1 )
return false;
screen = SDL_SetVideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,SDL_SWSURFACE);
if(!screen)
return false;
SDL_WM_SetCaption("Snake v0.1",NULL);
Snake_Body = LoadSnake();
rectangle1.x = 0; //Red border
rectangle1.y = 0;
rectangle1.w = 500;
rectangle1.h = 500;
rectangle2.x = 25; //Black background
rectangle2.y = 25;
rectangle2.w = 450;
rectangle2.h = 450;
return true;
}
SDL_Surface *loadImage(const char* filename)
{
SDL_Surface *loadedImage = NULL;
SDL_Surface *optimizedImage = NULL;
loadedImage = SDL_LoadBMP(filename);
if (loadedImage)
{
optimizedImage = SDL_DisplayFormat(loadedImage);
SDL_FreeSurface(loadedImage);
}
return optimizedImage;
}
void pollInput()
{
while(SDL_PollEvent(&event))
{
if(event.type == SDL_QUIT)
{
end = true;
}
if(event.type == SDL_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
end = true; break;
case SDLK_UP:
facing = up; break;
case SDLK_DOWN:
facing = down; break;
case SDLK_RIGHT:
facing = right; break;
case SDLK_LEFT:
facing = left; break;
}
}
}
}
void Update()
{
for(unsigned int i = 1; i < snake.size(); i++)
{
snake[i] = snake[i-1];
}
switch(facing)
{
case up:
snake[0].y -= 5; break;
case down:
snake[0].y += 5; break;
case left:
snake[0].x -= 5; break;
case right:
snake[0].x += 5; break;
}
}
void SetUp()
{
snake[0].x = 250;
snake[0].y = 250;
snake[1].x = 250 + 15;
snake[1].y = 250;
snake[2].x = 250 + 15 + 15;
snake[2].y = 250;
}
void Draw()
{
unsigned short i;
int x;
SDL_FillRect(screen,&rectangle1,SDL_MapRGB(screen->format,255,0,0)); //Red Border
SDL_FillRect(screen,&rectangle2,SDL_MapRGB(screen->format,0,0,0)); //Black Board
for(i = 0; i < snake.size(); i++)
{
assert(SDL_BlitSurface(Snake_Body,NULL,screen,&snake[i]) == 0);
}
SDL_Flip(screen);
}
void Finish()
{
SDL_FreeSurface(Snake_Body);
SDL_Quit();
}
I have this code, it's a game of snake written in SDL I am working on, however, I seem to have a problem.
SDL draws the background just fine, but for some reason it won't draw the snake.
I set up an assert over there to check if the SDL_BlitSurface function succeeded, and it returns a normal value (0), even though nothing shows up on screen.
I set up the texture of the snake node to be a single green rectangle, Snake_Body, and I coded the locations that it needs to be drawn in a std::vector container, so I can call the SDL_BlitSurface() function on each of the elements in the vector, I have tracked the values and they are changing correctly, but for some reason the image stil isn't drawn. I have also attempted to replace my SDL_BlitSurface() function with a SDL_FillRect() in the same position, but it doesn't change anything.
EDIT: I have added my main loop below this edit:
#include "main.h"
bool end = false;
Uint32 time;
int main(int argc,char* argv[])
{
if(!init())
return 1;
SetUp();
time = SDL_GetTicks();
while(!end)
{
if(time+1000<SDL_GetTicks())
{
Update();
time = SDL_GetTicks();
}
pollInput();
Draw();
}
Finish();
return 0;
}
You don't appear to be doing any bounds checking on the snake's position to make sure it stays on the screen. So when it moves off the screen, it stays off and never comes back. My guess is that you aren't regulating the framerate properly, or you aren't regulating it at all(I would need to see your main loop), so the snake moves off the screen so fast that you never even see it.
What happens if you don't call the Update function?
If you posted the whole code then there's a call to SetUp missing. This won't set up the snake and it is probably somewhere outside the screen as the vector contains garbage. Also, even though SDL_BlitSurface ignores dstrect width and height, it's a good practice to initialize these to some meaningful values.
Related
#include<stdio.h>
#include<SDL2/SDL.h>
#include<SDL2/SDL_timer.h>
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
#define SPEED 250
#define FPS 60
int main(int argc,char* args[])
{
SDL_Surface *imageSurface = NULL;
SDL_Surface *windowSurface = NULL;
/*Initializing Graphics and Timer System*/
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER)!=0){
printf("Error Initializing SDL: %s\n",SDL_GetError());
return 1;
}
/*Creating a Window*/
SDL_Window* window = NULL;
window = SDL_CreateWindow("HELI",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
SCREEN_WIDTH,SCREEN_HEIGHT,
SDL_WINDOW_RESIZABLE);
windowSurface = SDL_GetWindowSurface(window);
if(window == NULL){
printf("Error Creating Window: %s\n",SDL_GetError());
SDL_Quit();
return 1;
}
/*Creating a Renderer, Which Sets Up the Graphics Hardware*/
Uint32 render_flags = SDL_RENDERER_ACCELERATED;
SDL_Renderer* renderer = NULL;
renderer = SDL_CreateRenderer(window,-1,render_flags);
if(renderer == NULL){
printf("Error Creating Renderer: %s\n",SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
/*Loading the Player image into memory using SDL Image Library Function*/
SDL_Surface* player = NULL;
player = SDL_LoadBMP("/home/betmon69/Documents/Heli/Images/player.bmp");
if(player == NULL){
printf("Error Creating Player\n");
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
/*Loading the Player Image Data Into the Graphics Hardware's Memory*/
SDL_Texture* player_tex = NULL;
player_tex = SDL_CreateTextureFromSurface(renderer,player);
SDL_FreeSurface(player);
if(player_tex == NULL){
printf("Error Creating Player Texture: %s\n",SDL_GetError());
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 1;
}
/*Structure to Hold the Position and Size of the Player*/
SDL_Rect dest;
/*Get the Dimensions of Player*/
SDL_QueryTexture(player_tex,NULL,NULL,&dest.w,&dest.h);
dest.w;
dest.h;
/* Start the Player in Center of Screen(ami nije korbo eta)*/
float x_pos = (SCREEN_WIDTH - dest.w)/2;
float y_pos = (SCREEN_HEIGHT - dest.h);
float x_vel = 0;
float y_vel = 0;
/*Keep Track of Which Inputs are given*/
int up = 0;
int down = 0;
int left = 0;
int right = 0;
/*Animation Loop*/
SDL_Event event;
imageSurface = SDL_LoadBMP("/home/betmon69/Documents/Heli/Images/background.bmp");
if(imageSurface == NULL){
printf("SDL Could Not Load Background! SDL Error: %s\n",SDL_GetError());
}
bool running = true;
while(running){
while(SDL_PollEvent(&event)){
switch(event.type){
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.scancode){
case SDL_SCANCODE_W:
case SDL_SCANCODE_UP:
up = 1;
break;
case SDL_SCANCODE_A:
case SDL_SCANCODE_LEFT:
left = 1;
break;
case SDL_SCANCODE_S:
case SDL_SCANCODE_DOWN:
down = 1;
break;
case SDL_SCANCODE_D:
case SDL_SCANCODE_RIGHT:
right = 1;
break;
}
break;
case SDL_KEYUP:
switch(event.key.keysym.scancode){
case SDL_SCANCODE_W:
case SDL_SCANCODE_UP:
up = 0;
break;
case SDL_SCANCODE_A:
case SDL_SCANCODE_LEFT:
left = 0;
break;
case SDL_SCANCODE_S:
case SDL_SCANCODE_DOWN:
down = 0;
break;
case SDL_SCANCODE_D:
case SDL_SCANCODE_RIGHT:
right = 0;
break;
}
break;
}
}
SDL_BlitSurface(imageSurface,NULL,windowSurface,NULL);
SDL_UpdateWindowSurface(window);
/*Determine the Velocity*/
x_vel = 0;
y_vel = 0;
if(up && !down) y_vel = -SPEED;
if(down && !up) y_vel = SPEED;
if(left && !right) x_vel = -SPEED;
if(right && !left) x_vel = SPEED;
/*Update Positions*/
x_pos += x_vel/60;
y_pos +=y_vel/60;
/*Collision Detection with Borders*/
if(x_pos<=0) x_pos = 0;
if(y_pos<=0) y_pos = 0;
if(x_pos>=SCREEN_WIDTH - dest.w) x_pos = SCREEN_WIDTH - dest.w;
if(y_pos>=SCREEN_HEIGHT - dest.h) y_pos = SCREEN_HEIGHT - dest.h;
/*Set the Positions in the Structure*/
dest.y = (int) y_pos;
dest.x = (int) x_pos;
/*Clear the Window*/
SDL_RenderClear(renderer);
/*Draw the Player to the Window*/
SDL_RenderCopy(renderer,player_tex,NULL,&dest);
SDL_RenderPresent(renderer);
SDL_Delay(1000/60);
}
/*Clean Up Resources Before Exiting*/
SDL_DestroyTexture(player_tex);
SDL_FreeSurface(imageSurface);
SDL_FreeSurface(windowSurface);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
So in my code you can see that i have created player which can freely roam around and collision also happens. I just want to create a background for the player i just have created. But the background doesn't create. I have used SDL_Surface and also used SDL_GetWindowSurface(). but the error i am getting is "Error Creating Renderer: Renderer already associated with window". What should i change to have a background for my player? Please Help.
I'm trying to make a simple Snake game. The self collision and a lot of things aren't ready. The problem is: Even with no errors, running just fine, changing "close()" to "endGame()" and reverting, rebuilding the entire program, i could not render anything with SDL_RenderCopy. You will see many unnecessary things in my code and some Brazilian-Portuguese comments, prepare yourself.
The image is a 16x16 png spritesheet, using the color #ff00ff as ColorKey. There are only 4 sprites in this spritesheet, respectively: Apple, Snake's Body, Snake's Head and Snake's Tail (still unused).
Whole code:
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
using namespace std;
const int CELL_SIZE = 16;
const int CELL_WIDTH = 16;
const int CELL_HEIGHT = 16;
const int SCREEN_WIDTH = CELL_SIZE * (CELL_WIDTH-1);
const int SCREEN_HEIGHT = CELL_SIZE * (CELL_HEIGHT-1);
SDL_Window* gWindow = NULL;
SDL_Renderer* gRenderer = NULL;
void loadTexture(string path);
SDL_Texture* spriteSheet = NULL;
void loadMedia();
void init();
class Snake {
int initialLength = 3; //from body (head incluse)
int length = initialLength;
int facing = DIR_UP;
//Head position in CELLS (multiplied for CELL_SIZE when drawed)
int x = 5;
int y = 5;
//UNUSED TEMPORARY COLORS - IGNORE
Uint8 color[3] = {0x22,0x88,0x44}; //Snake Color, em RGB
Uint8 headColor[3] = {0x11,0x44,0x44}; //Color for the Head of the Snek
int stepDelay = 60; //time in frames that the Snakes waits till move
int stepFramesRemaining = stepDelay;
int stepDelayReduction = 1; //reduces stepDelay every time the Snakes eats the apple
const int minStepDelay = 15; //the minimum delay
//For clipping the image (its an 16x16 png image)
const SDL_Rect clipHead = {0,8,8,8};
const SDL_Rect clipBody = {8,0,8,8};
const SDL_Rect clipTail = {8,8,8,8};
public:
enum direction { //direções nas quais a cobra pode se mover
DIR_UP,
DIR_RIGHT,
DIR_DOWN,
DIR_LEFT
};
/* The following var stores the entire Snake's body in an 2D Array. The number stored means how much "steps" it will survive.
When the value is zero, it means that there is no body in the place. The bodypart with value equivalent to "length" is the Head.
*/
int body[CELL_WIDTH][CELL_HEIGHT];
void init(); //initializes some vars
void tick(); //tick function
void stepFoward(); //moves Snake foward
void faceTo(int dir); //alters which direction Snake is faced
void eat(); //eats the apple
void draw(); //renders (or at least tries) to render the snake
int getLength(){
return length;
};
int getFacing(){
return facing;
};
} Snake;
class Food {
Uint8 color[3] = {0x85,0x22,0x10}; //RGB color of the Apple
bool visible = true;
public:
int x = 2;
int y = 2;
void respawn();
void destroy();
void draw();
} Food;
void Food::respawn(){
//teleports the apple to a random spot
x = rand() % (CELL_WIDTH-2);
y = rand() % (CELL_HEIGHT-2);
visible = true;
}
void Food::destroy(){
//Reset values
x = 0;
y = 0;
visible = false;
//resets
respawn();
}
void Food::draw(){
if(visible){
SDL_Rect rect = {x*CELL_SIZE,y*CELL_SIZE,CELL_SIZE,CELL_SIZE};
SDL_SetRenderDrawColor(gRenderer,color[0],color[1],color[2],0xff);
SDL_RenderFillRect(gRenderer, &rect);
}
}
void Snake::init(){
//Spawns in a vertical line
for(int i=0; i<length; i++){
body[x][y+i] = length-i;
}
}
void Snake::tick(){
if(stepFramesRemaining > 0){
stepFramesRemaining--;
} else {
//when 0, moves the snake
stepFramesRemaining = stepDelay;
stepFoward();
}
}
void Snake::eat(){
//increases the body size by 1
for(int i=0; i<CELL_HEIGHT; i++){
for(int j=0; j<CELL_WIDTH; j++){
if(body[j][i] > 0){
body[j][i]++;
}
}
}
length++;
if(stepDelay > minStepDelay){
stepDelay -= stepDelayReduction;
}
Food.destroy();
}
void Snake::draw(){
//SDL_SetRenderDrawColor(gRenderer,color[0],color[1],color[2],0xff);
SDL_Rect rect = {0,0,0,0}; //for later use
//Draws the body and head
for(int i=0; i<CELL_HEIGHT; i++){
for(int j=0; j<CELL_WIDTH; j++){
if(body[j][i] == length){
rect = {j*CELL_SIZE,i*CELL_SIZE,CELL_SIZE,CELL_SIZE};
SDL_SetRenderDrawColor(gRenderer,0x33,0xff,0x22,0xff);
SDL_RenderFillRect(gRenderer,&rect);
SDL_RenderCopy(gRenderer, spriteSheet, &clipHead, &rect);
} else if (body[j][i] > 0){
rect = {j*CELL_SIZE,i*CELL_SIZE,CELL_SIZE,CELL_SIZE};
//SDL_SetRenderDrawColor(gRenderer,color[0],color[1],color[2],0xff);
SDL_RenderCopyEx(gRenderer, spriteSheet, &clipBody, &rect, 0, NULL, SDL_FLIP_NONE);
SDL_SetRenderDrawColor(gRenderer,0x66,0xee,0x22,0xff);
SDL_RenderFillRect(gRenderer,&rect);
}
SDL_RenderFillRect(gRenderer,&rect);
}
}
//SDL_RenderFillRect(gRenderer,&rect);
}
void Snake::stepFoward(){
int headMoved = 0; //informs if the head already moved
//decreases the "body" lifespan and moves head
for(int i=0; i<CELL_HEIGHT; i++){
for(int j=0; j<CELL_WIDTH; j++){
if(body[j][i] > 0){
//Verifica se é a cabeça, para movê-la logo em seguida
if(body[j][i] == length && headMoved < 2){
//moves head position, looping if needed
switch(facing){
case DIR_UP:
if(y == 0){
body[x][CELL_HEIGHT-1] = length;
y = CELL_HEIGHT-1;
} else {
body[x][y-1] = length;
y--;
}
break;
case DIR_DOWN:
if(y == CELL_HEIGHT-2){
body[x][0] = length+1; //(+1 to avoid being subtracted twice)
y = 0;
} else {
body[x][y+1] = length+1;
y++;
}
break;
case DIR_LEFT:
if(x == 0){
body[CELL_WIDTH-1][y] = length;
x = CELL_WIDTH-1;
} else {
body[x-1][y] = length;
x--;
}
break;
case DIR_RIGHT:
if(x == CELL_WIDTH-2){
body[0][y] = length+1; //avoiding again the "-2" subtraction.
x = 0;
} else {
body[x+1][y] = length+1;
x++;
}
break;
}
headMoved++;
}
body[j][i]--; //decreases the "body" lifespan
}
}
}
//verifies if can eat (head in the same position as the apple)
if(x == Food.x && y == Food.y){
eat();
}
}
void Snake::faceTo(int dir){
facing = dir;
}
void init();
void close();
void init(){ //Initializes the game
gWindow = SDL_CreateWindow("· Snake ·", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );
if( gRenderer == NULL ){
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
}
int imgFlags = IMG_INIT_PNG;
if(!(IMG_Init(imgFlags) & imgFlags)){
cout << "IMG INIT error!" << endl;
}
loadMedia();
Snake.init();
}
void close(){ //Closes the program
SDL_DestroyTexture(spriteSheet);
spriteSheet = NULL;
SDL_DestroyRenderer(gRenderer);
gRenderer = NULL;
IMG_Quit();
SDL_Quit();
}
void loadTexture(string path){ //Almost the same function from LazyFoo tutorial
//The final texture
SDL_Texture* newTexture = NULL;
//Load image at specified path
SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else
{
//Color key image
SDL_SetColorKey( loadedSurface, SDL_TRUE, SDL_MapRGB( loadedSurface->format, 0xff, 0x00, 0xff));
//Create texture from surface pixels
newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface);
if( newTexture == NULL ){
printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
//Get rid of old loaded surface
SDL_FreeSurface( loadedSurface );
}
spriteSheet = newTexture;
}
void loadMedia(){ //loads everything (it will load sound too, when i make the sounds of course)
loadTexture("spritesheet.png");
if(spriteSheet == NULL){
cout << "ERRO" << endl;
}
}
void tick(){
Snake.tick();
}
void draw(){ //Render Function
//Background
SDL_SetRenderDrawColor(gRenderer, 0xee, 0xf2, 0xf0, 0xff);
SDL_RenderClear(gRenderer);
Snake.draw();
Food.draw();
//Aplica as alterações
SDL_RenderPresent(gRenderer);
}
int main(){
srand (time (NULL));
init();
bool quit = false;
SDL_Event e; //Event Handling
while(!quit){
while(SDL_PollEvent(&e) != 0){
if(e.type == SDL_QUIT){
quit = true;
} else if(e.type == SDL_KEYDOWN){
switch(e.key.keysym.sym){
case SDLK_UP:
Snake.faceTo(Snake.DIR_UP);
break;
case SDLK_DOWN:
Snake.faceTo(Snake.DIR_DOWN);
break;
case SDLK_LEFT:
Snake.faceTo(Snake.DIR_LEFT);
break;
case SDLK_RIGHT:
Snake.faceTo(Snake.DIR_RIGHT);
break;
}
}
}
//Tick function
tick();
//Renders everything
draw();
SDL_RenderCopy(gRenderer, spriteSheet, NULL, NULL);
//Slows down the program just a bit (its not a time based frame system... yet)
SDL_Delay(3);
}
close(); //ends
return 0;
}
The portion of code who should be working, but isn't:
//Draws the body and head
for(int i=0; i<CELL_HEIGHT; i++){
for(int j=0; j<CELL_WIDTH; j++){
if(body[j][i] == length){
rect = {j*CELL_SIZE,i*CELL_SIZE,CELL_SIZE,CELL_SIZE};
SDL_SetRenderDrawColor(gRenderer,0x33,0xff,0x22,0xff);
SDL_RenderFillRect(gRenderer,&rect);
SDL_RenderCopy(gRenderer, spriteSheet, &clipHead, &rect);
} else if (body[j][i] > 0){
rect = {j*CELL_SIZE,i*CELL_SIZE,CELL_SIZE,CELL_SIZE};
//SDL_SetRenderDrawColor(gRenderer,color[0],color[1],color[2],0xff);
SDL_RenderCopyEx(gRenderer, spriteSheet, &clipBody, &rect, 0, NULL, SDL_FLIP_NONE);
SDL_SetRenderDrawColor(gRenderer,0x66,0xee,0x22,0xff);
SDL_RenderFillRect(gRenderer,&rect);
}
SDL_RenderFillRect(gRenderer,&rect);
}
}
//SDL_RenderFillRect(gRenderer,&rect);
}
I'm currently having a problem with my pong game. I'm trying to smooth out the player movement (so it wont stutter so much when is moves, and no delay after first keypress)
This is my code so far, problem is while I've got the movement smoother the _paddle move too fast! and I don't now how to make it move slower!
Is there a way i can make the _paddle move slower or did i write the code wrong?
maingame.h
#pragma once
#include <iostream>
#include <SDL/SDL.h>
#include <string>
#include "maingame.h"
class maingame
{
public:
maingame();
~maingame();
//loads pictures
bool loadMedia(std::string path);
//init the system
void init();
//runs the game
void run();
//THE EPIC GAMELOOP
void gameloop();
//draw the screen
void draw();
void UserInput();
private:
//window
SDL_Window* _window;
//redenderer
SDL_Renderer* _rend;
//the screens surface
SDL_Surface* _screensurface;
//player, ai and the ball
SDL_Rect _paddle;
SDL_Rect _ai;
SDL_Rect _ball;
//checks if you pressed down the W or S button
bool keydown_w = false;
bool keydown_s = false;
//Event for the pall stuff
SDL_Event e;
};
maingame.c
#include "maingame.h"
/*
PONG V0.2
Black background - CHECK
paddle appear on screen - CHECK
other paddle appear on screen - CHECK
ball appear on screen - CHECK
move player paddle - CHECK
impossible to move outside of map - CHECK
movement smoother -
make ball go around -
collison with paddles -
keep scores -
show scores -
make a 2nd player chooseable -
*/
//screen width and height
const int SCREEN_WIDTH = 1024;
const int SCREEN_HEIGHT = 768;
maingame::maingame()
{
_window = nullptr;
_rend = nullptr;
}
maingame::~maingame()
{
}
void maingame::init()
{
SDL_Init(SDL_INIT_EVERYTHING);
}
void maingame::run()
{
init();
//creating a windows
_window = SDL_CreateWindow("PONG", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
//create the render
_rend = SDL_CreateRenderer(_window, -1, SDL_RENDERER_ACCELERATED);
//set out the player
_paddle.x = 100;
_paddle.y = (SCREEN_HEIGHT / 2) - 100;
_paddle.w = 20;
_paddle.h = 200;
//set out the ai
_ai.x = SCREEN_WIDTH - 100;
_ai.y = (SCREEN_HEIGHT / 2) - 100;
_ai.w = 20;
_ai.h = 200;
//set out the ball
_ball.x = SCREEN_WIDTH / 2 - 20;
_ball.y = (SCREEN_HEIGHT / 2) - 20;
_ball.w = 20;
_ball.h = 20;
draw();
gameloop();
}
void maingame::draw()
{
//make the render be black
SDL_SetRenderDrawColor(_rend, 0, 0, 0, 0);
//Clear the render with the color we set with SDL_SetRenderDrawColor, in this case black
SDL_RenderClear(_rend);
//make the next things we will render white
SDL_SetRenderDrawColor(_rend, 255, 255, 255, 0);
//make the paddle, ai and ball the color of SDL_SetRenderDrawColor, which is whites in this case
SDL_RenderFillRect(_rend, &_paddle);
SDL_RenderFillRect(_rend, &_ai);
SDL_RenderFillRect(_rend, &_ball);
//SDL_RenderDrawRect(_rend, &_paddle);
//Present the render, draw it to the screen
SDL_RenderPresent(_rend);
}
bool maingame::loadMedia(std::string path)
{
//Loading success flag
bool success = true;
SDL_Surface* pic;
//Load splash image
pic = SDL_LoadBMP(path.c_str());
if (pic == NULL)
{
printf("Unable to load image %s! SDL Error: %s\n", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError());
success = false;
}
return success;
}
void maingame::gameloop()
{
const Uint8 *keys = SDL_GetKeyboardState(NULL);
bool keydown_w = false;
bool keydown_s = false;
while (true)
{
while (SDL_PollEvent(&e) != 0)
{
//pressed the X, quit the program
if (e.type == SDL_QUIT)
{
exit(1);
}
UserInput();
}
UserInput();
draw();
}
}
void maingame::UserInput()
{
float lol = 0;
//Pressed a key!
if (e.type == SDL_KEYDOWN)
{
//pressed W, move the player
if (e.key.keysym.sym == SDLK_w)
{
keydown_w = true;
}
//pressed S, move the player
else if (e.key.keysym.sym == SDLK_s)
{
keydown_s = true;
}
}
if (e.type == SDL_KEYUP)
{
std::cout << keydown_w << std::endl;
if (e.key.keysym.sym == SDLK_w)
keydown_w = false;
if (e.key.keysym.sym == SDLK_s)
keydown_s = false;
}
if (keydown_w)
{
if (_paddle.y > 1)
{
_paddle.y -= 1;
}
std::cout << keydown_w << std::endl;
}
if (keydown_s)
{
if (_paddle.y < SCREEN_HEIGHT - _paddle.h)
{
_paddle.y += 1;
}
}
}
It maybe bad programming practice to do so but the only way I would see getting around your problem is to add an SDL_Delay() in your gameloop function. I would suggest you use it as a temporary fix until you find an alternative solution. Hope this helps.
I'm working on a PONG clone and just on the title screen. I have a class to work the title screen loop of the state machine and it uses very little, only a single sprite and a single true type font message. But when I call the function to render the message onto the SDL_Surface, it throws my program into whack. The error I receive is Unhandled exception at 0x6F4C2A9D (SDL_ttf.dll) in Pong.exe: 0xC0000005: Access violation reading location 0x00000000. Usually this means that I didn't initialize something or didn't define it in the class definition or something, but it all seems in order. So I'll post the code here in hopes that someone sees what's up with the render function or the bits surrounding it.
To be perfectly clear the exception is thrown on this line:
Title_Message = TTF_RenderText_Solid(font, "PONG", color);
//start code
/*CLASSES*/
class GameState
{
public:
virtual void events() = 0;
virtual void logic() = 0;
virtual void render() = 0;
virtual ~GameState(){};
};
class Button
{
public:
SDL_Rect button_clip[2];
SDL_Rect button;
SDL_Surface *button_sprite = NULL;
Button();
};
class Title : public GameState
{
private:
SDL_Surface *Title_Message = NULL;
SDL_Rect *clip;
Button Title_Button;
public:
void events();
void logic();
void render();
Title();
~Title();
};
/*FONTS*/
SDL_Color color = { 255, 255, 255 };
TTF_Font *font = NULL;
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);
//check screen
if (screen == NULL)
{
return false;
}
//init TTF
if (TTF_Init() == -1)
{
return false;
}
//set window caption
SDL_WM_SetCaption("PONG", NULL);
//if evetything worked
return true;
}
//load files
bool load_files()
{
font = TTF_OpenFont("PIXELITE.ttf", 45);
if (font == NULL)
{
return false;
}
return true;
}
/*CLASS DEFINITIONS*/
Button::Button()
{
}
Title::Title()
{
Title_Message = TTF_RenderText_Solid(font, "PONG", color);
Title_Button.button_sprite = load_image("Start.png");
Title_Button.button.x = 200;
Title_Button.button.y = 350;
Title_Button.button.w = 100;
Title_Button.button.h = 50;
//clips not hover
Title_Button.button_clip[0].x = 0;
Title_Button.button_clip[0].y = 0;
Title_Button.button_clip[0].w = 100;
Title_Button.button_clip[0].h = 50;
//clips hover
Title_Button.button_clip[1].x = 0;
Title_Button.button_clip[1].y = 50;
Title_Button.button_clip[1].w = 100;
Title_Button.button_clip[1].h = 50;
}
Title::~Title()
{
SDL_FreeSurface(Title_Message);
SDL_FreeSurface(Title_Button.button_sprite);
}
void Title::events()
{
int x = 0;
int y = 0;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_MOUSEMOTION)
{
x = event.motion.x;
y = event.motion.y;
if ((x > Title_Button.button.x) && (x < (Title_Button.button.x + Title_Button.button.w)) && (y > Title_Button.button.y) && (y < (Title_Button.button.y + Title_Button.button.h)))
{
clip = &Title_Button.button_clip[1];
}
else
{
clip = &Title_Button.button_clip[0];
}
}
if (event.type == SDL_QUIT)
{
quit = true;
}
}
}
void Title::logic()
{
}
void Title::render()
{
apply_surface(Title_Button.button.x, Title_Button.button.y, Title_Button.button_sprite, screen, clip);
apply_surface((SCREEN_WIDTH - Title_Message->w) / 2, 100, Title_Message, screen);
}
Anybody got an idea? Thanks!
I will post my suggestions from the comments as an actual answer:
The trouble-causing line Title_Message = TTF_RenderText_Solid(font, "PONG", color); refers to the global variable font of type TTF_Font*. The line is also part of the constructor of the class Title.
main looks like this:
int main(int argc, char* args[])
{
//init SDL
init();
//load everything
load_files();
currentState = new Title;
//...
font is initialized to NULL at declaration, an actual object is assigned only in load_files() which is executed at the beginning of main before Title is the first time instantiated.
So load_files() has to assign a valid pointer to font, otherwise the next line in main will cause an access violation.
load_files() provides a return value depending on whether creating and assigning this object was successful. However main never checks for this value and thus it is not guaranteed that font is a valid pointer.
As knefcy pointed out the problem was a wrong filename in load_files().
I'm self learning programming using various online tutorials and a couple of books. Currently it's C++. I've done a bit of OpenGL and SDL in the last few days.
I have a small program that creates a wall to stop a small square from passing through it.
Here's my code:
//
// main.cpp
// SDL_Template
//
// The headers
#include <stdlib.h>
#include <string>
// SDL headers
#include <SDL/SDL.h>
#include "SDL_image/SDL_image.h"
//#include "SDL/SDL_ttf.h"
//#include "SDL/SDL_mixer.h"
// Other headers
#include <OpenGL/gl3.h>
// Screen attributes
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;
// The frame rate
const int FRAMES_PER_SECOND = 20;
// The attributes of the square
const int SQUARE_WIDTH = 20;
const int SQUARE_HEIGHT = 20;
// The surfaces
SDL_Surface *square = NULL;
SDL_Surface *screen = NULL;
// The event structure
SDL_Event event;
// The wall
SDL_Rect wall;
// The square
class Square
{
private:
// The collision box of the square
SDL_Rect box;
// The velocity of the square
int xVel, yVel;
public:
// Initializes the variables
Square();
// Takes key presses and adjusts the square's velocity
void handle_input();
// Moves the square
void move();
// Shows the square on the screen
void show();
};
//The timer
class Timer
{
private:
// The clock time when the timer started
int startTicks;
// The ticks stored when the timer was paused
int pausedTicks;
// The timer status
bool paused;
bool started;
public:
// Initializes variables
Timer();
// The various clock actions
void start();
void stop();
void pause();
void unpause();
// Gets the timer's time
int get_ticks();
// Checks the status of the timer
bool is_started();
bool is_paused();
};
SDL_Surface *load_image(std::string filename)
{
// The image that's loaded
SDL_Surface* loadedImage = NULL;
// The optimized surface that will be used
SDL_Surface* optimizedImage = NULL;
// Load the image
loadedImage = IMG_Load(filename.c_str());
// If the image loaded
if (loadedImage != NULL)
{
// Create an optimized surface
optimizedImage = SDL_DisplayFormat(loadedImage);
// Free the old surface
SDL_FreeSurface(loadedImage);
// If the surface was optimized
if (optimizedImage != NULL)
{
// Color key surface
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF));
}
}
// Return the optimized surface
return optimizedImage;
}
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL)
{
// Holds offsets
SDL_Rect offset;
// Get offsets
offset.x = x;
offset.y = y;
// Blit
SDL_BlitSurface(source, clip, destination, &offset);
}
bool check_collision(SDL_Rect A, SDL_Rect B)
{
// The sides of the rectangles
int leftA, leftB;
int rightA, rightB;
int topA, topB;
int bottomA, bottomB;
// Calculate the sides of rect A
leftA = A.x;
rightA = A.x + A.w;
topA = A.y;
bottomA = A.y + A.h;
// Calculate the sides of rect B
leftB = B.x;
rightB = B.x + B.w;
topB = B.y;
bottomB = B.y + B.h;
// If any of the sides from A are outside of B
if( bottomA <= topB )
{
return false;
}
if( topA >= bottomB )
{
return false;
}
if( rightA <= leftB )
{
return false;
}
if( leftA >= rightB )
{
return false;
}
// If none of the sides from A are outside B
return true;
}
bool init()
{
// Initialize all SDL subsystems
if (SDL_Init( SDL_INIT_EVERYTHING ) == -1)
{
return false;
}
// Set up the screen
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
// If there was an error in setting up the screen
if (screen == NULL)
{
return false;
}
// Set the window caption
SDL_WM_SetCaption("Move the Square", NULL);
// If everything initialized fine
return true;
}
bool load_files()
{
// Load the square image
square = load_image("square.bmp");
// If there was a problem in loading the square
if (square == NULL)
{
return false;
}
// If everything loaded fine
return true;
}
void clean_up()
{
// Free the surface
SDL_FreeSurface(square);
// Quit SDL
SDL_Quit();
}
Square::Square()
{
// Initialize the offsets
box.x = 0;
box.y = 0;
// Set the square's dimentions
box.w = SQUARE_WIDTH;
box.h = SQUARE_HEIGHT;
// Initialize the velocity
xVel = 0;
yVel = 0;
}
void Square::handle_input()
{
// If a key was pressed
if (event.type == SDL_KEYDOWN)
{
//Adjust the velocity
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel -= SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel += SQUARE_WIDTH / 2; break;
}
}
// If a key was released
else if (event.type == SDL_KEYUP)
{
//Adjust the velocity
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel += SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel -= SQUARE_WIDTH / 2; break;
}
}
}
void Square::move()
{
// Move the square left or right
box.x += xVel;
// If the square went too far to the left or right or has collided with the wall
if (( box.x < 0 ) || ( box.x + SQUARE_WIDTH > SCREEN_WIDTH ) || ( check_collision(box, wall)))
{
// Move back
box.x -= xVel;
}
// Move the square up or down
box.y += yVel;
// If the square went too far up or down or has collided with the wall
if (( box.y < 0 ) || ( box.y + SQUARE_HEIGHT > SCREEN_HEIGHT) || (check_collision(box, wall)))
{
// Move back
box.y -= yVel;
}
}
void Square::show()
{
// Show the square
apply_surface(box.x, box.y, square, screen);
}
Timer::Timer()
{
// Initialize the variables
startTicks = 0;
pausedTicks = 0;
paused = false;
started = false;
}
void Timer::start()
{
// Start the timer
started = true;
// Unpause the timer
paused = false;
// Get the current clock time
startTicks = SDL_GetTicks();
}
void Timer::stop()
{
// Stop the timer
started = false;
// Unpause the timer
paused = false;
}
void Timer::pause()
{
// If the timer is running and isn't already paused
if ((started == true) && (paused == false))
{
// Pause the timer
paused = true;
// Calculate the paused ticks
pausedTicks = SDL_GetTicks() - startTicks;
}
}
void Timer::unpause()
{
// If the timer is paused
if (paused == true)
{
// Unpause the timer
paused = false;
// Reset the starting ticks
startTicks = SDL_GetTicks() - pausedTicks;
// Reset the paused ticks
pausedTicks = 0;
}
}
int Timer::get_ticks()
{
// If the timer is running
if (started == true)
{
// If the timer is paused
if (paused == true)
{
// Return the number of ticks when the timer was paused
return pausedTicks;
}
else
{
// Return the current time minus the start time
return SDL_GetTicks() - startTicks;
}
}
// If the timer isn't running
return 0;
}
bool Timer::is_started()
{
return started;
}
bool Timer::is_paused()
{
return paused;
}
int main(int argc, char* args[])
{
// Quit flag
bool quit = false;
// The square
Square mySquare;
// The frame rate regulator
Timer fps;
// Initialize
if( init() == false )
{
return 1;
}
// Load the files
if (load_files() == false)
{
return 1;
}
// Set the wall
wall.x = 300;
wall.y = 40;
wall.w = 40;
wall.h = 400;
// While the user hasn't quit
while (quit == false)
{
// Start the frame timer
fps.start();
// While there are events to handle
while (SDL_PollEvent(&event))
{
// Handle events for the square
mySquare.handle_input();
// If the user has Xed out the window
if (event.type == SDL_QUIT)
{
// Quit the program
quit = true;
}
}
// Move the square
mySquare.move();
// Fill the screen white
SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF));
// Show the wall
SDL_FillRect (screen, &wall, SDL_MapRGB(screen->format, 0x77, 0x77, 0x77));
// Show the square on the screen
mySquare.show();
// Update the screen
if (SDL_Flip(screen) == -1)
{
return 1;
}
// Cap the frame rate
if (fps.get_ticks() < 1000 / FRAMES_PER_SECOND)
{
SDL_Delay((1000 / FRAMES_PER_SECOND) - fps.get_ticks());
}
}
// Clean up
clean_up();
return 0;
}
I completely understand how this site works, so I'm not asking you to check my code. My code compiles in both Xcode 4.5 and Visual Studio 2010. In Xcode it compiles, but throws some warnings up (although it still builds), but nothing happens when it's run. However in Visual Studio 2012, it compiles, with no warnings and runs successfully.
I have searched here and the C++/SDL forums/help pages, but I haven't found any similar cases.
Why may this be? Seems it runs in Visual Studio 2010, I'm confident it isn't the code...
In case you were wondering the warnings flagged up in Xcode are:
229 enumeration values not handled in switch: 'SDLK_UNKNOWN','SDLK_BACKSPACE','SDLK_TAB'...
This is highlighted on the switch (event.key.keysym.sym) line of code.
So my questions are:
What kind of problems could case this warning error?
Are there any commonly know issues with programs working in Visual Studio and not Xcode?
I'm guessing (it seems I can't find anything about it) it's a setting somewhere that I haven't spotted...
I apologise for the length of this.
You are not handling all the possible choices in your switch statement. If this is what you intended then you can remove the warning by using the default case like the following:
switch (event.key.keysym.sym)
{
case SDLK_UP: yVel -= SQUARE_HEIGHT / 2; break;
case SDLK_DOWN: yVel += SQUARE_HEIGHT / 2; break;
case SDLK_LEFT: xVel -= SQUARE_WIDTH / 2; break;
case SDLK_RIGHT: xVel += SQUARE_WIDTH / 2; break;
default: break;
}
Xcode is simply warning you that you are not handling all possible values for the event.key.keysym.sym enumeration. Since I doubt you want to handle ever single different type of key press, this isn't a problem, as I would maybe see if I could turn down the warning level to suppress these warnings.
As for the program not running successfully when built by Xcode, I don't know. Perhaps SDL is set up in a different way?