I'm really stucked with the following code, it renders the wrong image of the obstacles on the screen. instead of a blue circle ("obstacle.png") on the screen appears the image of the char spreadsheet (the whole "char_anim.png")
Here's my code:
// C-Jumper.cpp : Diese Datei enthält die Funktion "main". Hier beginnt und endet die Ausführung des Programms.
//
#include <stdio.h>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#include <iostream>
#include <vector>
using namespace std;
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const int GROUND = 50;
const int BOTTOM = SCREEN_HEIGHT - GROUND;
const char* FONT_FILE = "assets/fonts/arial.ttf";
const int FONT_SIZE = 24;
const int FPS = 60;
const int sollzeit = 1000 / FPS;
class Character {
public:
Character(SDL_Renderer* renderer) {
// Load sprite sheet image
SDL_Surface* spriteSheetSurface = IMG_Load("assets/images/char_anim.png");
spriteSheetTexture = SDL_CreateTextureFromSurface(renderer, spriteSheetSurface);
SDL_FreeSurface(spriteSheetSurface);
// Define frames for sprite sheet
const int NUM_FRAMES = 8;
SDL_Rect frames[NUM_FRAMES] = {
{0, 0, 40, 58},
{40, 0, 40, 58},
{80, 0, 40, 58},
{120, 0, 40, 58},
{160, 0, 40, 58},
{200, 0, 40, 58},
{240, 0, 40, 58},
{280, 0, 40, 58}
};
for (int i = 0; i < NUM_FRAMES; i++) {
spriteClips[i] = frames[i];
}
// Set initial animation state
currentFrame = 0;
currentSpriteClip = &spriteClips[currentFrame];
lastFrameTime = 0;
}
~Character() {
SDL_DestroyTexture(spriteSheetTexture);
}
void updateAnimation() {
// Animate character
Uint32 currentTime = SDL_GetTicks();
if (currentTime - lastFrameTime >= frameTime) {
// Update the current frame
currentFrame = (currentFrame + 1) % NUM_FRAMES;
currentSpriteClip = &spriteClips[currentFrame];
lastFrameTime = currentTime;
}
}
void render(SDL_Renderer* renderer, int x, int y) {
SDL_Rect destRect = { x, y, currentSpriteClip->w, currentSpriteClip->h };
SDL_RenderCopy(renderer, spriteSheetTexture, currentSpriteClip, &destRect);
}
private:
// SDL_Surface* spriteSheetSurface;
SDL_Texture* spriteSheetTexture;
SDL_Rect spriteClips[8];
SDL_Rect* currentSpriteClip;
const int NUM_FRAMES = 8;
int currentFrame;
Uint32 lastFrameTime;
int frameTime = 100; // time in milliseconds between frames
};
class Obstacle {
public:
Obstacle(int x, int y, int width, int height, SDL_Renderer* renderer)
: x_(x), y_(y), width_(width), height_(height)
{
SDL_Surface* ObjSurface = IMG_Load("assets/images/obstacle.png");
ObjTexture = SDL_CreateTextureFromSurface(renderer, ObjSurface);
if (ObjTexture == NULL) {
std::cout << "Failed to create texture from surface: " << SDL_GetError() << std::endl;
}
SDL_FreeSurface(ObjSurface);
}
~Obstacle() {
SDL_DestroyTexture(ObjTexture);
}
void move() {
x_ -= 2;
if (x_ < 10) { x_ = 600; }
}
bool isColliding(int x, int y, int width, int height) {
return (x_ < x + width && x_ + width_ > x && y_ < y + height && y_ + height_ > y);
}
void draw(SDL_Renderer* renderer) {
SDL_Rect drect = { x_, y_, width_, height_ };
SDL_RenderCopy(renderer, ObjTexture, NULL, &drect);
}
private:
int x_;
int y_;
int width_;
int height_;
SDL_Texture* ObjTexture;
// SDL_Surface* ObjSurface;
};
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow("Platformer Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); // | SDL_RENDERER_PRESENTVSYNC);
int BORDER = SCREEN_WIDTH - 40;
// Load background texture
SDL_Surface* backgroundSurface = IMG_Load("assets/images/background.png");
SDL_Texture* backgroundTexture = SDL_CreateTextureFromSurface(renderer, backgroundSurface);
SDL_FreeSurface(backgroundSurface);
// Definiere Font
TTF_Init();
TTF_Font* font = TTF_OpenFont(FONT_FILE, FONT_SIZE);
if (!font) {
printf("Failed to load font: %s\n", TTF_GetError());
return 1;
}
SDL_Color color = { 255, 255, 255 }; // white text color
SDL_Surface* textSurface = TTF_RenderText_Solid(font, "Hello, SDL!", color);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_FreeSurface(textSurface);
// Obstacles
vector<Obstacle> obstacles;
// Set up variables for timing
int lastTime = SDL_GetTicks();
int currentTime = 0;
int deltaTime = 0;
int id = 0;
obstacles.push_back(Obstacle(300, BOTTOM - 50, 50, 50, renderer));
obstacles.push_back(Obstacle(550, BOTTOM - 50, 50, 50, renderer));
obstacles.push_back(Obstacle(800, BOTTOM - 50, 50, 50, renderer));
// Create character object
Character character(renderer);
bool move = true;
// Regualte Frames per Second
Uint32 frameStart = SDL_GetTicks();
Uint32 FPS_Start = SDL_GetTicks();
int frameCount = 0;
int Sekunden = 0;
char puffer[50];
sprintf_s(puffer, "Frames: --");
SDL_Event event;
// Define constants for movement speed and jump height
const int MOVEMENT_SPEED = 5;
const int JUMP_SPEED = 20;
// Set initial velocity and position
int xVel = 0;
int yVel = 0;
int xPos = 100;
int xPos_last = 0;
int yPos = 100;
bool quit = false;
// Game loop here
while (!quit) {
// Calculate delta time Frames & Objects
frameStart = SDL_GetTicks();
currentTime = SDL_GetTicks();
deltaTime = currentTime - lastTime;
lastTime = currentTime;
// Handle events
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
quit = true;
}
}
// Read keyboard state
const Uint8* keyboardState = SDL_GetKeyboardState(NULL);
SDL_Color color = { 255, 255, 255 }; // white text color
SDL_Surface* Textsurface = TTF_RenderText_Solid(font, puffer, color);
SDL_Texture* Texttexture = SDL_CreateTextureFromSurface(renderer, Textsurface);
SDL_Rect dstrect = {50, 50, Textsurface->w, Textsurface->h };
SDL_FreeSurface(Textsurface);
/*
// Spawn a new obstacle every second
static int obstacleTimer = 0;
obstacleTimer += deltaTime;
if (obstacleTimer > 1000) {
obstacleTimer = 0;
id++;
int x = SCREEN_WIDTH-100;
int y = SCREEN_HEIGHT-200;
int w = 50;
int h = 50;
Obstacle obstacle(x, y, w, h, renderer);
obstacles.push_back(obstacle);
}
*/
// Update character animation
if (move == true) { character.updateAnimation(); }
// Handle movement
if (keyboardState[SDL_SCANCODE_A]) {
xVel = -MOVEMENT_SPEED;
}
else if (keyboardState[SDL_SCANCODE_D]) {
xVel = MOVEMENT_SPEED;
}
else {
xVel = 0;
}
// Handle jumping
static bool isJumping = false;
if (keyboardState[SDL_SCANCODE_SPACE] && !isJumping) {
isJumping = true;
yVel = -JUMP_SPEED;
}
// Update character position
xPos = 200; // += xVel;
yPos += yVel;
if (xPos > BORDER) { xPos = BORDER; }
if (xPos < 0) { xPos = 0; }
// Apply gravity
if (yPos < BOTTOM - 58) {
yVel += 1; // apply gravity
}
else {
yVel = 0;
isJumping = false;
}
// Clear screen
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
// Render background
SDL_RenderCopy(renderer, backgroundTexture, NULL, NULL);
SDL_RenderCopy(renderer, Texttexture, NULL, &dstrect);
// Render obstacles
for (auto& obstacle : obstacles) {
obstacle.move();
obstacle.draw(renderer);
}
/*
// Remove obstacles that are off screen
for (int i = 0; i < obstacles.size(); i++) {
if (obstacles[i].isOffScreen()) {
obstacles.erase(obstacles.begin() + i);
}
}
*/
// Render character
character.render(renderer, xPos, yPos);
// Update Screen
SDL_RenderPresent(renderer);
frameCount++;
Uint32 frameTime = SDL_GetTicks() - frameStart; // Milliseconds
Sekunden = SDL_GetTicks() - FPS_Start;
if (Sekunden > 1000) {
sprintf_s(puffer, "Frames: %d", frameCount);
frameCount = 0;
FPS_Start = SDL_GetTicks();
}
// control fps
if (frameTime < sollzeit) { SDL_Delay(sollzeit - frameTime); }
}
SDL_DestroyTexture(backgroundTexture);
SDL_DestroyTexture(textTexture);
TTF_CloseFont(font);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I filled the obstable-rect with black (Rectfill) and then there's only a black square, but no image. I also tried to use only one obstacle, it worked then. but as I tried with vector, it seems to display the wrong texture/pointer/whatever.