SDL How to animate a Sprite when key is pressed - c++

I'm going to get straight to the point:
I have a sprite sheet that has 8 movement sprites (http://i.imgur.com/hLpo2Qn.png cant post images :\ ), so it creates the illusion that im walking)
My problem is that when i press and hold a key i want the sprite to kinda have an animated walk. For example when i press the up arrow the first two sprites play in a loop until i let go of the key. All I've been able to do so far is to get only one sprite showing for each direction, so it kinda gives an unrealistic effect.
Code:
#include <SDL/SDL.h>
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface* screen, *image;
screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
bool running = true;
const int FPS = 30;
Uint32 start;
bool direction[4] = {0, 0, 0, 0};
SDL_Rect pos;
pos.x = 0;
pos.y = 0;
SDL_Rect sprite;
sprite.x = 160;
sprite.y = 0;
sprite.w = 32;
sprite.h = 32;;
Uint32 color = SDL_MapRGB(screen -> format, 0xff, 0xff, 0xff);
image = SDL_DisplayFormat(SDL_LoadBMP("sprite.bmp"));
SDL_SetColorKey(image, SDL_SRCCOLORKEY, SDL_MapRGB(screen -> format, 255, 0, 255));
while (running == true)
{
start = SDL_GetTicks();
SDL_Event event;
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
running = false;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_UP:
direction[0] = 1;
sprite.x = 0;
break;
case SDLK_LEFT:
direction[1] = 1;
sprite.x = 224;
break;
case SDLK_DOWN:
direction[2] = 1;
sprite.x = 160;
break;
case SDLK_RIGHT:
direction[3] = 1;
sprite.x = 96;
break;
}
break;
case SDL_KEYUP:
switch(event.key.keysym.sym)
{
case SDLK_UP:
direction[0] = 0;
sprite.x = 32;
break;
case SDLK_LEFT:
direction[1] = 0;
break;
case SDLK_DOWN:
direction[2] = 0;
break;
case SDLK_RIGHT:
direction[3] = 0;
break;
}
break;
}
}
if(direction[0])
pos.y-- ;
if(direction[1])
pos.x--;
if(direction[2])
pos.y++;
if(direction[3])
pos.x++;
SDL_FillRect(screen, &screen -> clip_rect, color);
SDL_BlitSurface(image, &sprite, screen, &pos);
SDL_Flip(screen);
if(1000 / FPS > SDL_GetTicks() - start)
SDL_Delay(1000 / FPS - (SDL_GetTicks() - start));
}
SDL_FreeSurface(image);
SDL_Quit();
return 0;
}

Disclaimer: This is not the only or best way to achieve what you wanting. It is simply one possible solution
You need to implement a basic timer/counter to switch between the two appropriate images.
For this example I would store your sprite offsets in a 2D array int sprite_x[4][2]; - this would represent the four directions and the two image offsets for each. Then on a key press instead of using a bool array just have a single integer index int sprite_index; for indexing the sprite offsets. All you would then need to do is have another integer value called something like int current_key; which you would switch between 0 and 1.
// Used for indexing the 2D array
enum
{
WALK_LEFT,
WALK_RIGHT,
WALK_UP,
WALK_DOWN
WALK_MAX
};
// How many sprites per animation
const int NUM_KEYFRAMES = 2;
// 2D array to hold the x value offsets for sprites
int sprite_x[WALK_MAX][NUM_KEYFRAMES];
int sprite_index = WALK_LEFT; // Current animation
int current_key = 0; // Current keyframe for the animation
// Set up all the x value offsets in the array
sprite_x[WALK_LEFT][0] = 0;
sprite_x[WALK_LEFT][1] = 32;
sprite_x[WALK_RIGHT][0] = 64;
sprite_x[WALK_RIGHT][1] = 96;
.
.
.
You then simply update the sprite x value accordingly sprite.x = sprite_x[sprite_index][current_key];

Related

How deep is mouse in Rectangle C++ & SDL2 (Position flickers between two positions)

