feat: add SFMLEngine

This commit is contained in:
PolishPigeon 2022-06-21 20:39:15 +02:00 committed by KRZYSZTOF RUDNICKI
parent 8333a455e2
commit a3a61328aa
35 changed files with 812 additions and 0 deletions

21
CPP/SFMLEngine/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Krzysztof Rudnicki
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

BIN
CPP/SFMLEngine/helloWorld/app Executable file

Binary file not shown.

View File

@ -0,0 +1,24 @@
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
sf::CircleShape shape(100.f);
shape.setFillColor(sf::Color::Green);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.draw(shape);
window.display();
}
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,6 @@
compile:./hello.cpp
g++ -c ./hello.cpp
g++ hello.o -o app -lsfml-graphics -lsfml-window -lsfml-system
run:
./app

View File

@ -0,0 +1,42 @@
#ifndef RESOURCES_HPP
#define RESOURCES_HPP
#include <assert.h>
// Mostly Chapter 2
// Handles resource management
namespace Textures // This gives us a scope for the enumerators which allows us to write Textures::Airplane instead of just Airplane to avoid name collisions in the global scope
{
enum ID
{
Eagle,
Raptor,
Desert
};
}
template <typename Resource, typename Identifier>
class ResourceHolder
{
public:
void load(Identifier id, const std::string& filename);
Resource& get(Identifier id);
const Resource& get(Identifier id) const;
template <typename Parameter>
void load(Identifier id, const std::string& filename, const Parameter& secondParameter);
// Second parameter can be of sf::Shader::Type or std::string&
private:
std::map< Identifier, std::unique_ptr<Resource> > mResourceMap;
// unique_ptr are class templates that act like pointers, this allows us to work with heavyweight objects without copying them all the time, or we can store classes that are non-cpyable like sf::Shader
};
typedef ResourceHolder<sf::Texture, Textures::ID> TextureHolder;
#include "resources.inl"
#endif // RESOURCES_HPP

View File

@ -0,0 +1,46 @@
#ifndef RESOURCES_INL
#define RESOURCES_INL
template <typename Resource, typename Identifier>
void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& filename)
// Function to load a resource, it takes one parameter for filename and one for identifier
{
std::unique_ptr<Resource> resource(new Resource()); // Create sf:Texture and store it in the unique pointer
if(!resource -> loadFromFile(filename))// Load the resource from the filename
{
throw std::runtime_error(TEXTURE_LOAD_ERROR + filename);
}
auto inserted = mResourceMap.insert(std::make_pair(id, std::move(resource))); // Insert resource into map mResourceMap, std::move used to take ownership from resource variable and transfer it to std::make_pair(), std::move moves the resource into a new place and removes it from earlier place https://en.cppreference.com/w/cpp/utility/move
assert(inserted.second);
}
template <typename Resource, typename Identifier>
Resource& ResourceHolder<Resource, Identifier>::get(Identifier id) // returns a reference to a resource
{
auto found = mResourceMap.find(id); // find returns an iterator to the found element or end() if nothing was found
assert(found != mResourceMap.end());
return *found -> second; // We have to access the second member of the pointer, then we deference it and get a resource
}
template <typename Resource, typename Identifier>
const Resource& ResourceHolder<Resource, Identifier>::get(Identifier id) const // we need to be able to invoke get() also if we only have a pointer/reference to the const ResourceHolder<Resource, Identifier>, it returns const Resource so the resource cannot be changed by caller
{
auto found = mResourceMap.find(id); // find returns an iterator to the found element or end() if nothing was found
assert(found != mResourceMap.end());
return *found -> second; // We have to access the second member of the pointer, then we deference it and get a resource
}
template <typename Resource, typename Identifier>
template <typename Parameter>
void ResourceHolder<Resource, Identifier>::load(Identifier id, const std::string& filename, const Parameter& secondParameter) // loads Shaders
{
std::unique_ptr<Resource> resource(new Resource()); // Create sf:Texture and store it in the unique pointer
if(!resource -> loadFromFile(filename, secondParameter))// Load the resource from the filename
{
throw std::runtime_error(TEXTURE_LOAD_ERROR + filename);
}
auto inserted = mResourceMap.insert(std::make_pair(id, std::move(resource))); // Insert resource into map mResourceMap, std::move used to take ownership from resource variable and transfer it to std::make_pair(), std::move moves the resource into a new place and removes it from earlier place https://en.cppreference.com/w/cpp/utility/move
assert(inserted.second);
}
#endif // RESOURCES_INL

