c++ sfml - changing the sprite isn't working - c++

I was working on changing sprite in my SFML project but it just doesn't want to wark. I tried everything - pointers, refrences and normal string objects. You can see in debug console i printed out this->path that containted a path to file to change but when it left the function this->path was null (empty "" string). Can you please help me? Here's the code:
Player.cpp
#include "Player.h"
#include <iostream>
Player::Player(std::string path)
{
this->path = path;
texture.loadFromFile(path);
sprite.setTexture(texture);
sprite.setPosition(500.f, 700.f);
}
void Player::update()
{
// Movement //
//if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
//sprite.move(0.f, -velocity);
//if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
//sprite.move(0.f, velocity);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
sprite.move(-velocity, 0.f);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
sprite.move(velocity, 0.f);
// Movement //
float szerokosc = sprite.getGlobalBounds().width;
float wysokosc = sprite.getGlobalBounds().height;
// Collision with screen //
// Left
if (sprite.getPosition().x < 0.f)
sprite.setPosition(0.f, sprite.getPosition().y);
// Top
if (sprite.getPosition().y < 0.f)
sprite.setPosition(sprite.getPosition().x, 0.f);
// Right
if (sprite.getPosition().x + szerokosc > 1000)
sprite.setPosition(1000 - szerokosc, sprite.getPosition().y);
// Bottom
if (sprite.getPosition().y + wysokosc > 800)
sprite.setPosition(sprite.getPosition().x, 800 - wysokosc);
// Collision with screen //
}
sf::Sprite Player::getSprite()
{
return sprite;
}
bool Player::collides(Food obj)
{
if (sprite.getGlobalBounds().intersects(obj.getSprite().getGlobalBounds()))
return true;
else
return false;
}
void Player::changeSkin(std::string path)
{
this->path = path;
std::cout << "changeSkin(): *this->path" << this->path << std::endl;
std::cout << "changeSkin(): *path" << path << std::endl;
texture.loadFromFile(path);
sprite.setTexture(texture);
}
void Player::updateSkin()
{
std::cout << "updateSkin() *this->path: " << this->path << std::endl;
std::cout << "updateSkin() *path: " << path << std::endl;
}
Player::~Player()
{
//delete texture;
//delete sprite;
}
Player.h
#pragma once
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <time.h>
#include "Food.h"
#include "ShopItem.h"
class Player
{
sf::Texture texture;
sf::Sprite sprite;
std::string path;
bool has_skin = false;
float velocity = 5.f;
public:
explicit Player(std::string path);
~Player();
void update();
sf::Sprite getSprite();
bool collides(Food obj);
void changeSkin(std::string path);
void updateSkin();
};
main.cpp - main() has Player::updateSkin() call
int main()
{
RenderWindow window(VideoMode(1000, 800), "Tomczyszyn Eater v0.21 BETA");
window.setFramerateLimit(60);
srand(time(nullptr));
Texture bg_text;
bg_text.loadFromFile("Assets/Textures/bg.png");
Sprite bg{ bg_text };
Player player{ "Assets/Textures/player.png" };
time_t start{};
Event event;
Intro* intro = new Intro{window};
MainMenu* menu = new MainMenu{&window};
Shop shop(&window);
Game game{player, &window};
bool intro_deleted{ false };
bool menu_deleted{ false };
bool game_started{ false };
int menuState{ 2 };
while (window.isOpen())
{
while (window.pollEvent(event))
{
if (event.type == Event::EventType::Closed)
window.close();
if (Keyboard::isKeyPressed(Keyboard::Space) && game.gameRunning() == false)
{
start = time(nullptr);
game.runGame();
}
else if (Keyboard::isKeyPressed(Keyboard::Escape) && game.gameRunning() == false)
{
menuState = 0;
}
}
window.clear();
if (game.gameRunning() == true && menuState == 1) // Main Game
{
if (game_started == false)
{
start = time(nullptr);
game_started = true;
}
if (intro_deleted == false)
{
delete intro;
intro_deleted = true;
}
if (menu_deleted == false)
{
delete menu;
menu_deleted = true;
}
window.draw(bg);
game.drawMoney();
player.update();
window.draw(player.getSprite());
// Player::updateSkin() - source of the problem
player.updateSkin();
game.update();
game.draw();
if (time(nullptr) - start == 2)
{
start = time(nullptr);
int liczba = rand() % 6 + 1;
string file_name{ "Assets/Textures/food" + to_string(liczba) + ".png" };
Food* newFood = new Food{file_name};
game.spawn(newFood);
}
game.catched();
game.fell();
}
else if (menuState == 0) // Menu
{
if (menu_deleted == true) menu = new MainMenu{ &window };
menu->draw();
menu->update(menuState);
menu_deleted = false;
}
else if (menuState == -1) // Intro
{
start = time(nullptr);
intro->play();
if (intro->intro_started() == true) menuState = 0;
}
else if (menuState == 2) // Shop
{
shop.draw();
shop.backIfClicked(menuState);
shop.checkIfBought(player, game.balance());
game.drawMoney();
}
else
{
game.drawDeathScreen();
}
window.display();
}
}
Shop.cpp - checkIfBought() has Player::changeSkin() call
void Shop::checkIfBought(Player player, int& money)
{
for (int i = 0; i < skins.size(); i++)
{
if (isClicking(skins[i].getSprite()) == true)
{
skins[i].buy(money);
player.changeSkin(skins[i].getPath()); //Plaer::changeSkin() here - source of the problem
std::cout << skins[i].getPath() << std::endl;
}
}
for (int i = 0; i < bg_skins.size(); i++)
{
if (isClicking(bg_skins[i].getSprite()) == true)
{
bg_skins[i].buy(money);
player.changeSkin(bg_skins[i].getPath()); //Plaer::changeSkin() here - source of the problem
}
}
}
Debug Console output:
changeSkin(): this->path = Assets/Textures/skin1.png
changeSkin(): path = Assets/Textures/skin1.png
Assets/Textures/skin1.png
updateSkin() this->path = Assets/Textures/player.png
updateSkin() path = Assets/Textures/player.png
Sorry if you didn't understand my english is bad. I really do need help i've spent so much time on fixing this that i just gave up.