I am creating a program, and I have a rectangle. Basically, I am creating a custom window inside the SDL2 window, which is a Rect, with another Rect being its toolbar. I am struggling for hours trying to figure how to detect how deep is the mouse within the Rect, but I am failing every time. The most obvious equation for me was int deep = mousePos.x - x, but it flickers between two positions every time I move my mouse. I then have tried a LOT of other calculations, but none of them worked. Either they flickered between two positions with descending values, or they were completely static and didn't move, or always moved a lot in a specific direction. I have visually represented the calculations, which were mostly correct, but the flickering between two positions is always ruining it. Thanks for any help. I am providing source code, too.
SOURCE:
//
// main.cpp
// Open
//
// Created by Fildom on 28.12.2021.
//
// Library includes
#include <SDL2/SDL.h>
#include <stdio.h>
bool isdown = false;
// Screen rendering helper
void on_render(SDL_Window* window, SDL_Renderer* renderer);
// Concatenation (probably not spelt correctly but idrc) for easier use
const char * concat(const char * one, const char * two) {
char * buffer = new char[strlen(one) + strlen(two) + 1];
strcpy(buffer, one);
strcat(buffer, two);
return buffer;
}
// Main method, required for performing application run
int main(int argc, const char * argv[]) {
SDL_Renderer *renderer = NULL; // Initialize the renderer
SDL_Event event = { 0 }; // Create a null event
SDL_Window *win = NULL; // Initialize a window
int exit = 0; // If exit is 1, win closes
// Window pre-modifiers
const char * appName = "test";
// SDL VIDEO mode initialization and error check
if(SDL_Init(SDL_INIT_VIDEO) == -1) {
printf("SDL_Init() failed with \"%s.\"", SDL_GetError());
return 1;
}
// Create the window and load it into a previously defined variable
win = SDL_CreateWindow(concat(appName, " - Initialization in progress"), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
// Window creation was unsuccessfull
if(!win) {
printf("SDL_CreateWindow() failed with \"%s.\"", SDL_GetError());
return -1;
}
// Creating renderer
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
// If renderer failed to load...
if(!renderer) {
printf("SDL_CreateRenderer() failed with \"%s.\"", SDL_GetError());
return -1;
}
// Everything has gone OK, thus the window can be renamed
SDL_SetWindowTitle(win, appName);
// Game loop, as said previously, false = 0, true = 1.
// while !exit |
// while not exit <- |
// while exit is 0 (false) <-
while (!exit) {
// Event loop
if (SDL_WaitEvent(&event)) {
// Event types
switch(event.type) {
case SDL_QUIT:
exit = 1; // Exit = 1, thus app is being exitted
break;
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE) exit = 1; // If ESC is pressed
break;
case SDL_MOUSEBUTTONUP:
isdown = false;
break;
case SDL_MOUSEBUTTONDOWN:
isdown = true;
break;
case SDL_MOUSEMOTION:
break;
case SDL_WINDOWEVENT:
switch(event.window.event) {
case SDL_WINDOWEVENT_CLOSE: // macOS and/or other OSes rely on right click + Quit to fully exit out of an application. This makes it easier by just hitting the close button.
exit = 1;
break;
}
break;
default: break;
}
}
// Render the screen
on_render(win, renderer);
// Swap buffers to display
SDL_RenderPresent(renderer);
}
// Cleanup
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
class Window {
public:
int x, y, w, h;
SDL_Color winc, wintc;
bool draggable;
int titleh;
Window(int wx, int wy, int ww, int wh, SDL_Color window_color = {255, 255, 255, 255}, SDL_Color window_title_color = {200, 200, 200, 255}) {
x = wx;
y = wy;
w = ww;
h = wh;
winc = window_color;
wintc = window_title_color;
draggable = true;
titleh = 50;
}
int tx, ty = 0;
void Render(SDL_Renderer* renderer) {
SDL_Rect _t;
_t.x = x;
_t.y = y;
_t.w = w;
_t.h = h;
SDL_Rect title;
title.x = x;
title.y = y;
title.w = w;
title.h = titleh;
SDL_SetRenderDrawColor(renderer, winc.r, winc.g, winc.b, winc.a);
SDL_RenderFillRect(renderer, &_t);
SDL_SetRenderDrawColor(renderer, wintc.r, wintc.g, wintc.b, wintc.a);
SDL_RenderFillRect(renderer, &title);
int mx, my;
SDL_PumpEvents();
SDL_GetMouseState(&mx, &my);
SDL_Point ms;
ms.x = mx;
ms.y = my;
if (SDL_PointInRect(&ms, &title) and isdown) {
x = mx - tx;
y = my - ty;
tx = x;
ty = y;
}
}
};
Window test1 = Window(200, 100, 300, 200);
void on_render(SDL_Window* window, SDL_Renderer* renderer) {
SDL_Rect wind = { 0 };
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_GetWindowSize(window, &wind.w, &wind.h);
test1.Render(renderer);
}
I ended up doing it in a different way. Instead of using mousePosition.x and y, I used relative X and Y which worked out perfectly.
code for that is
mousePosition.relX and mousePosition.relY;

Using SFML to draw stuff [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to create a scribble clone for a uni project.
My lines are basically a lot of dots. If I draw too quick, the line breaks and I have single dots.
Also, I can't figure out how to draw lines ONLY when a mouse button is pressed.
I tried to put mouseMoved into a while loop until mouseButton is released but that didn't seem to work. I ended up in an infinite loop.
Here is my code so far:
while (window.isOpen())
{
while (window.pollEvent(event))
{
int mouseButtonX = event.mouseButton.x;
int mouseButtonY = event.mouseButton.y;
int mouseMoveX = event.mouseMove.x;
int mouseMoveY = event.mouseMove.y;
setBrushSize(5);
brush.setRadius(brushSize);
brush.setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
brush.setFillColor(sf::Color::Transparent);
brush.setOutlineColor(sf::Color::Green);
brush.setOutlineThickness(2);
switch (event.type) {
case (sf::Event::Closed):
window.close();
break;
case (sf::Event::KeyPressed):
if (event.key.control && event.key.code == sf::Keyboard::X) {
cout << "closing";
window.close();
}
if (event.key.code == sf::Keyboard::R) {
cout << "printed";
brushColor = setBrushColor(255, 0, 0);
}
if (event.key.code == sf::Keyboard::G) {
brushColor = setBrushColor(0, 255, 0);
}
if (event.key.code == sf::Keyboard::B) {
brushColor = setBrushColor(0, 0, 255);
}
if (event.key.code == sf::Keyboard::C) {
for (int i = 0; i < points.size(); i++) {
points.clear();
}
it = 0;
}
break;
case(sf::Event::MouseButtonPressed):
points.push_back(point);
points[it].setRadius(brushSize);
points[it].setFillColor(brushColor);
points[it].setPosition(mouseButtonX - brushSize, mouseButtonY - brushSize);
it++;
cout << "drawPoint: Pressed X = " << mouseButtonX << " Y = " << mouseButtonY << endl;
break;
case(sf::Event::MouseMoved):
points.push_back(point);
points[it].setRadius(brushSize);
points[it].setFillColor(brushColor);
points[it].setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
it++;
cout << "drawPoint: Moved X = " << mouseMoveX << " Y = " << mouseMoveY << endl;
break;
}
}
window.clear(sf::Color(255, 247, 204));
window.draw(SkechyT);
window.draw(close);
window.draw(brush);
window.draw(color);
window.draw(clear);
for (int i = 0; i < points.size(); i++) {
window.draw(points[i]);
}
//window.draw(point);
window.display();
}
}
int getBrushSize() {
return brushSize;
}
void setBrushSize(int num) {
brushSize = num;
}
sf::Color setBrushColor(int r, int g, int b) {
return sf::Color(r, g, b);
}
~Visualizer();
};
While you can modify a sf::VertexArray on the fly (basically building a vector drawing app), you can also use a sf::RenderTexture as an actual drawing canvas.
Considering you tried drawing lots of small points, I'd assume you're aiming for the latter. What's important here is the fact that you don't necessarily have to clear render textures between drawing calls and can therefore preserve whatever has been drawn before.
Combined with the original goal – drawing – this becomes very easy.
All you have to do is draw the changes (e.g. when moving the cursor), finalize the render texture (by calling display()), and then presenting it using any drawable (like sf::Sprite.
I've quickly scribbled together the following example, which should show the concept rather well (and you won't run into an endless loop other than the actual main loop):
#include <SFML/Graphics.hpp>
#include <vector>
int main(int argc, char **argv) {
sf::RenderWindow window(sf::VideoMode(800, 600), L"SFML Drawing – C to clear, PageUp/PageDown to pick colors", sf::Style::Default);
// Set a specific frame rate, since we don't want to
// worry about vsync or the time between drawing iterations
window.setVerticalSyncEnabled(false);
window.setFramerateLimit(100);
// First we'll use a canvas to basically store our image
sf::RenderTexture canvas;
canvas.create(800, 600);
canvas.clear(sf::Color::White);
// Next we'll need a sprite as a helper to draw our canvas
sf::Sprite sprite;
sprite.setTexture(canvas.getTexture(), true);
// Define some colors to use
// These are all with very low alpha so we
// can (over-)draw based on how fast we move the cursor
const std::vector<sf::Color> colors = {
sf::Color(255, 0, 0, 8),
sf::Color(255, 255, 0, 8),
sf::Color(0, 255, 0, 8),
sf::Color(0, 255, 255, 8),
sf::Color(0, 0, 255, 8),
sf::Color(255, 0, 255, 8)
};
// We'll need something to actually draw
// For simplicity, I'm just drawing a circle shape
// but you could also draw a line, rectangle, or something more complex
const float brush_size = 25;
sf::CircleShape brush(brush_size, 24);
brush.setOrigin(brush_size, brush_size); // Center on the circle's center
sf::Vector2f lastPos;
bool isDrawing = false;
unsigned int color = 0;
// Apply some default color
brush.setFillColor(colors[color]);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
switch (event.key.code) {
case sf::Keyboard::C:
// Clear our canvas
canvas.clear(sf::Color::White);
canvas.display();
break;
case sf::Keyboard::PageUp:
// Get next color
color = (color + 1) % colors.size();
// Apply it
brush.setFillColor(colors[color]);
break;
case sf::Keyboard::PageDown:
// Get previous color
color = (color - 1) % colors.size();
// Apply it
brush.setFillColor(colors[color]);
break;
}
break;
case sf::Event::Resized:
{
// Window got resized, update the view to the new size
sf::View view(window.getView());
const sf::Vector2f size(window.getSize().x, window.getSize().y);
view.setSize(size); // Set the size
view.setCenter(size / 2.f); // Set the center, moving our drawing to the top left
window.setView(view); // Apply the view
break;
}
case sf::Event::MouseButtonPressed:
// Only care for the left button
if (event.mouseButton.button == sf::Mouse::Left) {
isDrawing = true;
// Store the cursor position relative to the canvas
lastPos = window.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
// Now let's draw our brush once, so we can
// draw dots without actually draging the mouse
brush.setPosition(lastPos);
// Draw our "brush"
canvas.draw(brush);
// Finalize the texture
canvas.display();
}
break;
case sf::Event::MouseButtonReleased:
// Only care for the left button
if (event.mouseButton.button == sf::Mouse::Left)
isDrawing = false;
break;
case sf::Event::MouseMoved:
if (isDrawing)
{
// Calculate the cursor position relative to the canvas
const sf::Vector2f newPos(window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y)));
// I'm only using the new position here
// but you could also use `lastPos` to draw a
// line or rectangle instead
brush.setPosition(newPos);
// Draw our "brush"
canvas.draw(brush);
// Finalize the texture
canvas.display();
break;
}
}
}
// Clear the window
window.clear(sf::Color(64, 64, 64));
// Draw our canvas
window.draw(sprite);
// Show the window
window.display();
}
return 0;
}
Once running, you can start drawing using the left mouse button. C will clear the canvas and Page Up and Page Down allow you to pick a different color:
Edit: And just to mention it, in the example above, rather than drawing a circle, you can just draw a sf::VertexArray with sf::Lines and two vertices: lastPos and newPos. This way you'll always draw a continuous line. (But you'd obviously have to save/update lastPos with the value of newPos once you're done.)