View File

@ -0,0 +1,94 @@
#ifndef WORLD_CPP // ZA WARUDO
#define WORLD_CPP
#include <cstddef> // std::size_t
#include "../SceneNodeDerrivatives/SpriteNode.hpp"
#include "../SceneNodeDerrivatives/entity.hpp"
World::World(sf::RenderWindow& window)
: mWindow(window)
, mWorldView(window.getDefaultView())
, mWorldBounds
(
WORLD_LEFT_X_POSITION,
WORLD_TOP_Y_POSITION,
mWorldView.getSize().x,
WORLD_HEIGHT
)
, mSpawnPosition
(
mWorldView.getSize().x / 2.f,
mWorldBounds.height - mWorldView.getSize().y
)
, mScrollSpeed ( WORLD_SCROLL_SPEED )
, mPlayerAircraft(nullptr)
{
loadTextures();
buildScene();
mWorldView.setCenter(mSpawnPosition);
}
void World::loadTextures()
{
mTextures.load(Textures::Eagle, PATH_TO_EAGLE_TEXTURE);
mTextures.load(Textures::Raptor, PATH_TO_RAPTOR_TEXTURE);
mTextures.load(Textures::Desert, PATH_TO_DESERT_TEXTURE);
}
void World::buildScene()
{
for (std::size_t i = 0; i < LayerCount; i++) // initialization of scene layers, iterate through array of layer node pointers
{
SceneNode::ScenePointer layer(new SceneNode());
mSceneLayers[i] = layer.get(); // initialize elments of this arry
mSceneGraph.attachChild(std::move(layer)); // attach new node to the scene graph's root node
}
sf::Texture& texture = mTextures.get(Textures::Desert);
sf::IntRect textureRect(mWorldBounds);
texture.setRepeated(true); // make desert texture repeat itself
std::unique_ptr<SpriteNode> backgroundSprite(new SpriteNode(texture, textureRect)); // SpriteNode class that links to the desrt texture, our sprite will be as big as the whole world because we passed the texture rectangle
backgroundSprite -> setPosition(mWorldBounds.left, mWorldBounds.top);
mSceneLayers[Background] -> attachChild(std::move(backgroundSprite));
// Adding airplanes
std::unique_ptr<Aircraft> leader(new Aircraft(Aircraft::Eagle, mTextures)); // we create the player's airplane
mPlayerAircraft = leader.get();
mPlayerAircraft -> setPosition(mSpawnPosition); // Set player position
mPlayerAircraft -> SetVelocity(PLAYER_SIDEWARD_VELOCITY, mScrollSpeed); // forward velocity equals scroll speed, sideward velocity equals PLAYER_SIDEWARD_VELOCITY
mSceneLayers[Air] -> attachChild(std::move(leader)); // we attach the plane to the Air scene layer
std::unique_ptr<Aircraft> leftEscort(new Aircraft(Aircraft::Raptor, mTextures)); // create new airplane
leftEscort -> setPosition(LEFT_ESCORT_X_POSITION, LEFT_ESCORT_Y_POSITION); // Set new airplane position
mPlayerAircraft -> attachChild(std::move(leftEscort)); // leftEscort is now a child of player aircraft and it will folow it!
std::unique_ptr<Aircraft> rightEscort(new Aircraft(Aircraft::Raptor, mTextures)); // create new airplane
rightEscort -> setPosition(RIGHT_ESCORT_X_POSITION, RIGHT_ESCORT_Y_POSITION); // Set new airplane position
mPlayerAircraft -> attachChild(std::move(rightEscort)); // leftEscort is now a child of player aircraft and it will folow it!
}
void World::draw()
{
mWindow.setView(mWorldView);
mWindow.draw(mSceneGraph);
}
void World::update(sf::Time deltaTime) // controls world scrolling and entity movement
{
mWorldView.move(0.f, mScrollSpeed * deltaTime.asSeconds());
sf::Vector2f position = mPlayerAircraft -> getPosition();
sf::Vector2f velocity = mPlayerAircraft -> getVelocity();
if(position.x <= mWorldBounds.left + WORLD_MAX_DISTANCE_FROM_BOUNDARY || position.x >= mWorldBounds.left + mWorldBounds.width - WORLD_MAX_DISTANCE_FROM_BOUNDARY) // if the player gets too close to world bounds make its velocity negative so it comes back
{
velocity.x = -velocity.x;
mPlayerAircraft -> SetVelocity(velocity);
}
mSceneGraph.update(deltaTime); // mSceneGraph actaully applies these velocities
}
#endif // WORLD_CPP