Related

How to reset values after dying

I am making a google chrome dinosaur game using an SDL Template for graphics and I am almost finished but I have run into the issue of needing to be able to reset to the starting values of the game just like how you reset when you hit spacebar after dying in the google chrome dinosaur game. I have made an isGameOver function but I don't know how to reset the values to start a new game which is my main problem.
this is my GameScene class where the game over logic is located
GameScene.h
#pragma once
#include "Scene.h"
#include "GameObject.h"
#include "Player.h"
#include "Floor.h"
#include "Obstacle.h"
#include "FlyingObstacle.h"
#include <vector>
#include "util.h"
#include "text.h"
class GameScene : public Scene
{
public:
GameScene();
~GameScene();
void start();
void draw();
void update();
std::vector<Obstacle*> spawnedObstacle;
std::vector<FlyingObstacle*> spawnedBird;
private:
Player* player;
Floor* floor;
float spawnTime;
float currentSpawnTimer;
void floorCollision();
void obstacleCollision();
void birdCollision();
void obstacleSpawn();
void birdSpawn();
void despawnObstacle(Obstacle* obstacle);
void despawnBird(FlyingObstacle* bird);
int points;
int highscore;
bool isGameOver;
};
GameScene.cpp
#include "GameScene.h"
GameScene::GameScene()
{
// Register and add game objects on constructor
player = new Player();
this->addGameObject(player);
floor = new Floor();
this->addGameObject(floor);
points = 0;
highscore = 0;
}
GameScene::~GameScene()
{
delete player;
}
void GameScene::start()
{
Scene::start();
// Initialize any scene logic here
initFonts();
isGameOver = true;
currentSpawnTimer = 300;
spawnTime = rand() % 300; //spawn time of 5 seconds
for (int i = 0; i < 1; i++)
{
obstacleSpawn();
}
for (int i = 0; i < 3; i++)
{
birdSpawn();
}
}
void GameScene::draw()
{
Scene::draw();
drawText(110, 20, 255, 255, 255, TEXT_CENTER, "POINTS: %03d", points);
if (player->getIsAlive() == true)
{
drawText(900, 20, 255, 255, 255, TEXT_CENTER, "PRESS SPACE TO START MOVING");
}
if (player->getIsAlive() == false)
{
if (isGameOver == false)
drawText(SCREEN_WIDTH / 2, 200, 255, 255, 255, TEXT_CENTER, "YOU LOSE! PRESS SPACE TO SHOW POINTS");
if (isGameOver == true)
{
drawText(SCREEN_WIDTH / 2, 200, 255, 255, 255, TEXT_CENTER, "HIGHSCORE: %03d", highscore);
if (points > highscore)
{
drawText(SCREEN_WIDTH / 2, 200, 255, 255, 255, TEXT_CENTER, "NEW HIGHSCORE: %03d", points, highscore);
}
}
}
}
void GameScene::update()
{
if (isGameOver == true)
{
if (app.keyboard[SDL_SCANCODE_SPACE])
{
isGameOver = false;
}
}
if (isGameOver == false)
{
Scene::update();
floorCollision();
obstacleCollision();
birdCollision();
if (currentSpawnTimer > 0)
currentSpawnTimer--;
if (currentSpawnTimer <= 0)
{
for (int i = 0; i < 1; i++)
{
obstacleSpawn();
}
for (int i = 0; i < 3; i++)
{
birdSpawn();
}
currentSpawnTimer = spawnTime;
}
//This is where Gravity strength is located
if (player->getOnFloor() == false) {
player->setY(player->getY() + 7);
}
else {
player->getY() + 0;
}
}
}
void GameScene::floorCollision()
{
//Checks for collisions
for (int i = 0; i < objects.size(); i++)
{
//Cast to floor
Floor* floor = dynamic_cast<Floor*>(objects[i]);
//Check if the floor was casted
if (floor != NULL)
{
int collision = checkCollision(
player->getX(), player->getY(), player->getWidth(), player->getHeight(),
floor->getX(), floor->getY(), floor->getWidth(), floor->getHeight()
);
if (collision == 1)
{
player->setOnFloor(true);
if (player->getIsAlive() == true)
{
points++;
highscore++;
}
break;
}
}
}
}
void GameScene::obstacleCollision()
{
for (int i = 0; i < objects.size(); i++)
{
Obstacle* obstacle = dynamic_cast<Obstacle*>(objects[i]);
if (obstacle != NULL)
{
if (obstacle != NULL)
{
int collision = checkCollision(
player->getX(), player->getY(), player->getWidth(), player->getHeight(),
obstacle->getX(), obstacle->getY(), obstacle->getWidth(), obstacle->getHeight()
);
if (collision == 1)
{
player->doDeath();
isGameOver = true;
break;
}
}
}
}
}
void GameScene::birdCollision()
{
for (int i = 0; i < objects.size(); i++)
{
FlyingObstacle* bird = dynamic_cast<FlyingObstacle*>(objects[i]);
if (bird != NULL)
{
if (bird != NULL)
{
int collision = checkCollision(
player->getX(), player->getY(), player->getWidth(), player->getHeight(),
bird->getX(), bird->getY(), bird->getWidth(), bird->getHeight()
);
if (collision == 1)
{
player->doDeath();
isGameOver = true;
break;
}
}
}
}
}
void GameScene::obstacleSpawn()
{
Obstacle* obstacle = new Obstacle();
this->addGameObject(obstacle);
obstacle->setPosition(1200, 300 + (rand() % 300));
spawnedObstacle.push_back(obstacle);
}
void GameScene::birdSpawn()
{
FlyingObstacle* bird = new FlyingObstacle();
this->addGameObject(bird);
bird->setPos(1200, 300 + (rand() % 300));
spawnedBird.push_back(bird);
}
void GameScene::despawnObstacle(Obstacle* obstacle)
{
int index = -1;
for (int i = 0; i < spawnedObstacle.size(); i++)
{
//If pointer matches
if (obstacle == spawnedObstacle[i])
{
index = i;
break;
}
}
//If any match is found
if (index != -1)
{
spawnedObstacle.erase(spawnedObstacle.begin() + index);
delete obstacle;
}
}
void GameScene::despawnBird(FlyingObstacle* bird)
{
int index = -1;
for (int i = 0; i < spawnedBird.size(); i++)
{
//If pointer matches
if (bird == spawnedBird[i])
{
index = i;
break;
}
}
//If any match is found
if (index != -1)
{
spawnedBird.erase(spawnedBird.begin() + index);
delete bird;
}
}
I tried making an isGameOver bool inside my GameScene.h and I made it so that pressing spacebar would reset the game but in reality when the player dies the screen pauses every movement instead of resetting and if I press space again the game continues to move even though the player is dead.
Your entry point for the game(probably main function will probably have some form like this)
#include ...
#include ...
...
int main()
{
bool game_running = true;
while(game_running)
{
GameInstance* game = new Game(); //Allocation and initialization of all resources needed to play the game.
game.play(); // This function will finish when you lose the game.
delete game; // Deallocation.
if(!run_again())
{
game_running = false;
}
}
return 0;
}
After deallocation, you check if user wants to play again, you enter the next iteration of while loop, and new instance of Game is allocated, where all the resource handling takes place. The only problem is that allocating Game instance for every iteration might be a little costly, but you can ignore that if you don't worry about performance much.