Drawing Line is flickering in SDL2 C++. How To Modify My Game Loop?

My line drawing works fine, but the line is flickering.
I was thinking to change the FPS of my loop, but I think I only have to add my RenderPresent() code in another line or add some new code for rendering the line. I tried a lot of possibilities and nothing worked.
What can I do to stop the line flickering?
If you need more information please write a comment.
// Global variables
SDL_Event event; // Event object
int mouse_x = 0; // Actual Mouse Coordinate X
int mouse_y = 0; // Actual Mouse Coordinate Y
int mouse_last_x = 0; // The coordinate X by last click
int mouse_last_y = 0; // The coordinate Y by last click
bool dragged = false; // Boolean after I clicked on some place
bool running = true; // Makes the game loop run
void GameWin::loop() //Game Loop
{
while (running)
{
SDL_GetMouseState(&mouse_x, &mouse_y); // Get Mouse Coordninates
SDL_PollEvent(&event);
SDL_SetRenderDrawColor(GameWin::renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); // Draw The Background Black
update();
render();
switch (event.type)
{
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN: // Mouse Click Event
if (event.button.button == SDL_BUTTON_LEFT)
{
mouse_last_x = mouse_x; // After Left Click Save my Mouse Coordingates
mouse_last_y = mouse_y;
dragged = true;
}
break;
case SDL_MOUSEMOTION:
if (dragged)
{
SDL_SetRenderDrawColor(GameWin::renderer, 137, 255, 85, SDL_ALPHA_OPAQUE); // Set The Color Line To Green
SDL_RenderDrawLine(GameWin::renderer, mouse_last_x, mouse_last_y, mouse_x, mouse_y); // Draw The Line
SDL_RenderPresent(GameWin::renderer); // Render Line
}
break;
case SDL_MOUSEBUTTONUP:
if (dragged)
{
dragged= false;
mouse_last_x = mouse_x;
mouse_last_y = mouse_y;
}
break;
default:
break;
}
}
}
// My render method
void GameWin::render()
{
SDL_RenderClear(GameWin::renderer);
SDL_RenderPresent(GameWin::renderer);
}
First of all, you don't check if any event happened at all. You call SDL_PollEvent, and then process event - it might be ok, or it might be completely wrong as there is no guarantee there was an event in queue. SDL_PollEvent returns 0 if queue is empty - which means it didn't fill your event structure with meaningful data.
Second, don't combine event handling with drawing. Fetch all events that happened between iterations, then draw once.
Basically it should be something like:
#include "SDL.h"
// Global variables
SDL_Event event; // Event object
int mouse_x = 0; // Actual Mouse Coordinate X
int mouse_y = 0; // Actual Mouse Coordinate Y
int mouse_last_x = 0; // The coordinate X by last click
int mouse_last_y = 0; // The coordinate Y by last click
bool dragged = false; // Boolean after I clicked on some place
bool running = true; // Makes the game loop run
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *w = NULL;
SDL_Renderer *renderer = NULL;
SDL_CreateWindowAndRenderer(640, 480, 0, &w, &renderer);
while (running)
{
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_GetMouseState(&mouse_x, &mouse_y); // Get Mouse Coordninates
while(SDL_PollEvent(&event)) {
switch (event.type)
{
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN: // Mouse Click Event
if (event.button.button == SDL_BUTTON_LEFT)
{
mouse_last_x = mouse_x; // After Left Click Save my Mouse Coordingates
mouse_last_y = mouse_y;
dragged = true;
}
break;
case SDL_MOUSEBUTTONUP:
if (dragged)
{
dragged= false;
mouse_last_x = mouse_x;
mouse_last_y = mouse_y;
}
break;
default:
break;
}
}
if(!running) break;
if (dragged)
{
SDL_SetRenderDrawColor(renderer, 137, 255, 85, SDL_ALPHA_OPAQUE); // Set The Color Line To Green
SDL_RenderDrawLine(renderer, mouse_last_x, mouse_last_y, mouse_x, mouse_y); // Draw The Line
}
SDL_RenderPresent(renderer);
}
}