View File

@ -0,0 +1,42 @@
#ifndef WORLD_HPP // ZA WARUDO
#define WORLD_HPP
#include <array>
#include "../SceneNodeDerrivatives/SceneNode.hpp"
#include "../SceneNodeDerrivatives/aircraft.hpp"
class World : private sf::NonCopyable // We only have one world and we do not want to copy it #StopClimateChange amiright
{
public:
explicit World(sf::RenderWindow& window);
void update(sf::Time deltaTime);
void draw();
private:
void loadTextures();
void buildScene();
private:
enum Layer
{
Background,
Air,
LayerCount
};
private:
sf::RenderWindow& mWindow; // reference to the render window
sf::View mWorldView; // current world's view
TextureHolder mTextures; // All the textures needed inside the world
SceneNode mSceneGraph;
std::array<SceneNode*, LayerCount> mSceneLayers; // Pointers to access the scene graph's layerr nodes
sf::FloatRect mWorldBounds; // Bounding rectangle of the world
sf::Vector2f mSpawnPosition; // Where player plane appears in the beginning
float mScrollSpeed; // Speed with which the world is scrolled
Aircraft* mPlayerAircraft; // Pointer to player aircraft
};
// std::array is a class template for fixed size static arrays, same functionality, performance as C arrays but allows copies, assignment, passing or returning objects from the function, additional safety and usefull methods like size(), begin() or end()
#include "world.cpp"
#endif // WORLD_HPP

View File

@ -0,0 +1,86 @@
#ifndef SCENE_NODE_CPP
#define SCENE_NODE_CPP
void SceneNode::attachChild(ScenePointer child) // takes ownership of the scene node
{
child -> mParent = this;
mChildren.push_back(std::move(child));
}
SceneNode::ScenePointer SceneNode::detachChild(const SceneNode& node) // finds node, releases it and returns it to caller
{
auto found = std::find_if
(
mChildren.begin(), mChildren.end(),
[&] (ScenePointer& p) -> bool { return p.get() == &node; }
);
// This is lambda expression
// [&] (ScenePointer& p) -> bool { return p.get() == &node; }
// [&] - how many and in what way will the lambda expression have access to the variables in surrounding scope, [] - no variables [&] - all variables by reference [=] - all variables by value
// (ScenePointer& p) - parameters passed to the function
// -> bool - return type
// function body encolsed in {}
assert(found != mChildren.end()); // We check validity of the iterator of the found element
ScenePointer result = std::move(*found); // we move the found node out of the container to result
result -> mParent = nullptr; // node's parent is set to null pointer
mChildren.erase(found); // we erase this element from the container
return result; // and we return the pointer to the node
}
void SceneNode::drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const
{
}
void SceneNode::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
// *= combines the parent's absolute transform with the relative one of the current node;
// states.transform contains the absolute world transform
drawCurrent(target, states); // now we can draw the derived object using states, this is similar to how sf::Sprite handles transforms
for (const ScenePointer& child : mChildren)
{
child -> draw(target, states); // we also need to draw all the child nodes
}
}
void SceneNode::updateCurrent(sf::Time deltaTime)
{
}
void SceneNode::updateChildren(sf::Time deltaTime)
{
for (const ScenePointer& child : mChildren)
{
child -> update(deltaTime); // we also need to draw all the child nodes
}
}
void SceneNode::update(sf::Time deltaTime)
{
updateCurrent(deltaTime);
updateChildren(deltaTime);
}
sf::Transform SceneNode::getWorldTransform() const
{
sf::Transform transform = sf::Transform::Identity; // sf::Transform::Identity represents the identity transform - it does not have any effecft on the object, it is not necessary in the code but it clarifies how transforms are applied
for (const SceneNode* node = this; node != nullptr; node = node -> mParent)
{
transform = node -> getTransform() * transform;
}
return transform;
}
sf::Vector2f SceneNode::getWorldPosition() const
{
return getWorldTransform() * sf::Vector2f();
}
#endif