SDL2 C++ Snake Game Self Collision

As a school project, I've made the classic snake game using SDL2 and C++.
I've already implemented the growing, moving features for the Snake but it was required to make the movement based on a grid, but when I implemented the grid feature, the self-collision was always triggering whenever grow one part, so every time I start the game, and eat the first fruit, the snake dies.
I've been trying for a while now, from placing a delay to the adding of the tail and delaying the collision check, but to no avail, it's always colliding with itself even though it is not.
I can't see what is wrong with the self collision, I would gladly appreciate it if someone can point out what's wrong.
Snake.h
#include "GameObject.h"
#include "common.h"
#include "draw.h"
#include "Food.h"
#include "util.h"
#include <vector>
struct Segment {
int x;
int y;
Segment(int posx, int posy) {
x = posx;
y = posy;
}
};
class Snake :
public GameObject
{
public:
~Snake();
void start();
void update();
void draw();
void outOfBoundsCheck();
void move();
void addSegment(int x, int y);
void selfCollisionCheck(bool hasEaten);
void setHasMoved(bool a);
void setIsAlive(bool a);
int getX();
int getY();
int getWidth();
int getHeight();
bool getIsAlive();
bool getHasMoved();
std::vector<Segment*> const& getV() const;
private:
std::vector<Segment*> body;
SDL_Texture* headTexture;
SDL_Texture* bodyTexture;
int x;
int y;
int width;
int height;
int dx;
int dy;
int tempX;
int tempY;
bool isAlive;
bool hasMoved;
};
Snake.cpp
Snake::~Snake()
{
}
void Snake::start()
{
// Load Texture
headTexture = loadTexture("gfx/player.png");
bodyTexture = loadTexture("gfx/body.png");
tempX = 0;
tempY = 0;
x = 0;
y = 0;
dx = 0;
dy = 0;
isAlive = true;
hasMoved = false;
width = 0;
height = 0;
SDL_QueryTexture(headTexture, NULL, NULL, &width, &height);
addSegment(x, y);
}
void Snake::update()
{
std::cout << "Head" << body[0]->x << std::endl;
if (body.size() > 1) {
std::cout << "2nd Segment" << body[1]->x << std::endl;
if (body.size() > 2) {
std::cout << "3nd Segment" << body[2]->x << std::endl;
}
}
move();
outOfBoundsCheck();
}
void Snake::draw()
{
if (!isAlive) return; // Cancel the render if player dies
for (int i = 0; i < body.size(); i++) {
blit(headTexture, body[i]->x, body[i]->y);
}
}
void Snake::outOfBoundsCheck()
{
for (int i = 0; i < body.size(); i++) {
if (body[i]->x > SCREEN_WIDTH) {
body[i]->x = 0;
}
if (body[i]->x < 0) {
body[i]->x = SCREEN_WIDTH;
}
if (body[i]->y > SCREEN_HEIGHT) {
body[i]->y = 0;
}
if (body[i]->y < 0) {
body[i]->y = SCREEN_HEIGHT;
}
}
}
void Snake::move()
{
if (app.keyboard[SDL_SCANCODE_W] && dy != 5) {
dx = 0;
dy = -5;
}
if (app.keyboard[SDL_SCANCODE_A] && dx != 5) {
dx = -5;
dy = 0;
}
if (app.keyboard[SDL_SCANCODE_S] && dy != -5) {
dx = 0;
dy = 5;
}
if (app.keyboard[SDL_SCANCODE_D] && dx != -5) {
dx = 5;
dy = 0;
}
Segment* snakeHead = *(body.begin()); //Grid
tempX += dx;
tempY += dy;
if (tempX % 25 == 0) {
snakeHead->x += tempX;
tempX = 0;
}
if (tempY % 25 == 0) {
snakeHead->y += tempY;
tempY = 0;
}
for (int i = body.size() - 1; i > 0; i--) { //For the other parts to follow
body[i]->x = body[i - 1]->x;
body[i]->y = body[i - 1]->y;
}
}
void Snake::addSegment(int x, int y)
{
Segment* seg = new Segment(x, y );
body.push_back(seg);
}
void Snake::selfCollisionCheck(bool hasEaten) // Fail
{
Segment* head = body[0];
if (hasEaten == false) {
for (int i = 1; i < body.size(); i++) {
if (head->x == body[i]->x && head->y == body[i]->y) {
isAlive = false;
break;
}
}
}
else {
return;
}
}
void Snake::setHasMoved(bool a)
{
hasMoved = a;
}
void Snake::setIsAlive(bool a)
{
isAlive = a;
}
int Snake::getX()
{
return x;
}
int Snake::getY()
{
return y;
}
int Snake::getWidth()
{
return width;
}
int Snake::getHeight()
{
return height;
}
bool Snake::getIsAlive()
{
return isAlive;
}
bool Snake::getHasMoved()
{
return hasMoved;
}
std::vector<Segment*> const& Snake::getV() const
{
// TODO: insert return statement here
return body;
}
GameScene.h
#include "Scene.h"
#include "GameObject.h"
#include "Snake.h"
#include "Food.h"
#include "util.h"
#include "text.h"
#include "SoundManager.h"
class GameScene : public Scene
{
public:
GameScene();
~GameScene();
void start();
void draw();
void update();
void spawnFood();
void collisionLogic();
void selfCollision();
void despawnFood(Food* food);
private:
Snake* snake;
Food* food;
int points;
std::vector<Food*> spawnedFood;
};
GameScene.cpp
#include "GameScene.h"
GameScene::GameScene()
{
// Register and add game objects on constructor
snake = new Snake();
this->addGameObject(snake);
points = 0;
}
GameScene::~GameScene()
{
delete snake;
delete food;
}
void GameScene::start()
{
Scene::start();
// Initialize any scene logic here
initFonts();
spawnFood();
}
void GameScene::draw()
{
Scene::draw();
drawText(110, 20, 255, 255, 255, TEXT_CENTER, "POINTS: %03d", points);
if (snake->getIsAlive() == false) {
drawText(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 255, 255, 255, TEXT_CENTER, "GAME OVER!");
}
}
void GameScene::update()
{
Scene::update();
if (spawnedFood.size() == 0 && spawnedFood.size() != 1) {
spawnFood();
}
collisionLogic();
selfCollision();
}
void GameScene::spawnFood()
{
int random = rand() % 720;
if (random % 25 != 0) {
random = rand() % 720;
}
else {
Food* food = new Food();
this->addGameObject(food);
food->setPosition(rand() % SCREEN_WIDTH, rand() % SCREEN_HEIGHT);
spawnedFood.push_back(food);
}
}
void GameScene::collisionLogic()
{
Segment* head = snake->getV()[0];
std::vector<Segment*> snakeBody = snake->getV();
for (int i = 0; i < objects.size(); i++) {
Food* food = dynamic_cast<Food*>(objects[i]);
if (food != NULL) {
int collision = checkCollision(
head->x, head->y, snake->getWidth(), snake->getHeight(),
food->getX(), food->getY(), food->getWidth(), food->getHeight()
);
if (collision == 1) {
despawnFood(food);
snake->addSegment(snakeBody[snakeBody.size() - 1]->x, snakeBody[snakeBody.size() - 1]->y); //Adds a part to the snake
points++;
break;
}
}
}
}
void GameScene::selfCollision()
{
std::vector<Segment*> body = snake->getV();
Segment* head = snake->getV()[0];
for (int i = 1; i < snake->getV().size(); i++) {
if (head->x == body[i]->x && head->y == body[i]->y) {
snake->setIsAlive(false);
break;
}
}
}
void GameScene::despawnFood(Food* food)
{
int index = -1;
for (int i = 0; i < spawnedFood.size(); i++) {
if (food == spawnedFood[i]) {
index = i;
break;
}
}
if (index != -1) {
spawnedFood.erase(spawnedFood.begin() + index);
delete food;
}
}
It seems that I had some logical errors when it comes to the grid movement because when I re-coded everything and changed the grid movement into cell based instead of using modulo condition by dividing the screen width and height to the pixel size of my snake and using that as the coordinates for my movement, everything went back to normal and the collision bug disappeared.
Instead of doing this for the grid movement
Old Grid Movement Code
tempX += dx;
tempY += dy;
if (tempX % 25 == 0) {
snakeHead->x += tempX;
tempX = 0;
}
if (tempY % 25 == 0) {
snakeHead->y += tempY;
tempY = 0;
}
I defined this as a permanent value in my defs.h
defs.h
#define CELL_SIZE 25 // Size of the segment
#define CELL_WIDTH SCREEN_WIDTH / CELL_SIZE
#define CELL_HEIGHT SCREEN_HEIGHT / CELL_SIZE
After that, since I'm still going to render the picture with the default resolution, I multiplied CELL_SIZE to the dest variable of my blit function
draw.cpp
void blit(SDL_Texture* texture, int x, int y)
{
SDL_Rect dest;
dest.x = x * CELL_SIZE;
dest.y = y * CELL_SIZE;
SDL_QueryTexture(texture, NULL, NULL, &dest.w, &dest.h);
SDL_RenderCopy(app.renderer, texture, NULL, &dest);
}
This results to the snake and any other thing that I'm going to render to follow a grid and by assigning the x and y values with the CELL_WIDTH and CELL_HEIGHT as substitution to the resolution, I accomplished the grid movement with no conflict with my collision check.