SDL_PollEvent() skips events

Very Simple program, for drawing on screen (like with pen in Paint)
I'm using SDL 1.2. Only events I'm proccesing are mouse motion, mouse left click and quiting program. My problem is that SDL_MOUSEMOTION events are 'skipped' when I'm moving mouse fast (when I say fast I mean faster than 1 pixel/second)
Why this happens?
screen shots:
http://postimg.org/image/gcb87v9zr/
http://postimg.org/image/i5e4w6v6f/
#include <SDL/SDL.h>
SDL_Event event;
SDL_Surface* screen;
bool clicked = false;
Uint32 whiteColor;
int W = 200; // screen width
int H = 200; // screen height
Uint32* screenPixels;
bool handleInput();
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(W,H,32,SDL_SWSURFACE);
whiteColor = SDL_MapRGB(screen->format,255,255,255);
screenPixels = (Uint32*) screen->pixels;
while(handleInput())
{
}
SDL_Quit();
return 0;
}
bool handleInput()
{
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:{
return false;
break;
}
case SDL_MOUSEBUTTONDOWN:{
clicked = true;
break;
}
case SDL_MOUSEBUTTONUP:{
clicked = false;
break;
}
case SDL_MOUSEMOTION:{
if(clicked)
{
int P_x = event.motion.x;
int P_y = event.motion.y;
screenPixels[P_y * W + P_x] = whiteColor;
SDL_Flip(screen);
}
break;
}
}
}
return true;
}
It is because you SDL_Flip for all your screen, it takes too many time.
Better call SDL_Flip in another thread (using std::async, for example).
Or you may update not the all surface, but only the part which is changed color to white.