View File

@ -0,0 +1,39 @@
#ifndef SCENE_NODE_HPP
#define SCENE_NODE_HPP
class SceneNode : public sf::Transformable, public sf::Drawable, private sf::NonCopyable
// we derrive from transformable - to be able to store and modify position, rotation and scale
// we derrive from drawable - to be able to draw it on screen
// we derrive from noncopyable - so that copy constructor and copy assignemnt operators are disabled
// This is used to create scene graph (tree data structure) in order to manage transform hierarchies
{
public:
typedef std::unique_ptr<SceneNode> ScenePointer; // element types must be complete types and we do not want to manage memory ourselves so we use std::unique_ptr
public:
//SceneNode();
void attachChild(ScenePointer child);
ScenePointer detachChild(const SceneNode& node);
void update(sf::Time deltaTime);
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const; // we override draw() function of sf::Drawable
// Virtual functions are member functions whose behavior can be overridden in derived classes
// draw() function allows our class to be used like this:
/*
sf::RenderWindow window(...); // window class calls our draw() function
SceneNode::ScenePointer node(...);
window.draw(*node);
*/
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const; // draws only the current object, and not the children
virtual void updateCurrent(sf::Time deltaTime); // we reuse scene graph to reach all entities with world update, this one updates current node
void updateChildren(sf::Time deltaTime); // this one updates child nodes
sf::Transform getWorldTransform() const; // it takes into account all the parent transform
sf::Vector2f getWorldPosition() const;
private:
std::vector<ScenePointer> mChildren;
SceneNode* mParent;
};
#include "SceneNode.cpp"
#endif

View File

@ -0,0 +1,19 @@
#ifndef SPRITE_NODE_CPP
#define SPRITE_NODE_CPP
SpriteNode::SpriteNode(const sf::Texture& texture)
: mSprite(texture)
{
}
SpriteNode::SpriteNode(const sf::Texture& texture, const sf::IntRect& textureRect)
: mSprite(texture, textureRect)
{
}
void SpriteNode::drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(mSprite, states);
}
#endif // SPRITE_NODE_CPP

View File

@ -0,0 +1,20 @@
#ifndef SPRITE_NODE_HPP
#define SPRITE_NODE_HPP
class SpriteNode : public SceneNode
{
public:
explicit SpriteNode(const sf::Texture& texture);
SpriteNode(const sf::Texture& texture, const sf::IntRect& rectangle);
private:
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const;
private:
sf::Sprite mSprite;
};
#include "SpriteNode.cpp"
#endif // SPRITE_NODE_HPP

View File

@ -0,0 +1,32 @@
#ifndef AIRCRAFT_CPP
#define AIRCRAFT_CPP
Textures::ID toTextureID(Aircraft::Type type)
{
switch (type)
{
case Aircraft::Eagle:
return Textures::Eagle;
case Aircraft::Raptor:
return Textures::Raptor;
default:
return Textures::Eagle;
}
return Textures::Eagle;
}
Aircraft::Aircraft(Type type, const TextureHolder& textures) : mType(type), mSprite(textures.get(toTextureID(type)))
{
sf::FloatRect bounds = mSprite.getLocalBounds(); // we get local bounding rectangle which means that we do not take transforms into account, as opposed to getGlobalBounds()
mSprite.setOrigin(bounds.width / 2.f, bounds.height / 2.f); // we want to set origin of the sprite to the middle of a rectangle around it
}
void Aircraft::drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(mSprite, states);
}
#endif