C++ "Unable to read memory" when accessing pointer object from inherited class

I have this error:
Exception thrown at 0x0108C6E9 in myprojectname.exe: 0xC0000005: Access violation reading location 0x00000028.
However, this only happens when I call a function from the base class via the derived class.
derived class:
#pragma once
#include "Player.h"
class Space;
class Enemy : public Player{
public:
void init(Space * s);
private:
//Space * space = nullptr;
};
CPP file:
#include "Space.h"
#include "Enemy.h"
#include "Player.h"
void Enemy::init(Space * s) {
//space = s;
}
I need a pointer to the space object because my base class also needs that. I am not sure if this is needed.
This is how I call the functions of the base(Player) class:
space->getEnemy().drawPlayer(); //FIRST I GET THE OBJECT OF THE DERIVED(ENEMY CLASS) AND THAN I CALL A FUNCTION FROM THE BASE CLASS(PLAYER CLASSS)
The error message "Unable to read memory" happens in getter functions in a class that the base class needs(for example a pointer to the window).
Does anyone know what I am doing wrong?
EDIT
I forgot to tell: I initialize that space pointer to my import class named Space, in every class of my project. The program works fine with those space pointers if I don't call the inherited stuff of Enemy class
Space.h
#pragma once
#include "Window.h"
#include "Game.h"
#include "Input.h"
#include "Text.h"
#include "Player.h"
#include "Enemy.h"
#include <ctime>
class Space {
public:
void init();
int getStartTime();
Window & getWindow();
Game & getGame();
Input & getInput();
Text & getText();
Player & getPlayer();
Enemy & getEnemy();
private:
Text textObj;
Window windowObj;
Game gameObj;
Input inputObj;
Player playerObj;
Enemy enemyObj;
int startTime = clock();
};
Space.cpp:
#include "Space.h"
//PASSING THE SPACE CLASS OBJECT TO THE INIT FUNCTIONS OF THE OTHER CLASSES
void Space::init(){
windowObj.init(this);
gameObj.init(this);
inputObj.init(this);
textObj.init(this);
playerObj.init(this);
enemyObj.init(this);
//STARTING THE GAME ACTUALLY
windowObj.createWindow();
}
Enemy & Space::getEnemy() {
return enemyObj;
}
Window & Space::getWindow(){
return windowObj;
}
Game & Space::getGame() {
return gameObj;
}
Input & Space::getInput() {
return inputObj;
}
Text & Space::getText() {
return textObj;
}
Player & Space::getPlayer(){
return playerObj;
}
int Space::getStartTime(){
return startTime;
}
Player.h(has space pointer):
#pragma once
class Space;
class Player {
public:
void init(Space * s);
void drawPlayer();
void setPlayerXSpeed(float speed);
void move();
void jump();
void checkFalling();
void setJumping(bool value);
void setAttacking(bool value);
void projectileAttack();
float getPlayerX();
float getPlayerY();
private:
Space * space;
int sprites = 8;
int chanceToMove = 0;
int times = 0;
int spriteCount = 0;
float spritePart = 0.0f;
float spritePiece;
float playerX = -0.7f;
float playerY = -0.42f;
float playerXSpeed = 0.0f;
float playerYSpeed = 0.0f;
bool ableToChangeY = true;
bool jumping = false;
bool falling = false;
bool strafeRight = true;
bool attacking = false;
};
Player.cpp:
#include "Player.h"
#include "Space.h"
#include <SDL2\SDL_opengl.h>
#include <iostream>
#define MAX_JUMP_HEIGHT 0.2f
#define SPAWN_X -0.42f
void Player::init(Space * s){ //INITIALIZING SPACE CLASS OBJECT
space = s;
spritePiece = 0.125f;
}
void Player::drawPlayer(){
glPushMatrix();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, space->getWindow().getTexture(1));
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
//PART OF THE SPRITESHEET DRAWING COORDINATES
glTexCoord2f(spritePart, 0.0f); if (strafeRight) { glVertex2f(playerX , playerY + 0.52f); } else { glVertex2f(playerX , playerY + 0.52f); }
glTexCoord2f(spritePart + spritePiece, 0.0f); if (strafeRight) { glVertex2f(playerX + 0.13f, playerY + 0.52f); } else { glVertex2f(playerX - 0.13f, playerY + 0.52f); }
glTexCoord2f(spritePart + spritePiece, 1.0f); if (strafeRight) { glVertex2f(playerX + 0.13f, playerY) ; } else { glVertex2f(playerX - 0.13f, playerY ); }
glTexCoord2f(spritePart, 1.0f); if (strafeRight) { glVertex2f(playerX , playerY) ; } else { glVertex2f(playerX , playerY ); }
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
void Player::move(){
chanceToMove++;
if (!attacking){ //NORMAL WALK ANIMATION
if (playerXSpeed != 0.0f) {
if (spriteCount != sprites - 3) { //IF CURRENT PART IS NOT THE LAST PART
if (chanceToMove % 4 == 0) { //SO THE ANIMATION IS NOT AS FAST AS SANIC IS
spritePart += spritePiece;
spriteCount++;
}
}else {
spritePart = 0.0f;
spriteCount = 0;
}
}else {
spritePart = 0.0f; //ALSO RESET
}
}else { //ATTACKING
spritePart = spritePiece * (sprites - 2); //ATTACK SPRITE
projectileAttack();
if (times == 5) {
attacking = false;
times = 0;
}else {
times++;
}
}
if (playerXSpeed < 0) { //IF PLAYER IS MOVING LEFT
strafeRight = false;
}else {
strafeRight = true; //MOVING RIGHT
}
if (jumping) {
jump();
}
playerX += playerXSpeed; //UPDATING PLAYER POSITIONS
playerY += playerYSpeed;
}
void Player::checkFalling() {
if ((playerX < space->getGame().getPlatformLeft() - 0.1f || playerX > space->getGame().getPlatformRight() - 0.05f) && playerY < -0.4f) { //IF PLAYER JUMPED OFF THE PLATFORM
ableToChangeY = false;
playerYSpeed = -0.03f;
}if (playerY < -2.0f) { //IF PLAYER FELL TO DEATH(RIP)
space->getGame().stopGame();
}
}
void Player::setJumping(bool value){
jumping = value;
}
void Player::setAttacking(bool value){
attacking = value;
}
void Player::projectileAttack(){
}
void Player::jump(){
spritePart = spritePiece * (sprites-1); //JUMPING SPRITE
if (ableToChangeY) { //IF PLAYER IS NOT FALLING RIP
if (playerY < MAX_JUMP_HEIGHT && !falling) { //WHILE THE PLAYER DID NOT PASS THE MAXIMUM JUMP HEIGHT
playerYSpeed = 0.03f;
}else { //IF THE PLAYER JUMPED TOO HIGH
falling = true;
if (playerY > SPAWN_X) {
playerYSpeed = -0.03f;
}else { //PLAYER IS BACK ON EARTH
jumping = false;
falling = false;
playerYSpeed = 0.0f;
}
}
}
}
void Player::setPlayerXSpeed(float speed){
playerXSpeed = speed;
}
float Player::getPlayerX()
{
return playerX;
}
float Player::getPlayerY(){
return playerY;
}
EDIT MAIN FUNCTION
#include "Space.h"
#include <iostream>
#include <SDL2\SDL.h>
#include <SDL2\SDL_opengl.h>
#include <SDL2\SDL_ttf.h>
#undef main
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_EVERYTHING);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
TTF_Init();
Space space;
space.init();
std::cout << "Type something and press ENTER to quit..." << std::endl;
char temp;
std::cin >> temp;
TTF_Quit();
SDL_Quit();
return 0;
}