How can I set gravity using this code?

I am trying to make a game and am stuck on gravity..... In the following code a rectangle stands for a player and when I press up key it moves in y-axis but when I activate gravity on it (i.e resetting its previous position) it does not animate (i.e. It does not jumps) instead it just stays in its position. I am using SFML library of C++ and that's a game development tool. Please Help!
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Gravity");
sf::RectangleShape rectangle;
rectangle.setSize(sf::Vector2f(100, 100));
rectangle.setFillColor(sf::Color::Black);
rectangle.setPosition(sf::Vector2f(10, 350));
while(window.isOpen())
{
sf::Event Event;
while(window.pollEvent(Event))
{
if(Event.type == sf::Event::Closed)
{
window.close();
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
rectangle.move(0, -1);
}
if(rectangle.getPosition().y >= 350-1)
{
rectangle.setPosition(0, 350);
}
window.display();
window.clear(sf::Color::Cyan);
window.draw(rectangle);
}
}
Theoretically your code would work, but there's one significant problem:
Your initial position is 350.
Now your "jumping code" (which will allow the player to fly indefinitely!) triggers and your position is changed to 349.
However, your code keeping the player from dropping off the screen (y >= 350-1) essentially resolves to the check y >= 349, which will be true, so your position is permanently reset to 350.
To solve this, just remove the -1 or replace the >= operator with >.
While your approach should be working (once the fix above is applied), you should rethink your strategy and store a velocity in addition to a position. I've recently written the following example code. It's far from being perfect, but it should teach you a few basics for a jump and run game (not necessarily the only way to do such things):
Allow the player to jump.
Apply gravity.
Allow the player to determine jump height based on how long he holds down a key.
#include <SFML/Graphics.hpp>
int main(int argc, char **argv) {
sf::RenderWindow window;
sf::Event event;
sf::RectangleShape box(sf::Vector2f(32, 32));
box.setFillColor(sf::Color::White);
box.setOrigin(16, 32);
box.setPosition(320, 240);
window.create(sf::VideoMode(640, 480), "Jumping Box [cursor keys + space]");
window.setFramerateLimit(60);
window.setVerticalSyncEnabled(false);
// player position
sf::Vector2f pos(320, 240);
// player velocity (per frame)
sf::Vector2f vel(0, 0);
// gravity (per frame)
sf::Vector2f gravity(0, .5f);
// max fall velocity
const float maxfall = 5;
// run acceleration
const float runacc = .25f;
// max run velocity
const float maxrun = 2.5f;
// jump acceleration
const float jumpacc = -1;
// number of frames to accelerate in
const unsigned char jumpframes = 10;
// counts the number of frames where you can still accelerate
unsigned char jumpcounter = 0;
// inputs
bool left = false;
bool right = false;
bool jump = false;
while (window.isOpen()) {
while (window.pollEvent(event)) {
switch(event.type) {
case sf::Event::KeyPressed:
case sf::Event::KeyReleased:
switch (event.key.code) {
case sf::Keyboard::Escape:
window.close();
break;
case sf::Keyboard::Left:
left = event.type == sf::Event::KeyPressed;
break;
case sf::Keyboard::Right:
right = event.type == sf::Event::KeyPressed;
break;
case sf::Keyboard::Space:
jump = event.type == sf::Event::KeyPressed;
break;
}
break;
case sf::Event::Closed:
window.close();
break;
}
}
// logic update start
// first, apply velocities
pos += vel;
// determine whether the player is on the ground
const bool onground = pos.y >= 480;
// now update the velocity by...
// ...updating gravity
vel += gravity;
// ...capping gravity
if (vel.y > maxfall)
vel.y = maxfall;
if (left) { // running to the left
vel.x -= runacc;
}
else if (right) { // running to the right
vel.x += runacc;
}
else { // not running anymore; slowing down each frame
vel.x *= 0.9;
}
// jumping
if (jump) {
if (onground) { // on the ground
vel.y += jumpacc * 2;
jumpcounter = jumpframes;
}
else if (jumpcounter > 0) { // first few frames in the air
vel.y += jumpacc;
jumpcounter--;
}
}
else { // jump key released, stop acceleration
jumpcounter = 0;
}
// check for collision with the ground
if (pos.y > 480) {
vel.y = 0;
pos.y = 480;
}
// check for collision with the left border
if (pos.x < 16) {
vel.x = 0;
pos.x = 16;
}
else if (pos.x > 624) {
vel.x = 0;
pos.x = 624;
}
// logic update end
// update the position
box.setPosition(pos);
window.clear();
window.draw(box);
window.display();
}
return 0;
}