View File

@ -0,0 +1,25 @@
#ifndef AIRCRAFT_HPP
#define AIRCRAFT_HPP
#include "entity.hpp"
class Aircraft : public Entity
{
public:
enum Type
{
Eagle,
Raptor
};
public:
explicit Aircraft(Type type, const TextureHolder& textures);
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const;
private:
Type mType;
sf::Sprite mSprite;
};
#include "aircraft.cpp"
#endif

View File

@ -0,0 +1,25 @@
#ifndef ENTITY_CPP
#define ENTITY_CPP
void Entity::SetVelocity(sf::Vector2f velocity)
{
mVelocity = velocity;
}
void Entity::SetVelocity(float velocityX, float velocityY)
{
mVelocity.x = velocityX;
mVelocity.y = velocityY;
}
sf::Vector2f Entity::getVelocity() const
{
return mVelocity;
}
void Entity::updateCurrent(sf::Time deltaTime)
{
move(mVelocity * deltaTime.asSeconds()); // shortcut for setPosition(getPosition() + offset)
}
#endif

View File

@ -0,0 +1,21 @@
#ifndef ENTITY_HPP
#define ENTITY_HPP
#include "SceneNode.hpp"
#include "SceneNode.cpp"
class Entity : public SceneNode
{
public:
void SetVelocity(sf::Vector2f velocity);
void SetVelocity(float velocityX, float velocityY);
sf::Vector2f getVelocity() const;
private:
sf::Vector2f mVelocity; // default ocnstructor initializes this vector to a zero vector
virtual void updateCurrent(sf::Time deltaTime);
};
#include "entity.cpp"
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

View File

@ -0,0 +1,10 @@
#ifndef BASIC_CPP
#define BASIC_CPP
#include <iostream>
void print(const std::string s)
{
std::cout << s << std::endl;
}
#endif // BASIC_CPP

Binary file not shown.

View File

@ -0,0 +1,47 @@
#ifndef CONSTANTS_HPP
#define CONSTANTS_HPP
#include <SFML/Graphics.hpp>
// Paths
const std::string PATH_TO_PLAYER_TEXTURE = "Textures/Player.png";
const std::string PATH_TO_EAGLE_TEXTURE = "Textures/Eagle.png";
const std::string PATH_TO_RAPTOR_TEXTURE = "Textures/Raptor.png";
const std::string PATH_TO_DESERT_TEXTURE = "Textures/Desert.jpg";
// Player constants
const float PLAYER_RADIUS = 40;
const float PLAYER_X_POSITION = 100;
const float PLAYER_Y_POSITION = 100;
const sf::Color PLAYER_COLOR = sf::Color::Cyan;
const float PLAYER_SIDEWARD_VELOCITY = 40;
// Other sprites constants
const float LEFT_ESCORT_X_POSITION = -80;
const float LEFT_ESCORT_Y_POSITION = 50;
const float RIGHT_ESCORT_X_POSITION = -LEFT_ESCORT_X_POSITION;
const float RIGHT_ESCORT_Y_POSITION = LEFT_ESCORT_Y_POSITION;
// Movement constants
// const sf::Vector2f INITIAL_MOVEMENT (0.f, 0.f);
const float MOVING_UP_SPEED = -100;
const float MOVING_DOWN_SPEED = -MOVING_UP_SPEED;
const float MOVING_RIGHT_SPEED = 100;
const float MOVING_LEFT_SPEED = -MOVING_RIGHT_SPEED;
// Time constants
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 60.f); // 1 frame is 1 / 60 of the second so we get 60 frames in a second
// Error strings
const std::string TEXTURE_LOAD_ERROR = "TextureHolder::load - Failed to load ";
// World constants
const float WORLD_LEFT_X_POSITION = 0;
const float WORLD_TOP_Y_POSITION = 0;
// const float WORLD_WIDTH = 0; by default mWorldView.getSize().x
const float WORLD_HEIGHT = 2000;
const float WORLD_SCROLL_SPEED = -1;
const float WORLD_MAX_DISTANCE_FROM_BOUNDARY = 150;
#endif // CONSTANTS_HPP