Snake Rectangle Vector Collision

I'm new to SFML and C++ so I'm trying to learn both at the same time. I've decided to write a Snake game. For my snakes body I am using a vector of RectangleShapes. I've drawn a berry in the center of the screen and I can detect when the head of my snake is in collision with the berry, however I have no idea how to test if the snake is colliding with itself.
I've thought about testing collision between the head of the snake against the entire vector of blocks, but this will always return true as the head of the snake is in collision with itself.
I would appreciate any suggestions and criticisms of my code, Thanks!
#include <iostream>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <string>
#include <sstream>
using namespace sf;
constexpr int windowWidth{800}, windowHeight{600};
Vector2f blockLocation{0, 0};
struct Block
{
RectangleShape shape;
Vector2f blockSize{15,15};
Block(float posX, float posY)
{
shape.setPosition(posX, posY);
shape.setSize(blockSize);
shape.setFillColor(Color::Blue);
shape.setOutlineColor(Color::Green);
shape.setOutlineThickness(3);
}
};
struct Berry
{
CircleShape shape;
Berry(float posX, float posY)
{
shape.setPosition(posX, posY);
shape.setRadius(8);
shape.setFillColor(Color::Red);
shape.setOutlineColor(Color::Magenta);
shape.setOutlineThickness(3);
}
};
bool keyUp(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Up)) return true;
return false;
}
bool keyDown(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Down)) return true;
return false;
}
bool keyLeft(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Left)) return true;
return false;
}
bool keyRight(void)
{
if(Keyboard::isKeyPressed(Keyboard::Key::Right)) return true;
return false;
}
int stat(std::vector<Block> *blocks, RenderWindow *window)
{
sf::Font font;
if(!font.loadFromFile("Oswald-Bold.ttf"))
{
std::cerr << "Cannot load font!" << std::endl;
return 1;
}
sf::Text text;
text.setFont(font);
std::ostringstream message;
message << "x: " << blockLocation.x << std::endl
<< "y: " << blockLocation.y << std::endl
<< "blocks: " << blocks->size() << std::endl;
text.setString(message.str());
text.setCharacterSize(24);
text.setColor(sf::Color::Magenta);
text.setOrigin(0, 0);
window->draw(text);
return 0;
}
bool collision(Block *shapeA, Berry *shapeB)
{
if( shapeA->shape.getGlobalBounds().intersects(shapeB->shape.getGlobalBounds()) )
{
std::cout << "collision with ";
std::cout << "x: " << shapeA->shape.getPosition().x << "y: " <<
shapeA->shape.getPosition().y << "and x: " << shapeB->shape.getPosition().x << "y: " << shapeB->shape.getPosition().y << std::endl;
return true;
}
else
return false;
}
int main(void)
{
Clock clock;
Time timeSinceLastUpdate = Time::Zero;
const Time TimePerFrame = seconds(3.0f/30.f);
std::vector<Block> blocks;
RenderWindow window{ {windowWidth, windowHeight} , "blocks!"};
bool up(false);
bool down(false);
bool left(false);
bool right(false);
window.setFramerateLimit(60);
Berry berry(400, 300);
blocks.emplace_back(blockLocation.x, blockLocation.y);
while(window.isOpen())
{
if(Keyboard::isKeyPressed(Keyboard::Key::Escape)) return 0;
Time elapsedTime = clock.restart();
timeSinceLastUpdate += elapsedTime;
while(timeSinceLastUpdate > TimePerFrame)
{
timeSinceLastUpdate -= TimePerFrame;
window.clear(Color::Black);
// Get the Head of the snake
auto first = blocks.back();
if(keyUp())
{
up = true;
down = false, left = false, right = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
else if(keyDown())
{
down = true;
up = false, left = false, right = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
else if(keyLeft())
{
left = true;
right = false, up = false, down = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
else if(keyRight())
{
right = true;
left = false, up = false, down = false;
blocks.emplace_back(blockLocation.x, blockLocation.y);
blocks.erase(blocks.begin());
}
if(up) { blockLocation.y-=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if(down) { blockLocation.y+=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if(left) { blockLocation.x-=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if(right){ blockLocation.x+=19; blocks.emplace_back(blockLocation.x, blockLocation.y); blocks.erase(blocks.begin());
}
if (collision(&first, &berry)) blocks.emplace_back(blockLocation.x, blockLocation.y);
if(blocks.size() > 50)
{
blocks.erase(blocks.begin());
}
for(auto a : blocks)
{
window.draw(a.shape);
}
window.draw(berry.shape);
stat(&blocks, &window);
window.display();
}
}
return 0;
}

SDL Tile Map Rendering Error C++/C

So I am making a 2D platformer using SDL. I have experience in C/C++, but I haven't really written anything with it in the past 8 months. I'm using SDL to render my graphics, and I get an entirely blank screen, and I can't really seem to figure out why. Can anybody help me figure out why this isn't rendering?
EDIT: I added the extra code that was missing.
Map.cpp
#include "Map.h"
int map[10][10] = { {0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0}
};
Map::Map()
: g( Graphics() )
{
grassTile = SDL_LoadBMP("grass.bmp");
}
Map::~Map()
{
}
void Map::renderMap()
{
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
int newPos = map[y][x];
if (newPos == 0)
{
g.drawImage(x * 32, y * 32, grassTile);
}
}
}
}
Graphics.cpp
#include "Graphics.h"
#include <iostream>
#include <SDL.h>
#include <Windows.h>
using namespace std;
Graphics::Graphics()
: count( 0 )
{
}
Graphics::~Graphics()
{
}
int Graphics::getWidth(int i)
{
return this->width = i;
}
int Graphics::getHeight(int i)
{
return this->height = i;
}
void Graphics::initScreen(int width,int height, char* title)
{
if (!SDL_Init(SDL_INIT_EVERYTHING) == 1)
{
cout << "SDL is running" << endl;
}
SDL_WM_SetCaption(title,NULL);
screen = SDL_SetVideoMode(width,height,8,NULL);
getWidth(width);
getHeight(height);
}
void Graphics::beginFrame()
{
SDL_FillRect(screen,NULL,0x000000);
}
void Graphics::repaint()
{
SDL_Flip(screen);
}
void Graphics::loadImage(char* location, SDL_Surface* sur)
{
sur = SDL_LoadBMP(location);
}
void Graphics::renderTileMap(SDL_Surface* sur, int width, int height, int amountX, int amountY)
{
for (int y = 0; y < amountY; y++)
{
for (int x = 0; x < amountX; x++)
{
drawImage(x * width, y * height, sur);
}
}
}
void Graphics::pixel(int x,int y, int r,int g, int b)
{
if (screen != NULL)
{
if (screen->pixels != NULL)
{
Uint8* pixels = (Uint8*)screen->pixels;
Uint8* indevidualPixel = pixels + (y * screen->pitch) + x;
*indevidualPixel = SDL_MapRGB(screen->format,r,g,b);
}
}
}
void Graphics::drawImage(int x,int y, SDL_Surface* sur)
{
SDL_Rect rect;
rect.x = x;
rect.y = y;
SDL_BlitSurface(sur,NULL,screen,&rect);
}
Main.cpp>
#include <SDL.h>
#include <cstdio>
#include "Graphics.h"
#include "Keyboard.h"
#include "Game.h"
SDL_Event event;
bool running = true;
Game game = Game();
int main(int argc, char* argv[])
{
game.k = Keyboard();
game.g.initScreen(900,500, "theDevCorner's SDL Tutorials!!!");
while (running)
{
SDL_PollEvent(&event);
if (event.type == SDL_QUIT)
{
running = false;
}
if (event.type == SDL_KEYUP)
{
SDLKey keyReleased = event.key.keysym.sym;
if (keyReleased == SDLK_RIGHT)
{
game.k.right = false;
}
if (keyReleased == SDLK_LEFT)
{
game.k.left = false;
}
if (keyReleased == SDLK_DOWN)
{
game.k.down = false;
}
if (keyReleased == SDLK_UP)
{
game.k.up = false;
}
}
if (event.type == SDL_KEYDOWN)
{
SDLKey keyPressed = event.key.keysym.sym;
if (keyPressed == SDLK_RIGHT)
{
game.k.right = true;
}
if (keyPressed == SDLK_LEFT)
{
game.k.left = true;
}
if (keyPressed == SDLK_DOWN)
{
game.k.down = true;
}
if (keyPressed == SDLK_UP)
{
game.k.up = true;
}
}
game.g.beginFrame();
game.render();
game.g.repaint();
}
return 0;
};
Game.cpp
#include "Game.h"
Game::Game()
: g(Graphics()),
x( 0 ),
y( 0 ),
m( Map() )
{
image = SDL_LoadBMP("grass.bmp");
}
Game::~Game()
{
}
void Game::keyLogic()
{
if (k.right)
{
x += 5;
}
if (k.left)
{
x -= 5;
}
if (k.down)
{
y += 5;
}
if (k.up)
{
y -= 5;
}
}
void Game::update()
{
if (count < 10)
{
count++;
}
if (count == 10)
{
keyLogic();
count = 0;
}
}
void Game::render()
{
update();
m.renderMap();
}
You have two instances of Graphics, one in Game and one in Map. You call Graphics::initScreen on the one in the Game instance game, but later you try to render in the Graphics instance of the Map instance game.m, where the SDL surface screen is uninitialized. Specifically game.render(); calls game.m.renderMap();, which calls game.m.g.drawImage(...).
Decide for one location of the Graphics instance or use references.