All my sprites are reversed when I try to draw my isometric map.
Here is the tileset.png mentionned in the following code :
Object.h/Object.cpp
I can use them to draw tiles, UI element, etc. ...
#pragma once
class Object {
public:
//FUNCTIONS
Object();
void addComponent(float value);
int getComponent(float index);
void editComponent(float index, float value);
void deleteComponent(float index);
private:
vector<int> components;
};
#include "Object.cpp"
-
#pragma once
//FUNCTIONS
Object::Object() {
//...
}
void Object::addComponent(float value) {
components.push_back(value);
}
int Object::getComponent(float index) {
return components[index];
}
void Object::editComponent(float index, float value) {
components[index] = value;
}
void Object::deleteComponent(float index) {
components.erase(components.begin() + index);
}
Note: I may have weird includes, I'm struggling with visual studio ha ha.
Scene.h/Scene.cpp
Handle data & graphics
#pragma once
class Scene {
public:
Scene(float w, float h, int mapx, int mapy, int tilesize, int mapwidth, int mapheight);
void run();
void addLayer();
void loadTileset(sf::String url);
void loadUiTileset(sf::String url);
//functions
//...
//getters
//...
//setters
//...
private:
sf::RenderWindow window;
float width;
float height;
int nb_layers;
int map_x;
int map_y;
int map_width;
int map_height;
int tile_size;
int selected_tile_index;
sf::RenderTexture texture;
sf::Sprite tile;
sf::Sprite map;
sf::Texture tileset;
vector<Object> tiles;
sf::Texture uiTileset;
//private functions
void updateMap();
//...
void processEvent();
void update(sf::Time deltaTime);
void render();
//...
};
#include "Scene.cpp"
-
#pragma once
//functions
Scene::Scene(float w, float h, int mapx, int mapy, int tilesize, int mapwidth, int mapheight) : window(sf::VideoMode(w, h), "Editor") {
width = w;
height = h;
map_x = mapx;
map_y = mapy;
map_width = mapwidth;
map_height = mapheight;
tile_size = tilesize;
selected_tile_index = 0;//default
nb_layers = 0;
}
void Scene::run() {
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
sf::Time TimePerFrame = sf::seconds(1.f / 60.f);
while (window.isOpen()) {
processEvent();
timeSinceLastUpdate += clock.restart();
while (timeSinceLastUpdate > TimePerFrame) {
timeSinceLastUpdate -= TimePerFrame;
processEvent();
update(TimePerFrame);
}
render();
}
}
void Scene::addLayer() {
nb_layers += 1;
int tile_x = map_x,
tile_y = map_y,
num_layer = nb_layers - 1,
layer_pos = (num_layer * tile_size) / 2,
tile_zOrder = -1;
tile_y -= layer_pos;
int x = map_x,
y = map_y;
for (int h = 0; h < map_height; h++) {
for (int w = 0; w < map_width; w++) {
tile_zOrder = (w * (h + 1)) + (num_layer * 10);
x = carthesianToIsometric(tile_x, tile_y)[0];
y = carthesianToIsometric(tile_x, tile_y)[1] - layer_pos;
cout << x << ", " << y << endl;
Object tile;
tile.addComponent(selected_tile_index);
tile.addComponent(x);
tile.addComponent(y);
tile.addComponent(tile_zOrder);
tile.addComponent(num_layer);
tiles.push_back(tile);
tile_x += tile_size;
}
tile_x = 0;
tile_y += tile_size;
}
updateMap();
}
void Scene::loadTileset(sf::String url) {
if (!tileset.loadFromFile(url))
{
cout << std::string(url) << "couldn't be loaded..." << endl;
}
}
void Scene::loadUiTileset(sf::String url) {
if (!uiTileset.loadFromFile(url))
{
cout << std::string(url) << "couldn't be loaded..." << endl;
}
}
//getters
//...
//setters
//...
//private functions
void Scene::updateMap() {
int tile_position_x = 0,
tile_position_y = 0;
int tile_x = 0,
tile_y = 0;
if (!texture.create(map_width * tile_size, (map_height * tile_size) / 2))
cout << "Texture couldn't be loaded... " << endl;
texture.clear(sf::Color(133, 118, 104, 255));
sf::Sprite image;
image.setTexture(tileset);
int tileset_width = image.getGlobalBounds().width,
tileset_height = image.getGlobalBounds().height;
tile.setTexture(tileset);
for (int tile_index = 0; tile_index < tiles.size(); tile_index++) {
tile_position_x = getTilePosition(tileset_width, tileset_height, tiles[tile_index].getComponent(0), tile_size)[0];
tile_position_y = getTilePosition(tileset_width, tileset_height, tiles[tile_index].getComponent(0), tile_size)[1];
tile.setTextureRect(sf::IntRect(tile_position_x, tile_position_y, tile_size, tile_size));
tile_x = tiles[tile_index].getComponent(1);
tile_y = tiles[tile_index].getComponent(2);
tile.setPosition(sf::Vector2f(tile_x, tile_y));
texture.draw(tile);
}
map.setTexture(texture.getTexture());
}
void Scene::processEvent() {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Escape)
window.close();
break;
}
}
}
void Scene::update(sf::Time deltaTime) {
//REMEMBER: distance = speed * time
//MOVEMENT, ANIMATIONS ETC. ..
}
void Scene::render() {
window.clear();
window.draw(map);
window.display();
}
main.cpp
#pragma once
//global functions + main headers + class headers =>
#include "globalfunctions.h"
int main() {
int map_width = 15,
map_height = 15,
tile_size = 64;
float scene_width = map_width * tile_size,
scene_height = (map_height * tile_size) / 2;
Scene engine(scene_width, scene_height, 0, 0, tile_size, map_width, map_height);
engine.loadTileset("tileset.png");
//engine.loadUiTileset("menu.png");
engine.addLayer();
//...
engine.run();
return EXIT_SUCCESS;
}
globalfunctions.h
Some utility functions.
getTilePosition(...) allow me to get x, y on a texture with a given tile index. Example : if I want to draw the tile n°0 of the tileset texture.
#pragma once
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
vector<float> getTilePosition(float tileset_width, float tileset_height, float tile_index, float tile_size) {//In a tileset
float tileX = 0,
tileY = 0,
tilePerLine = 0;
tilePerLine = tileset_width / tile_size;
tileY = floor(tile_index / tilePerLine);
tileX = ((tile_index + 1) - (tileY * tilePerLine)) - 1;
tileX *= tile_size;
tileY *= tile_size;
vector<float> coords;
coords.push_back(tileX);
coords.push_back(tileY);
return coords;
}
vector<int> carthesianToIsometric(int x, int y) {
vector<int> coords;
float isoX = (x - y) / 2,
isoY = (x + y) / 4;
coords.push_back(isoX);
coords.push_back(isoY);
return coords;
}
#include "Object.h"
#include "Scene.h"
//...
And here, the WTF result I get :
Thanks for reading all that weird code !
Edit :
When I change
tile.setPosition(sf::Vector2f(tile_x, tile_y));
to
tile.setPosition(sf::Vector2f(0, 0));
in updateMap() from scene.cpp :
Unfortunatly, I cannot explain why. Maybe it will help you to understand the problem.
In case someone encounter the same problem :
As #Spectre suggested it was a problem of the sfml function draw().
http://en.sfml-dev.org/forums/index.php?topic=6903.0
You need to use display on the sf::renderTexture after your cleared it.
Related
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.
I am creating a classic breakout game in C++ using SFML library. So far I have a movable paddle and ball implemented.
Currently, my goal is to create a layout of bricks. So far I have it so that a single brick is displayed. However, I want to make it so that I can draw a layout of bricks in text file using a letter (For example using letter 'B'), read that text file's brick layout and draw that layout in game.
I am not sure how to do this so any help would be great!
Here is my code so far (Note that I did not include for Paddle and Ball as I thought it was not needed for this problem):
GameObject.h
#pragma once
#include <SFML/Graphics.hpp>
class GameObject
{
protected:
sf::Vector2f position;
float speed;
sf::RenderWindow& m_window;
public:
GameObject(float startX, float startY, sf::RenderWindow& window);
virtual ~GameObject() {};
virtual void Draw() = 0;
virtual void Update() = 0;
};
GameObject.cpp
#include "GameObject.h"
GameObject::GameObject(float startX, float startY, sf::RenderWindow& window)
: position{ startX, startY }
, speed{ 0.5f }
, m_window{ window }
{
}
Brick.h
#pragma once
#include "GameObject.h"
class Brick : public GameObject
{
private:
sf::RectangleShape brickShape;
static constexpr int shapeWidth = 50;
static constexpr int shapeHeight = 20;
int color;
int strength;
public:
Brick(float startX, float startY, sf::RenderWindow& window);
sf::FloatRect getPosition();
sf::RectangleShape getShape();
int getStrength();
void setStrength(int strengthValue);
void Draw() override;
void Update() override;
};
Brick.cpp
#include "Brick.h"
Brick::Brick(float startX, float startY, sf::RenderWindow& window)
: GameObject{ startX, startY, window }
{
brickShape.setSize(sf::Vector2f(shapeWidth, shapeHeight));
brickShape.setPosition(position);
color = (rand() % 2) + 1;
if (color == 1)
{
brickShape.setFillColor(sf::Color::Yellow);
strength = 1;
}
else
{
brickShape.setFillColor(sf::Color(255, 165, 0));
strength = 2;
}
}
sf::FloatRect Brick::getPosition()
{
return brickShape.getGlobalBounds();
}
sf::RectangleShape Brick::getShape()
{
return brickShape;
}
int Brick::getStrength()
{
return strength;
}
void Brick::setStrength(int strengthValue)
{
strength = strengthValue;
}
void Brick::Draw()
{
m_window.draw(brickShape);
}
void Brick::Update()
{
}
Game.h
#pragma once
#include <SFML/Graphics.hpp>
#include "Paddle.h"
#include "Ball.h"
#include "Brick.h"
#include <algorithm>
#include <fstream>
#include <iostream>
class Game
{
private:
sf::RenderWindow& m_window;
std::unique_ptr<Paddle> player;
std::unique_ptr<Ball> ball;
std::unique_ptr<Brick> brick;
std::vector<std::unique_ptr<Brick>>bricks;
int bricksCountX;
int bricksCountY;
public:
const unsigned int m_windowWidth;
const unsigned int m_windowHeight;
public:
Game(sf::RenderWindow& window, const unsigned int& windowWidth, const unsigned int& windowHeight);
float RandomFloat(float a, float b);
void ReadFile();
void HandleCollision();
void HandleInput();
void Draw();
void Update();
void Run();
};
Game.cpp
#include "Game.h"
Game::Game(sf::RenderWindow& window, const unsigned int& windowWidth, const unsigned int& windowHeight)
: m_window{ window }
, m_windowWidth{ windowWidth }
, m_windowHeight{ windowHeight }
{
player = std::make_unique<Paddle>(m_windowWidth/2, m_windowHeight - 70, m_window);
ball = std::make_unique<Ball>(m_windowWidth / 2, m_windowHeight / 2, m_window);
ReadFile();
for (int i = 0; i < bricksCountX; i++)
for (int j = 0; j < bricksCountY; j++)
bricks.emplace_back(std::make_unique<Brick>((i + 1.5) * ((long long)brick->getShape().getSize().x + 3) + 22,
(j + 5) * (brick->getShape().getSize().y + 3), m_window));
}
float Game::RandomFloat(float a, float b)
{
return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
void Game::ReadFile()
{
// Create a text string, which is used to output the text file
std::string bricksText;
int numOfLines = 0;
// Read from the text file
std::ifstream MyReadFile("Bricks Layout.txt");
// Use a while loop together with the getline() function to read the file line by line
while (std::getline(MyReadFile, bricksText))
{
++numOfLines;
// Output the text from the file
bricksCountX = bricksText.length();
std::cout << bricksCountX;
}
bricksCountY = numOfLines;
// Close the file
MyReadFile.close();
}
void Game::HandleCollision()
{
if (ball->getShape().getPosition().x - ball->getRadius() < 0.0f)
{
ball->reboundLeft();
}
else if (ball->getShape().getPosition().x + ball->getRadius() > m_windowWidth)
{
ball->reboundRight();
}
else if (ball->getShape().getPosition().y - ball->getRadius() < 0.0f)
{
ball->reboundTop();
}
else if (ball->getShape().getPosition().y + ball->getRadius() > m_windowHeight)
{
ball->ballAngle = ball->ballAngle * -1;
}
else if (ball->getPosition().intersects(player->getPosition()))
{
ball->reboundPaddle(*player);
}
for (unsigned int i = 0; i < bricks.size(); i++)
{
if (ball->getPosition().intersects(bricks[i]->getPosition()))
{
if (bricks[i]->getStrength() == 1)
{
ball->reboundBrick(*bricks[i]);
bricks.erase(std::remove(bricks.begin(), bricks.end(), bricks[i]), bricks.end());
}
else
{
ball->reboundBrick(*bricks[i]);
bricks[i]->setStrength(1);
}
}
}
}
void Game::HandleInput()
{
player->HandleInput();
}
void Game::Draw()
{
player->Draw();
ball->Draw();
for (unsigned int i = 0; i < bricks.size(); i++)
{
bricks[i]->Draw();
}
}
void Game::Update()
{
player->Update();
ball->Update();
brick->Update();
}
void Game::Run()
{
//Game Loop
while (m_window.isOpen())
{
sf::Event event;
while (m_window.pollEvent(event))
{
if (event.type == sf::Event::Closed || sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
m_window.close();
}
m_window.clear();
Draw();
HandleInput();
HandleCollision();
Update();
m_window.display();
}
}
I am following along Let's Make An RPG (C++/SDL2) - Tutorials on Youtube and am stuck on Let's Make an RPG (C++/SDL2) - Part 35 Continuation on Collision (https://www.youtube.com/watch?v=DLu6g2S3Ta0&list=PLHM_A02NtaaVey-4Ezh7p6bbOsv-DKA-0).
I am trying to place a transparent rectangle over all sprites to debug collision detection. I am not getting any errors so there is no one piece of code I can show you.
Can someone please shed some light on where I went wrong. I'm very new to C++ but I'm not giving up. Thank you for your time. I'm genuinely grateful.
This is the code for both the header and cpp file of the Collision Rectangle
#include "CollisionRectangle.h"
CollisionRectangle::CollisionRectangle()
{
OffsetX = 0;
OffsetY = 0;
SetRectangle(0,0,0,0);
}
CollisionRectangle::CollisionRectangle(int x, int y, int w, int h)
{
OffsetX = x;
OffsetY = y;
SetRectangle(0,0,w,h);
}
CollisionRectangle::~CollisionRectangle()
{
//dtor
}
void CollisionRectangle::SetRectangle(int x, int y, int w, int h)
{
CollisionRect.x = x + OffsetY;
CollisionRect.y = y + OffsetY;
CollisionRect.w = w;
CollisionRect.h = h;
}
//header
#pragma once
#include "stdafx.h"
class CollisionRectangle
{
public:
CollisionRectangle();
CollisionRectangle(int x, int y, int w, int h);
~CollisionRectangle(void);
void SetRectangle(int x, int y, int w, int h);
SDL_Rect GetRectangle(){ return CollisionRect; }
void setX(int x){ CollisionRect.x = x + OffsetX; }
void setY(int y){ CollisionRect.y = y + OffsetY; }
private:
int OffsetX;
int OffsetY;
SDL_Rect CollisionRect;
};
This is the code for the both the header and the cpp file of Sprites
#include "Sprite.h"
Sprite::Sprite(SDL_Renderer* passed_renderer, std::string FilePath, int x, int y, int w, int h, float *passed_CameraX, float *passed_CameraY, CollisionRectangle passed_CollisionRect)
{
CollisionRect = passed_CollisionRect;
renderer = passed_renderer;
CollisionSDL_Rect = CollisionRect.GetRectangle();
image = NULL;
image = IMG_LoadTexture(renderer, FilePath.c_str());
if (image == NULL)
{
std::cout << "Couldn't load " << FilePath.c_str() << std::endl;
}
CollisionImage = NULL;
CollisionImage = IMG_LoadTexture(renderer, "Data/DebugImages/DebugBox.png");
if (CollisionImage == NULL)
{
std::cout << "Couldn't load " << "CollisionImage" << std::endl;
}
rect.x = x;
rect.y = y;
rect.w = w;
rect.h = h;
SDL_QueryTexture(image,NULL,NULL, &img_width, &img_height);
crop.x = 0;
crop.y = 0;
crop.w = img_width;
crop.h = img_height;
X_pos = x;
Y_pos = y;
Origin_X = 0;
Origin_Y = 0;
CurrentFrame = 0;
Amount_Frame_X = 0;
Amount_Frame_Y = 0;
CameraX = passed_CameraX;
CameraY = passed_CameraY;
Camera.x = rect.x + *CameraX;
Camera.y = rect.y + *CameraY;
Camera.w = rect.w;
Camera.h = rect.h;
}
void Sprite::DrawSteady()
{
SDL_RenderCopy(renderer,image, &crop, &rect);
}
void Sprite::Draw()
{
Camera.x = rect.x + *CameraX;
Camera.y = rect.y + *CameraY;
CollisionRect.setX(rect.x + *CameraX);
CollisionRect.setY(rect.y + *CameraY);
SDL_RenderCopy(renderer,image, &crop, &Camera);
SDL_RenderCopy(renderer,CollisionImage, NULL, &CollisionSDL_Rect);
}
void Sprite::SetUpAnimation(int passed_Amount_X, int passed_Amount_Y)
{
Amount_Frame_X = passed_Amount_X;
Amount_Frame_Y = passed_Amount_Y;
}
void Sprite::PlayAnimation(int BeginFrame, int EndFrame, int Row, float Speed)
{
if (animationDelay+Speed < SDL_GetTicks())
{
if (EndFrame <= CurrentFrame)
CurrentFrame = BeginFrame;
else
CurrentFrame++;
crop.x = CurrentFrame * (img_width/Amount_Frame_X);
crop.y = Row * (img_height/Amount_Frame_Y);
crop.w = img_width/Amount_Frame_X;
crop.h = img_height/Amount_Frame_Y;
animationDelay = SDL_GetTicks();
}
}
Sprite::~Sprite()
{
SDL_DestroyTexture(image);
}
void Sprite::SetX(float X)
{
X_pos = X;
rect.x = int(X_pos - Origin_X);
}
void Sprite::SetY(float Y)
{
Y_pos = Y;
rect.y = int(Y_pos - Origin_Y);
}
void Sprite::SetPosition(float X, float Y)
{
X_pos = X;
Y_pos = Y;
rect.x = int(X_pos - Origin_X);
rect.y = int(Y_pos - Origin_Y);
}
float Sprite::getX()
{
return X_pos;
}
float Sprite::getY()
{
return Y_pos;
}
void Sprite::SetOrigin(float X, float Y)
{
Origin_X = X;
Origin_Y = Y;
SetPosition(getX(),getY());
}
void Sprite::SetWidth(int W)
{
rect.w = W;
}
void Sprite::SetHeight(int H)
{
rect.h = H;
}
int Sprite::GetWidth()
{
return rect.w;
}
int Sprite::GetHeight()
{
return rect.h;
}
//header
#pragma once
#include "stdafx.h"
#include "SDL_Setup.h"
#include "CollisionRectangle.h"
class Sprite
{
public:
Sprite(SDL_Renderer* passed_renderer, std::string FilePath, int x, int y, int w, int h, float *CameraX, float *CameraY, CollisionRectangle passed_CollisionRect);
~Sprite();
void Draw();
void DrawSteady();
void SetX(float X);
void SetY(float Y);
void SetPosition(float X, float Y);
float getX();
float getY();
void SetOrigin(float X, float Y);
int GetWidth();
int GetHeight();
void SetHeight(int H);
void SetWidth(int W);
void PlayAnimation(int BeginFrame, int EndFrame, int Row, float Speed);
void SetUpAnimation(int passed_Amount_X, int passed_Amount_Y);
private:
CollisionRectangle CollisionRect;
SDL_Rect Camera;
SDL_Rect CollisionSDL_Rect;
float *CameraX;
float *CameraY;
float Origin_X;
float Origin_Y;
float X_pos;
float Y_pos;
SDL_Texture* image;
SDL_Texture* CollisionImage;
SDL_Rect rect;
SDL_Rect crop;
SDL_Renderer* renderer;
int img_width;
int img_height;
int CurrentFrame;
int animationDelay;
int Amount_Frame_X;
int Amount_Frame_Y;
};
this is my first post on SO, please forgive me if I don't do it right.
I am trying to draw some a simple hexagon grid using C++ SFML. The hex grid is created in it'sown class and called in main.
Hex class Header
class Terrain : public sf::Drawable, public sf::Transformable
{
public:
explicit Terrain(sf::Texture texture, int x, int y);
sf::Texture texture;
sf::CircleShape hexMethod(float x, float y, float Radius);
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
void cameraAngle();
void setTexture(sf::Texture);
void setX(int xint);
void setY(int yint);
void update(sf::Time deltaTime);
sf::Time T_currentTime;
private:
sf::Texture m_terrain;
int xcoord, ycoord;
sf::Vertex m_verticeList[6];
bool isOdd(int integer)
{
if (integer % 2 == 0)
return true;
else
return false;
}
//virtual ~Terrain()
//{
//}
};
Hex class cpp
Terrain::Terrain(sf::Texture texture, int x, int y) :
m_terrain(texture), xcoord(x), ycoord(y)
{
}
void Terrain::setTexture(sf::Texture newText)
{
m_terrain = newText;
}
void Terrain::setX(int xint)
{
xcoord = xint;
}
void Terrain::setY(int yint)
{
ycoord = yint;
}
sf::CircleShape Terrain::hexMethod(float x, float y, float Radius){
float Width = Radius * 2, Height = Width *sqrt(3) / 2;
sf::CircleShape shape(Radius, 6);
float origo = 200;
float yrsize;
float normalDistanceX = origo + Width * 3 / 4 * x;
float normalSeparationY = origo + Height*y;
float isEven = Height / 2;
shape.setTexture(&texture, false);
shape.setOutlineThickness(2);
shape.setOrigin(Radius, Radius);
shape.setRotation(30);
if (Terrain::isOdd(x))
yrsize = normalSeparationY;
else
yrsize = normalSeparationY + isEven;
shape.setPosition(normalDistanceX, yrsize);
m_verticeList[0] = shape.getPoint(0);
m_verticeList[1] = shape.getPoint(1);
m_verticeList[2] = shape.getPoint(2);
m_verticeList[3] = shape.getPoint(3);
m_verticeList[4] = shape.getPoint(4);
m_verticeList[5] = shape.getPoint(5);
return shape;
}
void Terrain::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
for (size_t i = 0; i < 3; i++)
{
for (size_t j = 0; j < 3; j++)
{
states.transform *= getTransform();
states.texture = &m_terrain;
target.draw(m_verticeList, 4, sf::Points, states);
}
}
}
How I call it in main:
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 800), "Puppet Masters!");
if (!tTexture.loadFromFile("Green.jpg"))
return EXIT_FAILURE;
Terrain newterrain(tTexture, 3,3);
newterrain.hexMethod(3, 3, 70);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::P)
{
}
window.clear();
window.draw(newterrain);
window.display();
}
return 0;
}
I get no errors when running the code, however I also get no result, just a blank black screen. My intention is to have the hexes drawn from calling the class and defining it's variables. The Hexfunction I used in main at first to get a hex grid working, I don't think know how to translate that into a class properly.
Hi I made a level generator with a 3D Buzz tutorial called Evil Monkeys.
I generated a level but I can't get it to draw on the screen.
My code:
Level.cpp
#include "Level.h"
#include <stdlib.h>
#include "Sprite.h"
Level::Level(drawEngine *de, int w, int h)
{
drawArea = de;
width = w;
height = h;
gamer = 0;
//create memory for our level
level = new char *[width];
for(int x = 0; x < width; x++)
{
level[x] = new char[height];
}
//create the level
createLevel();
drawArea->setMap(level);
}
Level::~Level()
{
for(x = 0; x < width; x++)
delete []level[x];
delete [] level;
}
void Level::createLevel(void)
{
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
int random = rand() % 100;
if (y == 0 || y == height - 1 || x == 0 || x == width - 1)
{
level[x][y] = TILE_WALL;
}
else
{
if (random < 90 || (x < 3 && y < 3))
level[x][y] = TILE_EMPTY;
else
level[x][y] = TILE_WALL;
}
}
}
}
void Level::draw(void)
{
// level to be drawn here
drawArea->drawBackground();
}
Level.h
#ifndef LEVEL_H
#define LEVEL_H
enum
{
TILE_EMPTY,
TILE_WALL
};
#include "drawEngine.h"
class Character;
class Level
{
public:
Level(drawEngine *de, int width = 30, int height = 20);
~Level();
int x;
int y;
void addPlayer(Character *p);
void update(void);
void draw(void);
bool keyPress(char c);
protected:
void createLevel(void);
private:
int width;
int height;
char **level;
Character *gamer;
drawEngine *drawArea;
};
#endif
Game.cpp
#include "Game.h"
#include <conio.h>
#include <iostream>
#include "drawEngine.h"
#include "Character.h"
#include <windows.h>
using namespace std;
//this will give ME 32 fps
#define GAME_SPEED 25.33
bool Runner::run()
{
level = new Level(&drawArea, 30, 20);
drawArea.createBackgroundTile(TILE_EMPTY, ' ');
drawArea.createBackgroundTile(TILE_WALL, '+');
drawArea.createSprite(0, '$');
gamer = new Character(&drawArea, 0);
level->draw();
char key = ' ';
startTime = timeGetTime();
frameCount = 0;
lastTime = 0;
posX = 0;
while (key != 'q')
{
while(!getInput(&key))
{
timerUpdate();
}
//gamer->keyPress(key);
//cout << "Here's what you pressed: " << key << endl;
}
delete gamer;
cout << frameCount / ((timeGetTime() - startTime) / 100) << " fps " << endl;
cout << "Game Over" << endl;
return true;
}
bool Runner::getInput(char *c)
{
if (kbhit())
{
*c = getch();
return true;
}
}
void Runner::timerUpdate()
{
double currentTime = timeGetTime() - lastTime;
if (currentTime < GAME_SPEED)
return;
frameCount++;
lastTime = timeGetTime();
}
game.h
#ifndef GAME_H
#define GAME_H
#include "drawEngine.h"
#include "Sprite.h"
#include "Character.h"
#include "level.h"
class Runner
{
public:
bool run();
Runner(){};
protected:
bool getInput(char *c);
void timerUpdate();
private:
Level *level;
Character* gamer;
double frameCount;
double startTime;
double lastTime;
int posX;
drawEngine drawArea;
};
#endif
drawEngine.cpp
#include <iostream>
#include "drawEngine.h"
#include <windows.h>
using namespace std;
drawEngine::drawEngine(int index, int xSize, int ySize, int x, int y)
{
screenWidth = x;
screenHeight = y;
map = 0;
//set cursor visibility to false
//cursorVisibility(false);
}
drawEngine::~drawEngine()
{
cursorVisibility(true);
//set cursor visibility to true
}
int drawEngine::createSprite(int index, char c)
{
if (index >= 0 && index < 16)
{
spriteImage[index] = c;
return index;
}
return -1;
}
void drawEngine::deleteSprite(int index)
{
// in this implemantation we don't need it
}
void drawEngine::drawSprite(int index, int posX, int posY)
{
//go to the correct location
gotoxy (index, posX, posY);
// draw the sprite
cout << spriteImage[index];
cursorVisibility(false);
}
void drawEngine::eraseSprite(int index, int posX, int posY)
{
gotoxy (index, posX, posY);
cout << ' ';
}
void drawEngine::setMap(char **data)
{
map = data;
}
void drawEngine::createBackgroundTile(int index, char c)
{
if (index >= 0 && index < 16)
{
tileImage[index] = c;
}
}
void drawEngine::drawBackground(void)
{
if(map)
{
for(int y = 0; y < screenHeight; y++)
{
gotoxy(0,y, 0);
for(int x = 0; x < screenWidth; x++)
cout << tileImage[map[x][y]];
}
}
}
void drawEngine::gotoxy(int index, int x, int y)
{
HANDLE output_handle;
COORD pos;
pos.X = x;
pos.Y = y;
output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(output_handle, pos);
}
void drawEngine::cursorVisibility(bool visibility)
{
HANDLE output_handle;
CONSOLE_CURSOR_INFO cciInfo;
cciInfo.dwSize = 1;
cciInfo.bVisible = visibility;
output_handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(output_handle, &cciInfo);
}
drawEngine.h
#ifndef DRAWENGINE_H
#define DRAWENGINE_H
class drawEngine
{
public:
drawEngine(int index, int xSize = 30, int ySize = 20, int x = 0, int y = 0);
~drawEngine();
drawEngine(){};
int createSprite(int index, char c);
void deleteSprite(int index);
void eraseSprite(int index, int posX, int posY);
void createBackgroundTile(int index, char c);
void drawSprite(int index, int posX, int posY);
void drawBackground(void);
void setMap(char **);
protected:
char **map;
int screenWidth, screenHeight;
char spriteImage[16];
char tileImage[16];
private:
void gotoxy(int index, int x, int y);
void cursorVisibility(bool visibility);
};
#endif
I've also got Sprite.cpp, Sprite.h, Character.h,Character.cpp and main.cpp if you need them
Ok, I made it through the code and found one issue. The Runner class encapsulates a drawEngine object. At the constructor of Runner, the default c'tor of drawEngine is called, which doesn't set values for sceenWidth and screenHeight (or any other member). Luckily in debug mode, they are defaulted to 0xcccccccc which is negative so you're drawBackground returns immediately (Visual Studio 2010).
You should change that c'tor (or even remove it) and corretly initialize the engine in runner's constructor, e.g.:
class Runner {
public:
Runner() : drawArea(0, width, height, ?, ?){};
[...]
};
Further, the x and y members are used in the loops in drawBackground. You should use screenWidth and screenWidth, resp. BTW, I don't know what x and y should be in drawEngine
UPDATE: The x and y coordinates at the gotoxy call in drawBackground are mixed up, so you draw everything on the same line. BTW: what is index used for?