View File

@ -0,0 +1,161 @@
#ifndef GAME_CPP
#define GAME_CPP
#include <vector>
#include <SFML/Graphics.hpp>
#include "constants.hpp"
#include "./Classes/Other/resources.hpp"
#include "./Classes/Other/world.hpp"
#include "./Classes/SceneNodeDerrivatives/SceneNode.hpp"
#include "./Classes/SceneNodeDerrivatives/SpriteNode.hpp"
#include "./Classes/SceneNodeDerrivatives/entity.hpp"
#include "./Classes/SceneNodeDerrivatives/aircraft.hpp"
#include "basic.cpp"
class Game : private sf::NonCopyable
{
public:
Game(); // Sets up player radius, position and fill color
void run(); // runs the processEvents, update and render methods
private:
void processEvents(); // playerInput, mainLoop
void update(sf::Time deltaTime); // code that updates the game
void render(); // code that renders the game
void handlePlayerInput(sf::Keyboard::Key key, bool isPressed);
bool mIsMovingUp = false;
bool mIsMovingRight = false;
bool mIsMovingLeft = false;
bool mIsMovingDown = false;
private:
sf::RenderWindow mWindow;
TextureHolder mTexture;
sf::Sprite mPlayer;
World mWorld;
};
Game::Game()
: mWindow(sf::VideoMode(640, 480), "World", sf::Style::Close)
, mWorld(mWindow)
/* , mFont()
, mStatisticsText()
, mStatisticsUpdateTime()
, mStatisticsNumFrames(0)
*/
{
/* mFont.loadFromFile("Media/Sansation.ttf");
mStatisticsText.setFont(mFont);
mStatisticsText.setPosition(5.f, 5.f);
mStatisticsText.setCharacterSize(10);
*/
}
// Resposible for managing game loop - fetching input form the window system, updating the world, and ordering the rendering of the game
void Game::run()
{
/* Other useful frame rate related tecnhiques:
sf::sleep - interrupts the execution for a given time, not very accurate
sf::RenderWindow::setFramerateLimit() - tries to achieve the frame rate by calling sf::sleep, nice for testing purposes
sf::RenderWindow::setVerticalSyncEnabled() - enables V-sync which adapts the rate of graphical updates from sf::RenderWindow::display() to the refresh rate of the monitor
*/
sf::Clock clock;
sf::Time timeSinceLastUpdateFunction = sf::Time::Zero;
while (mWindow.isOpen()) // this loop calls the render method
{
processEvents();
timeSinceLastUpdateFunction += clock.restart();
while(timeSinceLastUpdateFunction > TIME_PER_FRAME) // fixed time stamps
// this loop collects user input and computes game logic
{
timeSinceLastUpdateFunction -= TIME_PER_FRAME;
processEvents();
update(TIME_PER_FRAME);
}
render();
}
}
/*
const std::vector < pair<bool, sf::Keyboard::Key> > PLAYER_MOVEMENT =
{
{mIsMovingUp, sf::Keyboard::W},
{mIsMovingDown, sf::Keyboard::S},
{mIsMovingLeft, sf::Keyboard::A},
{mIsMovingRight, sf::Keyboard::D}
}
*/
void Game::handlePlayerInput(sf::Keyboard::Key key, bool isPressed)
{
if (key == sf::Keyboard::W) mIsMovingUp = isPressed;
else if (key == sf::Keyboard::S) mIsMovingDown = isPressed;
else if (key == sf::Keyboard::A) mIsMovingLeft = isPressed;
else if (key == sf::Keyboard::D) mIsMovingRight = isPressed;
}
void Game::processEvents()
{
sf::Event event;
while (mWindow.pollEvent(event)) // mainLoop/gameLoop
{
// each time while loop iterates it means that we got a new event registered by the window.
switch (event.type)
{
case sf::Event::KeyPressed:
handlePlayerInput(event.key.code, true);
break;
case sf::Event::KeyReleased:
handlePlayerInput(event.key.code, false);
break;
case sf::Event::Closed:
mWindow.close();
break;
default:
break;
}
}
}
void Game::update(sf::Time deltaTime)
{
sf::Vector2f movement (0.f, 0.f); // movement from the origin of the current coordinate system, in this case origin is the shape's positon
movement.y += mIsMovingUp * MOVING_UP_SPEED + mIsMovingDown * MOVING_DOWN_SPEED;
movement.x += mIsMovingLeft * MOVING_LEFT_SPEED + mIsMovingRight * MOVING_RIGHT_SPEED;
mPlayer.move(movement * deltaTime.asSeconds());
// from physics formula distance = speed * time
// this allows us to move exactly the distance we want it to move in one second, no matter what computer are we on
// delta time / time step - time that has elapsed since the last frame
// mWorldView.move(0.f, mScrollSpeed * deltaTime.asSeconds()); we scroll up the map, we update both the map and the player so he does not get left behind, we multiple by time to ensure that we have the same speed of n pixels per second no matter the simulation frame rate
}
void Game::render()
{
mWindow.clear();
mWorld.draw();
mWindow.setView(mWindow.getDefaultView());
// mWindow.draw(mStatisticsText);
mWindow.display();
}
int main()
{
try
{
Game game;
game.run();
}
catch (std::exception& e)
{
std::cout << "\nEXCEPTION: " << e.what() << std::endl;
}
}
#endif // GAME_CPP

