-
-
Save anonymous/2af3c35d568324fb0a6ce8039ef42a64 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Camera.h" | |
Camera::Camera() | |
{ | |
// Set size of camera | |
camera.reset(sf::FloatRect(0.0f, 0.0f, (float)_screenDimensions.x, (float)_screenDimensions.y)); | |
// Set aspect ratio | |
camera.setViewport(sf::FloatRect(0.0f, 0.0f, 1.0f, 1.0f)); | |
// Set position | |
cameraPosition = sf::Vector2f(_screenDimensions.x / 2.0f, _screenDimensions.y / 2.0f); | |
} | |
sf::View &Camera::getView() | |
{ | |
return camera; | |
} | |
void Camera::update(Player &player) | |
{ | |
// Check if player position is half way across the screen | |
if (player.getPosition().x + 10.0f > _screenDimensions.x / 2.0f) | |
cameraPosition.x = player.getPosition().x + 10.0f; | |
else | |
cameraPosition.x = _screenDimensions.x / 2.0f; | |
// Check if player position is half way down the screen | |
if (player.getPosition().y - 10.0f > _screenDimensions.y / 2.0f) | |
cameraPosition.y = player.getPosition().y - 10.0f; | |
else | |
cameraPosition.y = _screenDimensions.y / 2.0f; | |
// Move the center | |
camera.setCenter(cameraPosition); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <SFML/Graphics.hpp> | |
#include "Globals.h" | |
#include "Player.h" | |
class Camera | |
{ | |
private: | |
sf::View camera; | |
sf::Vector2f cameraPosition; | |
public: | |
Camera(); | |
// Getters & Setters | |
sf::View &getView(); | |
// Game loop methods | |
void update(Player &player); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Game.h" | |
// Split constructor (let it call initialize and load) | |
Game::Game(unsigned int width, unsigned int height, std::string windowTitle) | |
{ | |
// Set the width, height, & title | |
_screenDimensions.x = width; | |
_screenDimensions.y = height; | |
this->windowTitle = windowTitle; | |
// Create the window | |
window.create(sf::VideoMode(_screenDimensions.x, _screenDimensions.y), windowTitle); | |
window.setMouseCursorVisible(true); | |
// Frame stuff | |
window.setFramerateLimit(60); | |
window.setVerticalSyncEnabled(false); | |
// Fixed time-step | |
timePerTick = sf::seconds(1.0f / 60.0f); // Ticks per second | |
timeSinceLastUpdate = sf::Time::Zero; // Time since last tick | |
frameTime = sf::Time::Zero; // Change in time | |
alpha = 0.0f; // Time between frames | |
this->loadContent(); // Load content | |
} | |
void Game::loadContent() | |
{ | |
// Get fonts | |
robotoFont.loadFromFile("Resources/Fonts/Roboto.ttf"); | |
// Set FPS text | |
fps.setFont(robotoFont); | |
fps.setCharacterSize(16); | |
fps.setPosition(10.0f, 10.0f); | |
// Set position text | |
posX.setFont(robotoFont); | |
posX.setCharacterSize(16); | |
posX.setPosition(10.0f, 30.0f); | |
posY.setFont(robotoFont); | |
posY.setCharacterSize(16); | |
posY.setPosition(10.0f, 50.0f); | |
// Camera settings | |
camera = Camera(); | |
// Load the player spritesheet (use initialization list in Game : if want to use constructor) | |
player.initialize("Resources/Sprites/Skeleton.png", 4, 9, sf::Vector2f(100.0f, 100.0f), 300.0f); | |
// Tilemaps | |
tileMap.load("Resources/Maps/LevelTest.xml"); | |
} | |
/*\ //******************************************* | |
|*| | |
|*| GAME LOOP | |
|*| - run() Handles events | |
|*| - update() Handles game updates | |
|*| - draw() Renders everything | |
|*| | |
\*/ //******************************************* | |
void Game::run() | |
{ | |
while (window.isOpen()) | |
{ | |
// Create event | |
sf::Event event; | |
// Handle events | |
while (window.pollEvent(event)) | |
{ | |
if (event.type == sf::Event::Closed) | |
window.close(); | |
if (event.type == sf::Event::KeyPressed) | |
{ | |
// Close game on Escape | |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) | |
window.close(); | |
// Reload tile | |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::L)) | |
tileMap.load("Resources/Maps/LevelTest.xml"); | |
} | |
} | |
// Updates | |
update(); | |
// Render | |
draw(); | |
} | |
} | |
void Game::update() | |
{ | |
// Get the time since this method was last called | |
frameTime = clock.restart(); | |
timeSinceLastUpdate += frameTime; | |
// Update per tick (around 120 ticks per second) | |
while (timeSinceLastUpdate > timePerTick) | |
{ | |
timeSinceLastUpdate -= timePerTick; | |
// Update FPS | |
fps.setString("FPS: " + std::to_string((int)(1.0f / frameTime.asSeconds()))); | |
// Update player | |
player.update(timePerTick.asSeconds()); | |
// Update the camera | |
camera.update(player); | |
posX.setString("X: " + std::to_string((int)player.getPosition().x)); | |
posY.setString("Y: " + std::to_string((int)player.getPosition().y)); | |
} | |
// Anything that needs to be updated every frame goes here. Otherwise put updates inside above loop! | |
} | |
void Game::draw() | |
{ | |
// Extra time between each tick | |
alpha = timeSinceLastUpdate / timePerTick; | |
// Clear everything | |
window.clear(); | |
// Follow camera | |
window.setView(camera.getView()); | |
window.draw(tileMap); | |
player.draw(window, alpha); | |
// Don't follow camera | |
window.setView(window.getDefaultView()); | |
window.draw(fps); | |
window.draw(posX); | |
window.draw(posY); | |
// Show everything | |
window.display(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <SFML/Graphics.hpp> | |
#include <pugixml.hpp> | |
#include "Globals.h" | |
#include "Camera.h" | |
#include "TileMap.h" | |
#include "Player.h" | |
#include "WorldObject.h" | |
class Game | |
{ | |
private: | |
// Game window | |
sf::RenderWindow window; | |
std::string windowTitle; | |
// Fixed time-step | |
sf::Clock clock; | |
sf::Time timePerTick; | |
sf::Time timeSinceLastUpdate; | |
sf::Time frameTime; | |
float alpha; | |
// Camera fields | |
Camera camera; | |
// TileMaps | |
TileMap tileMap; | |
// FPS display | |
sf::Font robotoFont; | |
sf::Text fps, posX, posY; | |
// TODO: Make an Entity class | |
Player player; | |
// Private methods | |
void loadContent(); | |
void update(); | |
void draw(); | |
public: | |
Game(unsigned int width, unsigned int height, std::string windowTitle); | |
// Game loop | |
void run(); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Player.h" | |
Player::Player() { } | |
Player::Player(std::string filename, int rows, int columns, sf::Vector2f position, float moveSpeed) | |
{ | |
this->initialize(filename, rows, columns, position, moveSpeed); | |
} | |
void Player::initialize(std::string filename, int rows, int columns, sf::Vector2f position, float moveSpeed) | |
{ | |
// Load the texture | |
if (!texture.loadFromFile(filename)) | |
std::cout << "Could not load " << filename << std::endl; | |
// Attach to player sprite | |
sprite.setTexture(texture); | |
// Sheet dimensions | |
sheetWidth = texture.getSize().x; | |
sheetHeight = texture.getSize().y; | |
// Set the position | |
crntPosition = sf::Vector2f(position.x, position.y); | |
// Get the sprite width and height | |
spriteWidth = sheetWidth / columns; | |
spriteHeight = sheetHeight / rows; | |
// Set the source frame | |
source.x = 0; | |
source.y = Right; | |
// Sprite frame | |
frameCounter = 0.0f; | |
frameSwitch = 100.0f; | |
frameSpeed = 1000.0f; | |
this->moveSpeed = moveSpeed; | |
} | |
sf::Vector2f &Player::getPosition() | |
{ | |
return crntPosition; | |
} | |
/* =========================================================== | |
* HELPER METHODS | |
* ======================================================== */ | |
void Player::moveFrame(float &timePerTick) | |
{ | |
if (source.y != previousRow) | |
source.x = 0; | |
frameCounter += frameSpeed * timePerTick; | |
if (frameCounter >= frameSwitch) | |
{ | |
source.x++; | |
if (source.x * spriteWidth >= sheetWidth) | |
source.x = 0; | |
frameCounter = 0; | |
} | |
} | |
void Player::resetFrame() | |
{ | |
//bool upKey = sf::Keyboard::isKeyPressed(sf::Keyboard::Up); | |
//bool downKey = sf::Keyboard::isKeyPressed(sf::Keyboard::Down); | |
//bool leftKey = sf::Keyboard::isKeyPressed(sf::Keyboard::Left); | |
//bool rightKey = sf::Keyboard::isKeyPressed(sf::Keyboard::Right); | |
// If no movement keys are pressed | |
if (!sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && !sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && | |
!sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && !sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) | |
{ | |
source.x = 0; | |
} | |
} | |
/* =========================================================== | |
* GAME LOOP | |
* ======================================================== */ | |
void Player::update(float timePerTick) | |
{ | |
// Get the previous position/direction | |
prevPosition = crntPosition; | |
previousRow = source.y; | |
// Try to reset frame if possible | |
resetFrame(); | |
// Check which key is pressed | |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) | |
{ | |
source.y = Up; | |
moveFrame(timePerTick); | |
crntPosition.y -= moveSpeed * timePerTick; | |
} | |
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) | |
{ | |
source.y = Down; | |
moveFrame(timePerTick); | |
crntPosition.y += moveSpeed * timePerTick; | |
} | |
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) | |
{ | |
source.y = Left; | |
moveFrame(timePerTick); | |
crntPosition.x -= moveSpeed * timePerTick; | |
} | |
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) | |
{ | |
source.y = Right; | |
moveFrame(timePerTick); | |
crntPosition.x += moveSpeed * timePerTick; | |
} | |
// TODO: Normalize speed when going diagonal | |
} | |
void Player::draw(sf::RenderWindow &window, float &alpha) | |
{ | |
// Interpolate movement | |
sprite.setPosition(crntPosition * alpha + prevPosition * (1.0f - alpha)); | |
// Create rectangle in sheet around a sprite | |
sprite.setTextureRect(sf::IntRect(source.x * spriteWidth, source.y * spriteHeight, spriteWidth, spriteHeight)); | |
// Draw the sprite | |
window.draw(sprite); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <iostream> | |
#include <SFML/Graphics.hpp> | |
class Player | |
{ | |
private: | |
sf::Texture texture; | |
sf::Sprite sprite; | |
sf::Vector2i source; | |
sf::Vector2f prevPosition, crntPosition; | |
unsigned int rows, columns; | |
unsigned int spriteWidth, spriteHeight; | |
unsigned int sheetWidth, sheetHeight; | |
float moveSpeed, frameCounter, frameSwitch, frameSpeed; | |
unsigned int previousRow; | |
// Corresponds to the row in the sprite sheet | |
enum Direction { Up, Left, Down, Right }; | |
// Private methods | |
void moveFrame(float &timePerTick); | |
void resetFrame(); | |
public: | |
Player(); | |
Player(std::string filename, int rows, int columns, sf::Vector2f position, float moveSpeed = 200.0f); | |
void initialize(std::string filename, int rows, int columns, sf::Vector2f position, float moveSpeed = 200.0f); | |
// Getters & Setters | |
sf::Vector2f &getPosition(); | |
// Game loop methods | |
void update(float timePerTick); | |
void draw(sf::RenderWindow &window, float &alpha); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "TileMap.h" | |
TileMap::TileMap() {} | |
bool TileMap::load(const char* xmlDocument) | |
{ | |
// Read Level from XML | |
if (!readXML(xmlDocument)) | |
return false; | |
// Load the tileset texture | |
if (!tileSheet.loadFromFile(filepath)) | |
return false; | |
// Get size of a tile | |
tileWidth = tileSheet.getSize().x / sheetColumns; | |
tileHeight = tileSheet.getSize().y / sheetRows; | |
// Intitalize the vertex arrays | |
for (unsigned int i = 0; i < layers; i++) | |
{ | |
sf::VertexArray vertexLayer; | |
// Resize the vertex array to fit the level size | |
vertexLayer.setPrimitiveType(sf::Quads); | |
vertexLayer.resize(worldWidth * worldHeight * 4); | |
// Add to whole vertex array vector | |
vertexArray.push_back(vertexLayer); | |
// Set the points and textures | |
setCoords(map[i], vertexArray[i]); | |
} | |
// Tilemap loaded successfully | |
return true; | |
} | |
// Set the VertexArray corners and texture coordinates | |
void TileMap::setCoords(std::vector<int> &mapLayer, sf::VertexArray &vertexLayer) | |
{ | |
// Populate the vertex array, with one quad per tile | |
for (unsigned int i = 0; i < worldWidth; i++) | |
{ | |
for (unsigned int j = 0; j < worldHeight; j++) | |
{ | |
// Get the current tile number (Does 1 column at a time) | |
int tileNumber = mapLayer[i + j * worldWidth]; | |
// Find its position in the tileset texture | |
int tileRow = tileNumber / (tileSheet.getSize().x / tileWidth); | |
int tileCol = tileNumber % (tileSheet.getSize().x / tileWidth); | |
// Get a pointer to the current tile's quad | |
sf::Vertex* quad = &vertexLayer[(i + j * worldWidth) * 4]; | |
/*\ | |
|*| Define its 4 corners | |
|*| | |
|*| 0 ----- 1 This takes care of where and how the quad will | |
|*| | | appear in the world. Adding or subtracting in the | |
|*| | | X or Y will change the size/shape. | |
|*| 3 ----- 2 | |
\*/ | |
quad[0].position = sf::Vector2f((float)(i * tileWidth), (float)(j * tileHeight)); | |
quad[1].position = sf::Vector2f((float)((i + 1) * tileWidth), (float)(j * tileHeight)); | |
quad[2].position = sf::Vector2f((float)((i + 1) * tileWidth), (float)((j + 1) * tileHeight)); | |
quad[3].position = sf::Vector2f((float)(i * tileWidth), (float)((j + 1) * tileHeight)); | |
/*\ | |
|*| Define its 4 texture coordinates | |
|*| | |
|*| 0 ------- 1 Offsets => Top(T), Right(R), Bottom(B), Left(L) | |
|*| | T | | |
|*| | L R | Offsets will be subtracted from the texture. | |
|*| | B | They are not required if you want the whole texture. | |
|*| 3 ------- 2 | |
\*/ | |
quad[0].texCoords = sf::Vector2f((float)((tileCol * tileWidth) - leftOffset), (float)((tileRow * tileHeight) - topOffset)); | |
quad[1].texCoords = sf::Vector2f((float)(((tileCol + 1) * tileWidth) - rightOffset), (float)((tileRow * tileHeight) - topOffset)); | |
quad[2].texCoords = sf::Vector2f((float)(((tileCol + 1) * tileWidth) - rightOffset), (float)(((tileRow + 1) * tileHeight) - bottomOffset)); | |
quad[3].texCoords = sf::Vector2f((float)((tileCol * tileWidth) - leftOffset), (float)(((tileRow + 1) * tileHeight) - bottomOffset)); | |
} | |
} | |
} | |
// Parse the level xml document | |
bool TileMap::readXML(const char* xmlDocument) | |
{ | |
// Used for tokenizing the level array | |
char *token, *nextToken; | |
// Clear the vector for reloading | |
map.clear(); | |
// Load the xml file | |
pugi::xml_parse_result result = document.load_file(xmlDocument); | |
// Check if loaded correctly | |
if (!result) | |
return false; | |
// Get the fields from the document | |
filepath = document.first_element_by_path("Level/Tileset", '/').text().as_string(); | |
sheetRows = document.first_element_by_path("Level/SheetRows", '/').text().as_uint(); | |
sheetColumns = document.first_element_by_path("Level/SheetColumns", '/').text().as_uint(); | |
worldWidth = document.first_element_by_path("Level/WorldWidth", '/').text().as_uint(); | |
worldHeight = document.first_element_by_path("Level/WorldHeight", '/').text().as_uint(); | |
topOffset = document.first_element_by_path("Level/TopOffset", '/').text().as_float(); | |
bottomOffset = document.first_element_by_path("Level/BottomOffset", '/').text().as_float(); | |
leftOffset = document.first_element_by_path("Level/LeftOffset", '/').text().as_float(); | |
rightOffset = document.first_element_by_path("Level/RightOffset", '/').text().as_float(); | |
layers = document.first_element_by_path("Level/Layers").text().as_uint(); | |
// Read all the map layers | |
for (unsigned int i = 0; i < layers; i++) | |
{ | |
std::vector<int> tiles; // Vector of tiles for a single layer | |
std::string layer = std::to_string(i + 1); // Get the correct layer number | |
// Get all the children of <Map layer="#"> | |
pugi::xml_node rows = document.root().first_child().find_child_by_attribute("layer", layer.c_str()); | |
// Loop through the rows and get the tile numbers | |
for each (pugi::xml_node row in rows.children()) | |
{ | |
// Tokenize the row | |
token = strtok_s((char*)row.text().as_string(), " ", &nextToken); | |
while (token) | |
{ | |
// Add tile number ('x' means no tile) | |
if (*token == 'x') | |
tiles.push_back(-1); | |
else | |
tiles.push_back(std::stoi(token)); | |
// Get next token | |
token = strtok_s(NULL, " ", &nextToken); | |
} | |
} | |
// Add layer to the map | |
map.push_back(tiles); | |
} | |
// XML file read successfully | |
return true; | |
} | |
// Draw each vertex array | |
void TileMap::draw(sf::RenderTarget& target, sf::RenderStates states) const | |
{ | |
// Apply the transforms | |
states.transform *= getTransform(); | |
// Apply the tileset texture | |
states.texture = &tileSheet; | |
// Draw the vertex arrays | |
for (unsigned int i = 0; i < vertexArray.size(); i++) | |
target.draw(vertexArray[i], states); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <string> | |
#include <SFML/Graphics.hpp> | |
#include <pugixml.hpp> | |
class TileMap : public sf::Drawable, public sf::Transformable | |
{ | |
private: | |
sf::Texture tileSheet; | |
std::string filepath; | |
// Holds the tiles | |
std::vector<std::vector<int>> map; | |
std::vector<sf::VertexArray> vertexArray; | |
// Level fields | |
unsigned int layers; | |
unsigned int sheetRows, sheetColumns; | |
unsigned int worldWidth, worldHeight; | |
unsigned int tileWidth, tileHeight; | |
// Offsets in sheet (transparent spaces usually) | |
float topOffset, bottomOffset, leftOffset, rightOffset; | |
// XML Document | |
pugi::xml_document document; | |
public: | |
TileMap(); | |
bool load(const char* xmlDocument); | |
private: | |
void setCoords(std::vector<int> &mapLayer, sf::VertexArray &vertexLayer); | |
bool readXML(const char* xmlDocument); | |
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment