When I ran the following code, I expected a result where pressing one of three buttons would each trigger a matching state that would render a matching image adjacent to those buttons, allowing me to rotate through fresh images at leisure with each successive button press.
Instead of that happy scenario, any initial button press skips right to the last image...or does nothing...or renders a blank white screen depending on how I fiddle with my placement of the initial state declaration and whether I place the state switch within or without the event handling switch. The whole system breaks and stops dead in its tracks. What is going on, and how do I fix it?
#include <string>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "cleanup.h"
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect* clip = NULL;
const int LONGBUTTON_HEIGHT = 128;
const int LONGBUTTON_WIDTH = 256;
int Screen_Width = 640;
int Screen_Height = 480;
int mouse_x;
int mouse_y;
int alphabutton_x = 0;
int alphabutton_y = 5;
int alphabutton_h = Screen_Width / 10;
int alphabutton_w = Screen_Width / 5;
int betabutton_x = 0;
int betabutton_y = 0.5 * (Screen_Width / 5) + 5;
int betabutton_h = Screen_Width / 10;
int betabutton_w = Screen_Width / 5;
int gammabutton_x = 0;
int gammabutton_y = 1 * (Screen_Width / 5) + 5;
int gammabutton_h = Screen_Width / 10;
int gammabutton_w = Screen_Width / 5;
int alpha_x = Screen_Width / 5;
int alpha_y = 0;
int alpha_h = Screen_Height;
int alpha_w = (4* Screen_Width)/5;
int beta_x = Screen_Width / 5;
int beta_y = 0;
int beta_h = Screen_Height;
int beta_w = (4* Screen_Width)/5;
int gamma_x = Screen_Width / 5;
int gamma_y = 0;
int gamma_h = Screen_Height;
int gamma_w = (4* Screen_Width)/5;
enum alphaButtonSprite {ALPHA_DEFAULT, ALPHA_HOVER, ALPHA_INACTIVE, ALPHA_PRESSED, ALPHA_TOTAL};
enum betaButtonSprite {BETA_DEFAULT, BETA_HOVER, BETA_INACTIVE, BETA_PRESSED, BETA_TOTAL};
enum gammaButtonSprite {GAMMA_DEFAULT, GAMMA_HOVER, GAMMA_INACTIVE, GAMMA_PRESSED, GAMMA_TOTAL};
enum State {ALPHA_STATE, BETA_STATE, GAMMA_STATE};
State state;
SDL_Texture* loadTexture(const std::string& file, SDL_Renderer* renderer)
{
SDL_Texture* texture = IMG_LoadTexture(renderer, file.c_str());
return texture;
}
void renderTexture(SDL_Texture* texture, SDL_Renderer* renderer, SDL_Rect dest,
SDL_Rect* clip = nullptr)
{
SDL_RenderCopy(renderer, texture, clip, &dest);
}
void renderTexture(SDL_Texture* texture, SDL_Renderer* renderer, int x, int y, int h, int w,
SDL_Rect* clip = nullptr)
{
SDL_Rect dest;
dest.x = x;
dest.y = y;
dest.h = h;
dest.w = w;
renderTexture(texture, renderer, dest, clip);
}
// Main Function
int main(int, char**)
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("New Window", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, Screen_Width, Screen_Height, SDL_WINDOW_RESIZABLE);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_Texture* longbutton_image = loadTexture("longbuttonSpriteSheet.png", renderer);
SDL_Texture* alpha_image = loadTexture("alphaImage.png", renderer);
SDL_Texture* beta_image = loadTexture("betaImage.png", renderer);
SDL_Texture* gamma_image = loadTexture("gammaImage.png", renderer);
state = BETA_STATE;
SDL_Rect alpha_clips[alphaButtonSprite::ALPHA_TOTAL];
for (int i = 0; i < alphaButtonSprite::ALPHA_TOTAL; i++)
{
alpha_clips[i].x = i * LONGBUTTON_WIDTH;
alpha_clips[i].y = 0;
alpha_clips[i].w = LONGBUTTON_WIDTH;
alpha_clips[i].h = LONGBUTTON_HEIGHT;
}
int usealpha_Clip = ALPHA_DEFAULT;
SDL_Rect beta_clips[betaButtonSprite::BETA_TOTAL];
for (int i = 0; i < betaButtonSprite::BETA_TOTAL; i++)
{
beta_clips[i].x = i * LONGBUTTON_WIDTH;
beta_clips[i].y = 4 * LONGBUTTON_HEIGHT;
beta_clips[i].w = LONGBUTTON_WIDTH;
beta_clips[i].h = LONGBUTTON_HEIGHT;
}
int usebeta_Clip = BETA_DEFAULT;
SDL_Rect gamma_clips[gammaButtonSprite::GAMMA_TOTAL];
for (int i = 0; i < gammaButtonSprite::GAMMA_TOTAL; i++)
{
gamma_clips[i].x = i * LONGBUTTON_WIDTH;
gamma_clips[i].y = 5 * LONGBUTTON_HEIGHT;
gamma_clips[i].w = LONGBUTTON_WIDTH;
gamma_clips[i].h = LONGBUTTON_HEIGHT;
}
int usegamma_Clip = GAMMA_DEFAULT;
SDL_Event e;
bool quit = false;
while (!quit)
{
while (SDL_PollEvent(&e))
{
switch (e.type)
{
case SDL_MOUSEBUTTONDOWN:
mouse_x = e.button.x;
mouse_y = e.button.y;
if ((mouse_x <= (alphabutton_x + alphabutton_w)) && (mouse_x > alphabutton_x) &&
(mouse_y <= (alphabutton_y + alphabutton_h)) && (mouse_y > alphabutton_y))
usealpha_Clip = ALPHA_PRESSED;
state = ALPHA_STATE;
if ((mouse_x <= (betabutton_x + betabutton_w)) && (mouse_x > betabutton_x) &&
(mouse_y <= (betabutton_y + betabutton_h)) && (mouse_y > betabutton_y))
usebeta_Clip = BETA_PRESSED;
state = BETA_STATE;
if ((mouse_x <= (gammabutton_x + gammabutton_w)) && (mouse_x > gammabutton_x) &&
(mouse_y <= (gammabutton_y + gammabutton_h)) && (mouse_y > gammabutton_y))
usegamma_Clip = GAMMA_PRESSED;
state = GAMMA_STATE;
break;
}
}
switch (state)
{
case ALPHA_STATE:
SDL_RenderClear(renderer);
renderTexture(longbutton_image, renderer, alphabutton_x, alphabutton_y, alphabutton_h, alphabutton_w, &alpha_clips[usealpha_Clip]);
renderTexture(longbutton_image, renderer, betabutton_x, betabutton_y, betabutton_h, betabutton_w, &beta_clips[usebeta_Clip]);
renderTexture(longbutton_image, renderer, gammabutton_x, gammabutton_y, gammabutton_h, gammabutton_w, &gamma_clips[usegamma_Clip]);
renderTexture(alpha_image, renderer, alpha_x, alpha_y, alpha_h, alpha_w, nullptr);
SDL_RenderPresent(renderer);
break;
case BETA_STATE:
SDL_RenderClear(renderer);
renderTexture(longbutton_image, renderer, alphabutton_x, alphabutton_y, alphabutton_h, alphabutton_w, &alpha_clips[usealpha_Clip]);
renderTexture(longbutton_image, renderer, betabutton_x, betabutton_y, betabutton_h, betabutton_w, &beta_clips[usebeta_Clip]);
renderTexture(longbutton_image, renderer, gammabutton_x, gammabutton_y, gammabutton_h, gammabutton_w, &gamma_clips[usegamma_Clip]);
renderTexture(beta_image, renderer, beta_x, beta_y, beta_h, beta_w, nullptr);
SDL_RenderPresent(renderer);
break;
case GAMMA_STATE:
SDL_RenderClear(renderer);
renderTexture(longbutton_image, renderer, alphabutton_x, alphabutton_y, alphabutton_h, alphabutton_w, &alpha_clips[usealpha_Clip]);
renderTexture(longbutton_image, renderer, betabutton_x, betabutton_y, betabutton_h, betabutton_w, &beta_clips[usebeta_Clip]);
renderTexture(longbutton_image, renderer, gammabutton_x, gammabutton_y, gammabutton_h, gammabutton_w, &gamma_clips[usegamma_Clip]);
renderTexture(gamma_image, renderer, gamma_x, gamma_y, gamma_h, gamma_w, nullptr);
SDL_RenderPresent(renderer);
break;
}
}
//Destroy the various items
cleanup(longbutton_image, alpha_image, beta_image, gamma_image, renderer, window);
IMG_Quit();
SDL_Quit();
return 0;
}
Found the answer to this one. In the mousebuttondown event switch cases, just put the state code before the useclip code. Why it makes a difference, I don't know, but it works. Cough...Also, doing it in the mousebuttonup switch cases instead of mousebuttondown works even better.
Related
I recently refactored my SDL2 C++ code using structs. It compiles and runs fine (using Visual Studio 2019), but is now throwing out an inconsistent warning:
C26496 Variable 'Graphic::X' is uninitialized. Always initialize a member variable.
This repeats for X = h, w, x, and y for the lines of code representing the renderTexture function. However, the warning does not show up for the mouseOverRect function that comes prior, both of which use Graphic struct variables in the exact same way.
I have included the relevant parts of my code below. I'm trying to figure out what caused the warning and why it didn't repeat for both functions?
header file
int mouse_x;
int mouse_y;
struct Graphic
{
std::string name;
std::string type;
int x;
int y;
int h;
int w;
};
source file
//Initialization
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Rect* clip = NULL;
//Log Error Function
void logSDLError(std::ostream &os, const std::string &msg)
{
os << msg << " error: " << SDL_GetError() << std::endl;
}
//Mouse Over Rectangle Function
bool mouseOverRect(int x, int y, Graphic &graphic)
{
if ((x <= graphic.x + graphic.w) && (x > graphic.x) &&
(y <= graphic.y + graphic.h) && (y > graphic.y))
return true;
else
return false;
//Render Texture at Destination Function
void renderTexture(SDL_Texture* texture, SDL_Renderer* renderer, Graphic &graphic,
SDL_Rect *clip = nullptr)
{
SDL_Rect dest;
dest.x = graphic.x;
dest.y = graphic.y;
dest.h = graphic.h;
dest.w = graphic.w;
SDL_RenderCopy(renderer, texture, clip, &dest);
}
// Main Function
int main(int, char**)
{
//Start up SDL
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
logSDLError(std::cout, "Cannot initialize SDL video.");
}
//Setup window and renderer
SDL_Window *window = SDL_CreateWindow("Dragon Hunt", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, Screen_Width, Screen_Height, SDL_WINDOW_RESIZABLE);
if (window == nullptr)
{
logSDLError(std::cout, "Cannot create window.");
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == nullptr)
{
logSDLError(std::cout, "Cannot create renderer.");
}
struct Graphic createbutton;
createbutton.name = "Create Forest";
createbutton.type = "longbutton";
createbutton.x = 0;
createbutton.y = 1 * (Screen_Width / 5) + 5;
createbutton.h = Screen_Width / 10;
createbutton.w = Screen_Width / 5;
SDL_Event e;
//For tracking if we want to quit
bool quit = false;
while (!quit) {
while (SDL_PollEvent(&e))
{
switch (e.type)
{
case SDL_MOUSEMOTION:
mouse_x = e.motion.x;
mouse_y = e.motion.y;
if (mouseOverRect(mouse_x, mouse_y, createbutton))
useCreate_Clip = CREATE_HOVER;
else
useCreate_Clip = CREATE_DEFAULT;
break;
}
renderTexture(longbutton_image, renderer, createbutton, &create_clips[useCreate_Clip]);
}
None of your structure's members are initialized. They are assigned to after initialization would have been done.
Initialize your structure when you declare it, something like
Graphic createbutton {
"Create Forest",
"longbutton",
0,
1 * (Screen_Width / 5) + 5,
Screen_Width / 10,
Screen_Width / 5
};
Note that you don't need the struct keyword here.
I started writing a little game but something with the image is not working. They're working fine at the beginning but after some moments there become black and then they disappear.
Don't be worried about the long code the relevant things with the images happen mostly in the following methods: build_mode_draw() and play_mode_draw().
I tested the program with a blue cube instead of a image and it worked fine
Probably I don't really understand how the image gets loaded
#include <SDL2/SDL.h>
#define WindowWidth 1500
#define WindowHight 800
#define ArrayGrosseBuildMode 100
#define StartFensterBlockmenge 10 // in Plockgröße bezüglich der kleineren Achse
bool end = false;
bool programm_part_run = true;
unsigned int play_mode_speed = 0;
unsigned int counter;
unsigned int counter_2;
unsigned int counter_3;
unsigned int blocksize;
unsigned int blocks_fit_in_X;
unsigned int blocks_fit_in_Y;
unsigned int play_mode_blockamount;
//unsigned int blockamount = 0;
bool build_mode_block_pos[ArrayGrosseBuildMode][ArrayGrosseBuildMode];
unsigned int play_mode_block_pos_X[WindowWidth]; // Fächer beschreiben
unsigned int play_mode_block_pos_Y[WindowHight]; // ||
//mouse variables
unsigned short int pressed_mouse_button = 0; // 0 = no , 1 = left , mouse Button pressed
unsigned int MouseX;
unsigned int MouseY;
//keyboard variables
//set window
SDL_Window* window = NULL;
//set renderer
SDL_Renderer* renderer = NULL;
//set event
SDL_Event event;
void input()
{
SDL_PollEvent(&event);
// reset variables
pressed_mouse_button = 0; // set to no mouse button pressed
switch(event.type)
{
case SDL_QUIT:
end = true;
programm_part_run = false;
break;
case SDL_MOUSEMOTION:
MouseX = event.motion.x;
MouseY = event.motion.y;
break;
case SDL_MOUSEBUTTONDOWN:
switch(event.button.button)
{
case SDL_BUTTON_LEFT:
pressed_mouse_button = 1;
break;
}
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_SPACE:
programm_part_run = false;
break;
}
}
}
void put_build_mode_grid_in_renderer()
{
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
for(counter = 0; counter <= blocks_fit_in_Y; counter = counter + 1)
{
SDL_RenderDrawLine(renderer,0,counter * blocksize,blocks_fit_in_X*blocksize,counter * blocksize);
}
for(counter = 0; counter <= blocks_fit_in_X; counter = counter + 1)
{
SDL_RenderDrawLine(renderer,counter * blocksize,0,counter * blocksize,blocks_fit_in_Y*blocksize);
}
}
void build_mode_draw()
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 0);
SDL_RenderClear(renderer);
put_build_mode_grid_in_renderer();
SDL_Surface * image = SDL_LoadBMP("stealcube.bmp");
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,image);
SDL_FreeSurface(image);
for(counter = 0; counter <= blocks_fit_in_X; counter = counter + 1)
{
for(counter_2 = 0; counter_2 <= blocks_fit_in_Y; counter_2 = counter_2 + 1)
{
if(build_mode_block_pos[counter][counter_2] == true)
{
SDL_Rect dstrect = { counter * blocksize, counter_2 * blocksize, blocksize, blocksize};
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
}
}
}
SDL_RenderPresent(renderer);
}
void build_mode()
{
while(programm_part_run)
{
input();
if(pressed_mouse_button == 1)
{
build_mode_block_pos[MouseX/blocksize][MouseY/blocksize] = true;
}
build_mode_draw();
}
}
void play_mode_draw()
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 0);
SDL_RenderClear(renderer);
SDL_Surface * image = SDL_LoadBMP("stealcube.bmp");
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,image);
SDL_FreeSurface(image);
for(counter = 0; counter < play_mode_blockamount; counter = counter + 1)
{
SDL_Rect dstrect = { play_mode_block_pos_X[counter], play_mode_block_pos_Y[counter], blocksize, blocksize};
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
}
SDL_RenderPresent(renderer);
}
void play_mode()
{
counter_3 = 0;
for(counter = 0; counter <= blocks_fit_in_X; counter = counter + 1)
{
for(counter_2 = 0; counter_2 <= blocks_fit_in_Y; counter_2 = counter_2 + 1)
{
if(build_mode_block_pos[counter][counter_2] == true)
{
play_mode_block_pos_X[counter_3] = counter*blocksize;
play_mode_block_pos_Y[counter_3] = counter_2*blocksize;
counter_3 = counter_3 + 1;
}
}
}
play_mode_blockamount = counter_3;
while(programm_part_run)
{
for(counter = 0; counter < play_mode_speed; counter = counter + 1)
{
input();
SDL_Delay(1);
}
for(counter = 0; counter <= play_mode_blockamount; counter = counter + 1)
{
if(play_mode_block_pos_Y[counter] < blocks_fit_in_Y * blocksize - blocksize)
{
play_mode_block_pos_Y[counter] = play_mode_block_pos_Y[counter] + 1;
}
}
play_mode_draw();
}
}
int main (int argc, char** argv)
{
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow
(
"Test Fenster :)", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WindowWidth,
WindowHight,
SDL_WINDOW_SHOWN
);
renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED);
//setup
if(WindowWidth < WindowHight)
{
blocksize = WindowWidth/StartFensterBlockmenge;
}
else
{
blocksize = WindowHight/StartFensterBlockmenge;
}
blocks_fit_in_X = WindowWidth/blocksize;
blocks_fit_in_Y = WindowHight/blocksize;
while(!end)
{
programm_part_run = true;
build_mode();
programm_part_run = true;
play_mode();
}
}
I'am new there. I've been learning classes and tried to make a very simple platform game. But I have problem now. I've wanted to set Class "Player" to collide with 2 objects of Class "Block" But Collision do not work for one of them.
Here is my code:
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#undef main
class Block
{
private:
SDL_Texture *BlockTexture;
public:
Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height);
~Block();
void Draw(SDL_Renderer *renderTarget);
SDL_Rect BlockPos;
};
Block::Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
BlockTexture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
BlockPos.x = xPos;
BlockPos.y = yPos;
BlockPos.w = Width;
BlockPos.h = Height;
}
Block::~Block()
{
SDL_DestroyTexture(BlockTexture);
}
void Block::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, BlockTexture, NULL, &BlockPos);
}
class Player
{
private:
SDL_Texture *Texture;
float moveSpeed;
float jumpSpeed;
int falling = 0;
SDL_Scancode keys [3];
public:
SDL_Rect PlayerPos;
Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height);
~Player();
void Update(float delta, const Uint8 *Keystate);
void Draw(SDL_Renderer *renderTarget);
bool Collision(Block &p);
};
Player::Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
Texture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
PlayerPos.x = PosX;
PlayerPos.y = PosY;
PlayerPos.w = Width;
PlayerPos.h = Height;
keys[0] = SDL_SCANCODE_UP;
keys[1] = SDL_SCANCODE_LEFT;
keys[2] = SDL_SCANCODE_RIGHT;
moveSpeed = 200.f;
jumpSpeed = 100.f;
}
Player::~Player()
{
SDL_DestroyTexture(Texture);
}
void Player::Update(float delta, const Uint8 *KeyState)
{
if(KeyState[keys[0]])
{
PlayerPos.y -= moveSpeed * delta;
}
if(KeyState[keys[1]])
{
PlayerPos.x -= (moveSpeed / 2) * delta;
}
if(KeyState[keys[2]])
{
PlayerPos.x += moveSpeed * delta;
}
if(falling == 0)
{
PlayerPos.y += jumpSpeed * delta;
}
}
void Player::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, Texture, NULL, &PlayerPos);
}
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
SDL_Texture *LoadTexture(std::string filePath, SDL_Renderer *Renderer)
{
SDL_Texture *texture = NULL;
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
texture = SDL_CreateTextureFromSurface(Renderer, surface);
}
SDL_FreeSurface(surface);
return texture;
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("Platform", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
SDL_Renderer *renderTarget = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
int imgFlags = IMG_INIT_PNG;
int currentTime = 0;
int previousTime = 0;
float delta = 0;
const Uint8 *Keystate;
Player Player(renderTarget, "BlockP.png", 100, 100, 50, 50);
Block Block1(renderTarget, "Block.png", 0, 500, 800, 100);
Block Block2(renderTarget, "Block.png", 100, 300, 300, 50);
bool isRunning = true;
SDL_Event ev;
while(isRunning)
{
Keystate = SDL_GetKeyboardState(NULL);
Player.Collision(Block1);
Player.Collision(Block2);
previousTime = currentTime;
currentTime = SDL_GetTicks();
delta = (currentTime - previousTime) / 1000.0f;
Player.Update(delta, Keystate);
while(SDL_PollEvent(&ev) != 0)
{
if(ev.type == SDL_QUIT)
isRunning = false;
}
SDL_RenderClear(renderTarget);
Player.Draw(renderTarget);
Block1.Draw(renderTarget);
Block2.Draw(renderTarget);
SDL_RenderPresent(renderTarget);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderTarget);
window = NULL;
renderTarget = NULL;
SDL_Quit();
return 0;
}
The problem with your code is that each call to Player.Collision overwrites the "falling" variable.
Player.Collision(Block1); //this call calculates a falling value
Player.Collision(Block2); //...then this call overwrites falling with a new value
So effectively your code is only testing if the player is colliding with Block2, so collisions with Block1 are ignored.
Currently your Collision function is:
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
Firstly, your "return false;" is not actually part of the else, as you don't have {}. In this particular case it makes no difference as the else is exited and then the return happens but your indentation would suggest you expect the "return false;" line to be executed as part of the else block so you should put:
else
{
falling = 1;
return false;
}
Next you want to say if you have already detected a collision (eg, with Block1) then don't set falling to 1, to do this add an if statement.
else
{
if(falling != 0) //if we haven't already detected a collision this frame
{
falling = 1;
}
return false;
}
You will however need to set falling back to 1 at the start of each frame, otherwise if a collision is detected on one frame then the player will never fall on subsequent frames, even if they are not colliding with a block.
As a side note, your Player.Update code modifies the player's y position if falling == 0, this seems counter intuitive as usually 0 is false and 1 is true, hence you seem to be saying if not falling then update y, where as it should be if falling update y. Personally I would use a bool rather than an int to hold the value of falling, and then say if(falling) update y, this would make your code clearer.
i want to make interpolation for my mini game. There are 2 SDL_Textures, when i click on first and then on second, they positions are swapped, but without move animation.
So how to make animated place swapping for SDL_Textures ?
void MainLoop() {
SDL_Event Event;
float t = 0.0f;
float dt = 0.1f;
float currentTime = 0.0f;
float accumulator = 0.0f;
while (Running)
{
while(SDL_PollEvent(&Event)) {
OnEvent(&Event);
}
const float newTime = SDL_GetTicks();
float frameTime = newTime - currentTime;
const Uint32 maxFrameTime = 1000; // 1 sec per frame is the slowest we allow
if( frameTime > maxFrameTime) {
frameTime = maxFrameTime;
}
currentTime = newTime;
accumulator += frameTime;
while( accumulator >= dt )
{
this->UpdatePositions(); // simulate a "frame" of logic at a different FPS than we simulate a frame of rendering
accumulator -= dt;
t += dt;
}
Render();
}
Main Render method:
void Puzzle::Render() const {
SDL_RenderClear(renderer);
for (int i = 0; i < blocksNum; ++i)
{
Rectangle texRect = normalizeTexCoords(blockRect(blocks[i]));
Rectangle scrRectOrigin = blockRect(i);
DrawRect(scrRectOrigin, i, texRect);
}
SDL_RenderPresent(renderer);
}
void DrawRect(const Rectangle& screenCoords, int textureId, const Rectangle& textureCoord) {
SDL_Texture *texture = blockTexture(blocks[textureId]);
renderTexture(texture, renderer, (int)screenCoords.left, (int)screenCoords.top, (int)blockWidth, (int)blockHeight);
//SDL_DestroyTexture(texture2);
}
void renderTexture(SDL_Texture *tex, SDL_Renderer *ren, int x, int y, int w, int h) {
// Destination rectangle position
SDL_Rect dst;
dst.x = x; dst.y = y; dst.w = w; dst.h = h;
SDL_RenderCopy(ren, tex, NULL, &dst);
}
And in my UpdatePosition method i want to make my SDL_Textures moving, but it still swapping without animation.
void Puzzle::UpdatePositions()
{
if (secondSwappedBlock != -1) {
Rectangle firstRect = blockRect(blocks[firstSwappedBlock]);
firstRect.left += speed * deltaTime;
firstRect.right += speed * deltaTime;
SDL_Texture *texture = blockTexture(blocks[firstSwappedBlock]);
renderTexture(texture, renderer, (int)firstRect.left, (int)firstRect.top, (int)blockWidth, (int)blockHeight);
}
}
void Puzzle::SwapBlocks(const int first, const int second) const
{
if (first != second)
{
const int t = blocks[first];
blocks[first] = blocks[second];
blocks[second] = t;
}
}
Here is a minimal (yet fully working) example:
#include "SDL.h"
#include <assert.h>
/* linear interpolation between {start.x; start.y} and {end.x; end.y} */
static void rect_lerp(SDL_Rect *out, const SDL_Rect *start, const SDL_Rect *end, float f) {
float t = 1.0f - f;
out->x = (float)start->x * t + (float)end->x * f;
out->y = (float)start->y * t + (float)end->y * f;
}
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
SDL_Window *window = SDL_CreateWindow("example",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_SHOWN);
assert(window);
SDL_Renderer *renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED);
assert(renderer);
int quit = 0;
int animate = 0;
Uint32 animation_start_time;
/* whole animation will play in e.g. one seconds */
const Uint32 animation_time_total = 1000;
SDL_Rect rect0 = {
.x = 0, .y = 0, .w = 128, .h = 128
};
SDL_Rect rect1 = {
.x = 256, .y = 256, .w = 128, .h = 128
};
while(!quit) {
/* time of current frame */
Uint32 tcurrent = SDL_GetTicks();
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_KEYUP) {
if(event.key.keysym.sym == SDLK_ESCAPE) {
quit = 1;
break;
} else if(event.key.keysym.sym == SDLK_SPACE) {
animate = 1;
animation_start_time = tcurrent;
}
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_Rect r0 = rect0, r1 = rect1;
/* if not within animation - leave coordinates as they are */
if(animate) {
if(tcurrent > animation_start_time + animation_time_total) {
/* animation ends by now */
/* swap rect0 and rect1 and stop animation */
SDL_Rect t = rect0;
rect0 = rect1;
rect1 = t;
animate = 0;
/* need to update r0 and r1 too */
r0 = rect0;
r1 = rect1;
} else {
/* animation is incomplete - interpolate coordinates */
/* calculate current animation percentage - in range [0; 1] */
float factor = ((float)(tcurrent - animation_start_time)) / animation_time_total;
rect_lerp(&r0, &rect0, &rect1, factor);
rect_lerp(&r1, &rect1, &rect0, factor);
}
}
/* r0 and r1 now have correct coordinates, draw */
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderDrawRect(renderer, &r0);
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
SDL_RenderDrawRect(renderer, &r1);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
For sake of simplicity it draws rectangles instead of textures, but that could be easily changed.
As you can see, in that example I'm keeping old coordinates for as long as animation incomplete, and fixating it only when it is fully gone. This easily allows to replay it back and don't have problems with precision; but - if you'll try to press space when animation already playing, it will just restart.
Another way could be updating coordinates on each animation step (may have different update frequency then redraw); in that case, you'll need to keep current coordinates, destination coordinates (the ones that you'll reach once animation is complete) and, probably, start coordinates (to eliminate precision problems).
I have a bmp-file of numbers and characters. My program reads keypresses and blits the appropriate character/number from the bitmap onto the screen. The only problem is if i press 'A' - 'A' will show on screen, but if I press 'B', it will take 'A's place. So I will never have more than one character on screen.
Here's my code:
#include <SDL/SDL.h>
#include <iostream>
#include <string>
#include <vector>
#include <SDL_image/SDL_image.h>
using namespace std;
const Uint32 FRAMES_PER_SECOND = 60;
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int WIDTH = 21;
const int HEIGHT = 25;
SDL_Event sdlEvent;
char getAsciiKey(const SDL_Event &sdlEvent);
int main( int argc, char* args[] )
{
//The surfaces
SDL_Surface* image[2] = {NULL};
SDL_Surface* screen = NULL;
//Start SDL
SDL_Init( SDL_INIT_EVERYTHING );
//Set up screen
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE | SDL_DOUBLEBUF );
char filename[256]; //create a large enough C-string
for(int index = 0; index < 2; index++)
{
sprintf(filename, "Text-types/Arial%d.bmp", index); //Arial0 and Arial1
//Load the image
image[index] = IMG_Load( filename );
if(image == NULL)
{
cout << "Error loading image: " << filename << endl;
exit(1);
}
}
Uint32 color = SDL_MapRGB(screen->format, 0xff,0xff,0xff); //White
SDL_FillRect(screen, &screen->clip_rect, color); //Backgroundcolor -> White
bool quit = false;
//Main program loop
while(quit == false)
{
//Process any events from the event queue - such as key presses or mouse movements
while(SDL_PollEvent(&sdlEvent))
{
if(sdlEvent.type == SDL_QUIT)
{
quit = true;
}
if (sdlEvent.type == SDL_KEYDOWN) //A key has just pressed
{
int x, y, temp;
SDL_Rect srcRect;
SDL_Rect dstRect;
//char letter = getAsciiKey(sdlEvent); //Getting keypress
temp = (static_cast<int>(getAsciiKey(sdlEvent)) - 12);
x = (temp % 20); //X-axis postion
y = (temp / 20); //Y-axis position
srcRect.x = (x - 1) * WIDTH;
srcRect.y = (y - 1) * HEIGHT;
//PIXELSIZE
srcRect.w = WIDTH;
srcRect.h = HEIGHT;
dstRect.x = 0;
dstRect.y = 0;
dstRect.w = WIDTH;
dstRect.h = HEIGHT;
SDL_BlitSurface(image[1] , &srcRect, screen, &dstRect ); //Putting image up on screen
//Update Screen
SDL_Flip( screen );
//Pause
SDL_Delay( 2000 );
}
}
}
//Free any loaded images
for(int index = 0; index < 2; index++)
{
SDL_FreeSurface( image[index] );
}
//Quit SDL
SDL_Quit();
return 0;
}
char getAsciiKey(const SDL_Event &sdlEvent)
{
char key = 0;
if(sdlEvent.key.keysym.sym >= SDLK_a && sdlEvent.key.keysym.sym <= SDLK_z)
{
if(sdlEvent.key.keysym.mod & KMOD_SHIFT)
{
key = 'A' + char(sdlEvent.key.keysym.sym - SDLK_a);
}
else
{
key = 'a' + char(sdlEvent.key.keysym.sym - SDLK_a);
}
}
else if(sdlEvent.key.keysym.sym >= SDLK_0 && sdlEvent.key.keysym.sym <= SDLK_9)
{
key = '0' + char(sdlEvent.key.keysym.sym - SDLK_0);
}
return key;
}
dstRect.x = 0;
dstRect.y = 0;
This is the position you're blitting to, and I don't see you changing it anywhere. Update it for each new character.
Also, this:
dstRect.w = WIDTH;
dstRect.h = HEIGHT;
is redundant, width and height of destination are ignored when blitting (at least the reference for SDL_BlitSurface says so).