Binary file not shown.

View File

@ -0,0 +1,9 @@
CXXFLAGS = -Wextra -Wall -Wfloat-equal -Wundef -Wshadow -Wpointer-arith -Wcast-align -Wstrict-overflow=5 -Wwrite-strings -Wcast-qual -Wunreachable-code -pedantic -Wswitch-default -Wno-unused-parameter
# https://stackoverflow.com/a/3376483
compile:./game.cpp
g++ $(CXXFLAGS) -c ./game.cpp
g++ game.o -o app -lsfml-graphics -lsfml-window -lsfml-system
run:
./app

BIN
CPP/SFMLEngine/minimalExample/app Executable file

Binary file not shown.

View File

@ -0,0 +1,34 @@
// SFML is split into 5 modules:
// #include <SFML/Graphics.hpp>
// #include <SFML/Audio.hpp>
// #include <SFML/System.hpp>
// #include <SFML/Window.hpp>
// #include <SFML/Network.hpp>
// We can include them like this or we can include just a specific header file:
// #include <SFML/Audio/Sound.hpp>
// Each module is compiled to separate library, it can be built for release or debug, linked statically or dynamically
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(640, 480), "SFML Application");
sf::CircleShape shape;
const float CIRCLE_RADIUS = 40;
shape.setRadius(CIRCLE_RADIUS);
const float CIRCLE_POSITION_X = 100;
const float CIRCLE_POSITION_Y = 100;
shape.setPosition(CIRCLE_POSITION_X, CIRCLE_POSITION_Y);
shape.setFillColor(sf::Color::Cyan);
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed) window.close();
}
window.clear();
window.draw(shape);
window.display();
}
}

Binary file not shown.

View File

@ -0,0 +1,6 @@
compile:./example.cpp
g++ -c ./example.cpp
g++ example.o -o app -lsfml-graphics -lsfml-window -lsfml-system
run:
./app

3
CPP/SFMLEngine/readme.md Normal file
View File

@ -0,0 +1,3 @@
# Textures and Audio used:
## Space Game Starter Set by [hc](https://opengameart.org/users/hc) - https://opengameart.org/content/space-game-starter-set
## 100 seamless textures by [Mitch Featherston](http://pdtextures.blogspot.com/) (Submitted by [Clint Bellanger](https://opengameart.org/users/clint-bellanger) - https://opengameart.org/content/100-seamless-textures