master
NaiJi ✨ 2 years ago
commit ac521c3129
  1. 3
      .gitignore
  2. 37
      application.cpp
  3. 23
      application.h
  4. 36
      command.h
  5. 31
      danmaku.pro
  6. 48
      enemy.cpp
  7. 36
      enemy.h
  8. 34
      entity.cpp
  9. 26
      entity.h
  10. 57
      game.cpp
  11. 31
      game.h
  12. 8
      main.cpp
  13. 57
      player.cpp
  14. 37
      player.h
  15. 55
      resourceholder.h
  16. 92
      scenenode.cpp
  17. 45
      scenenode.h
  18. 20
      spritenode.cpp
  19. 22
      spritenode.h
  20. 9
      state.cpp
  21. 35
      state.h
  22. 84
      world.cpp
  23. 46
      world.h

3
.gitignore vendored

@ -0,0 +1,3 @@
*.ogg
*.png
*user*

@ -0,0 +1,37 @@
#include "application.h"
#include "game.h"
constexpr int SCREEN_WIDTH = 640;
constexpr int SCREEN_HEIGHT = 480;
const sf::Time TIME_PER_SECOND = sf::seconds(1.f / 60.f);
Application::Application() :
render_window({SCREEN_WIDTH, SCREEN_HEIGHT}, "Test")
{}
void Application::registerStates()
{
map_states[State::Tag::Game] = std::make_unique<Game>(render_window, this);
active_state_tag = State::Tag::Game;
}
void Application::run()
{
sf::Clock clock;
sf::Time since_last_update = sf::Time::Zero;
while (render_window.isOpen())
{
map_states[active_state_tag]->processInput();
sf::Time delta = clock.restart();
since_last_update -= TIME_PER_SECOND;
map_states[active_state_tag]->processInput();
//if (!b_pause)
map_states[active_state_tag]->update(delta);
map_states[active_state_tag]->draw();
}
}

@ -0,0 +1,23 @@
#ifndef APPLICATION_H
#define APPLICATION_H
#include "state.h"
#include <memory>
#include <map>
class Application
{
public:
Application();
void registerStates();
void run();
private:
sf::RenderWindow render_window;
std::map<State::Tag, StateUPtr> map_states;
State::Tag active_state_tag;
};
#endif // APPLICATION_H

@ -0,0 +1,36 @@
#ifndef COMMAND_H
#define COMMAND_H
#include <functional>
namespace Category
{
enum Type
{
None = 0,
Scene = 1 << 0,
Player = 1 << 1,
Enemy = 1 << 2
};
}
class SceneNode;
namespace sf { class Time; }
struct Command
{
std::function<void(SceneNode&, sf::Time)> action;
Category::Type category;
};
template<typename GameObject, typename Functon>
std::function<void(SceneNode&, const sf::Time&)> derivedAction(Functon func)
{
return [=] (SceneNode& node, const sf::Time& time)
{
//assert(dynamic_cast<GameObject*>(&node));
func(static_cast<GameObject&>(node), time);
};
}
#endif // COMMAND_H

@ -0,0 +1,31 @@
TEMPLATE = app
CONFIG += c++17
CONFIG -= app_bundle
CONFIG -= qt
SOURCES += \
application.cpp \
entity.cpp \
enemy.cpp \
game.cpp \
main.cpp \
player.cpp \
scenenode.cpp \
spritenode.cpp \
state.cpp \
world.cpp
HEADERS += \
application.h \
command.h \
entity.h \
enemy.h \
game.h \
player.h \
resourceholder.h \
scenenode.h \
spritenode.h \
state.h \
world.h
unix:LIBS += -lsfml-graphics -lsfml-audio -lsfml-window -lsfml-system

@ -0,0 +1,48 @@
#include "enemy.h"
// /////////////////////////////////////////////////////////// //
static Textures::Id toTextureID(const Enemy::Type& type)
{
switch (type)
{
case Enemy::Type::Shotguner:
return Textures::Id::Shotguner;
case Enemy::Type::Weakling:
return Textures::Id::Weakling;
case Enemy::Type::Player:
return Textures::Id::Player;
}
return Textures::Id::Weakling;
}
// /////////////////////////////////////////////////////////// //
Enemy::Enemy(Type type, const TextureHolder& texture_holder) :
enemy_type(type),
enemy_sprite(texture_holder.get(toTextureID(type)))
{
const sf::FloatRect bounds = enemy_sprite.getLocalBounds();
enemy_sprite.setOrigin(bounds.width / 2.f, bounds.height / 2.f);
}
Enemy::~Enemy()
{}
Enemy::Type Enemy::type() const
{
return enemy_type;
}
Category::Type Enemy::category() const
{
return Category::Type::Enemy;
}
void Enemy::drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(enemy_sprite, states);
}

@ -0,0 +1,36 @@
#ifndef FAIRY_H
#define FAIRY_H
#include "entity.h"
#include "resourceholder.h"
#include <SFML/Graphics/Sprite.hpp>
class Enemy : public Entity
{
public:
enum class Type
{
Player,
Weakling,
Shotguner
};
explicit Enemy(Type type, const TextureHolder& texture_holder);
virtual ~Enemy() override;
Type type() const;
Category::Type category() const override;
private:
Type enemy_type;
sf::Sprite enemy_sprite;
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const override;
};
using EnemySPtr = std::shared_ptr<Enemy>;
using EnemyUPtr = std::unique_ptr<Enemy>;
#endif // FAIRY_H

@ -0,0 +1,34 @@
#include "entity.h"
Entity::Entity() :
vector_velocity(0.f, 0.f)
{}
Entity::~Entity()
{}
void Entity::setVelocity(sf::Vector2f vel)
{
vector_velocity = vel;
}
void Entity::setVelocity(float vx, float vy)
{
vector_velocity.x = vx;
vector_velocity.y = vy;
}
const sf::Vector2f& Entity::velocity() const
{
return vector_velocity;
}
void Entity::accelerate(sf::Vector2f vel)
{
vector_velocity += vel;
}
void Entity::updateCurrent(const sf::Time& dt)
{
move(vector_velocity * dt.asSeconds());
}

@ -0,0 +1,26 @@
#ifndef ENTITY_H
#define ENTITY_H
#include "scenenode.h"
#include <SFML/System.hpp>
class Entity : public SceneNode
{
public:
explicit Entity();
virtual ~Entity() = 0;
void setVelocity(sf::Vector2f vel);
void setVelocity(float vx, float vy);
const sf::Vector2f& velocity() const;
void accelerate(sf::Vector2f vel);
private:
sf::Vector2f vector_velocity;
virtual void updateCurrent(const sf::Time& dt) override;
};
#endif // ENTITY_H

@ -0,0 +1,57 @@
#include "game.h"
Game::Game(sf::RenderWindow &window, Application *application) :
State(window, application),
world(render_window)
{}
Game::~Game()
{}
bool Game::processInput()
{
std::queue<Command>& queue = world.getCommandQueue();
sf::Event event;
while (render_window.pollEvent(event))
{
player.handleEvent(event, queue);
switch (event.type)
{
case sf::Event::GainedFocus:
b_pause = false;
break;
case sf::Event::LostFocus:
b_pause = true;
break;
case sf::Event::Closed:
render_window.close();
break;
default:
break;
}
}
player.handleRealtimeInput(queue);
return true;
}
bool Game::update(const sf::Time &dt)
{
world.update(dt);
return true;
}
void Game::draw()
{
render_window.clear();
world.draw();
render_window.setView(render_window.getDefaultView());
render_window.display();
}

@ -0,0 +1,31 @@
#ifndef GAME_H
#define GAME_H
#include "world.h"
#include "player.h"
#include "state.h"
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Keyboard.hpp>
class Game final : public State
{
public:
Game(sf::RenderWindow& window, Application *application);
virtual ~Game() override;
void run();
private:
World world;
Player player;
bool b_pause;
bool b_to_right, b_to_left, b_to_up, b_to_down;
bool processInput() override;
bool update(const sf::Time& dt) override;
void draw() override;
};
#endif // GAME_H

@ -0,0 +1,8 @@
#include "application.h"
int main()
{
Application app;
app.registerStates();
app.run();
}

@ -0,0 +1,57 @@
#include "player.h"
#include "command.h"
#include "enemy.h"
Player::Player() :
player_speed(45.f)
{
map_key_bindings[sf::Keyboard::Left] = Action::MoveLeft;
map_key_bindings[sf::Keyboard::Right] = Action::MoveRight;
map_key_bindings[sf::Keyboard::Up] = Action::MoveUp;
map_key_bindings[sf::Keyboard::Down] = Action::MoveDown;
map_action_bindings[Action::MoveLeft].action =
[&] (SceneNode& node, const sf::Time& time)
{
node.move(-player_speed * time.asSeconds(), 0.f);
};
map_action_bindings[Action::MoveRight].action =
[&] (SceneNode& node, const sf::Time& time)
{
node.move(player_speed * time.asSeconds(), 0.f);
};
map_action_bindings[Action::MoveUp].action =
[&] (SceneNode& node, const sf::Time& time)
{
node.move(0.f, -player_speed * time.asSeconds());
};
map_action_bindings[Action::MoveDown].action =
[&] (SceneNode& node, const sf::Time& time)
{
node.move(0.f, player_speed * time.asSeconds());
};
for (auto& pair : map_action_bindings)
pair.second.category = Category::Enemy;
}
void Player::handleRealtimeInput(std::queue<Command>& queue)
{
for (const auto& pair : map_key_bindings)
if (sf::Keyboard::isKeyPressed(pair.first) && isRealtime(pair.second))
queue.push(map_action_bindings[pair.second]);
}
void Player::handleEvent(const sf::Event &event, std::queue<Command> &queue)
{
switch (event.type)
{
case sf::Event::KeyPressed:
break;
default:
break;
}
}

@ -0,0 +1,37 @@
#ifndef PLAYER_H
#define PLAYER_H
#include <queue>
#include <map>
#include <SFML/Window/Event.hpp>
class Command;
class Player
{
public:
Player();
enum class Action
{
MoveLeft,
MoveRight,
MoveUp,
MoveDown
};
void assignKey(Action action, sf::Keyboard::Key key);
sf::Keyboard::Key getAssignedKey(Action action) const;
void handleEvent(const sf::Event& event, std::queue<Command>& queue);
void handleRealtimeInput(std::queue<Command>& queue);
private:
float player_speed;
std::map<sf::Keyboard::Key, Action> map_key_bindings;
std::map<Action, Command> map_action_bindings;
static bool isRealtime(Action action) {return true;}
};
#endif // PLAYER_H

@ -0,0 +1,55 @@
#ifndef RESOURCEHOLDER_H
#define RESOURCEHOLDER_H
#include <assert.h>
#include <string>
#include <memory>
#include <map>
namespace sf { class Texture; class Font; }
template <typename Resource, typename Id>
class ResourceHolder
{
public:
bool load(Id id, const std::string& filename)
{
std::unique_ptr<Resource> resource(new Resource());
if (!resource->loadFromFile(filename))
return false;
map_resources[id] = std::move(resource);
return true;
}
Resource& get(Id id) const
{
const auto found = map_resources.find(id);
assert(found != map_resources.end());
return *found->second;
}
private:
std::map<Id, std::unique_ptr<Resource>> map_resources;
};
// /////////////////////////////////////////////////////////// //
namespace Textures
{
enum class Id
{
Player,
Weakling,
Shotguner,
Background
};
}
using TextureHolder = ResourceHolder<sf::Texture, Textures::Id>;
using FontHolder = ResourceHolder<sf::Font, Textures::Id>;
#endif // RESOURCEHOLDER_H

@ -0,0 +1,92 @@
#include "scenenode.h"
#include <algorithm>
SceneNode::SceneNode()
{}
SceneNode::~SceneNode()
{}
bool SceneNode::attachChild(const SceneNodeSPtr &child)
{
child->parent = shared_from_this();
vec_children.emplace_back(std::move(child));
return true;
}
SceneNodeSPtr SceneNode::detachChild(const SceneNode &node)
{
const auto found = std::find_if(vec_children.begin(), vec_children.end(),
[&] (SceneNodeSPtr& p) -> bool
{
return p.get() == &node;
});
if (found == vec_children.end())
return nullptr;
SceneNodeSPtr result = *found;
result->parent = nullptr;
vec_children.erase(found);
return result;
}
sf::Transform SceneNode::getWorldTransform() const
{
sf::Transform transform = sf::Transform::Identity;
for (SceneNodeConstSPtr node = shared_from_this(); node != nullptr; node = node->parent)
{
transform *= node->getTransform();
}
return transform;
}
sf::Vector2f SceneNode::getWorldPosition() const
{
return getWorldTransform() * sf::Vector2f();
}
void SceneNode::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
drawCurrent(target, states);
for (const auto& ch : vec_children)
ch->draw(target, states);
}
void SceneNode::update(const sf::Time& dt)
{
updateCurrent(dt);
updateChildren(dt);
}
void SceneNode::onCommand(const Command& command, const sf::Time& dt)
{
if (command.category & category())
command.action(*shared_from_this(), dt);
for (auto& ch : vec_children)
ch->onCommand(command, dt);
}
Category::Type SceneNode::category() const
{
return Category::Type::Scene;
}
void SceneNode::drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const
{}
void SceneNode::updateCurrent(const sf::Time& dt)
{}
void SceneNode::updateChildren(const sf::Time &dt)
{
for (SceneNodeSPtr& child : vec_children)
child->update(dt);
}

@ -0,0 +1,45 @@
#ifndef SCENENODE_H
#define SCENENODE_H
#include "command.h"
#include <vector>
#include <memory>
#include <SFML/Graphics.hpp>
class SceneNode;
using SceneNodeUPtr = std::unique_ptr<SceneNode>;
using SceneNodeSPtr = std::shared_ptr<SceneNode>;
using SceneNodeConstSPtr = std::shared_ptr<const SceneNode>;
class SceneNode : public std::enable_shared_from_this<SceneNode>,
public sf::Transformable,
public sf::Drawable,
private sf::NonCopyable
{
public:
explicit SceneNode();
virtual ~SceneNode();
bool attachChild(const SceneNodeSPtr &child);
SceneNodeSPtr detachChild(const SceneNode& node);
sf::Transform getWorldTransform() const;
sf::Vector2f getWorldPosition() const;
void update(const sf::Time& dt);
void onCommand(const Command& command, const sf::Time& dt);
virtual Category::Type category() const;
private:
std::vector<SceneNodeSPtr> vec_children;
SceneNodeSPtr parent;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override final;
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const;
virtual void updateCurrent(const sf::Time& dt);
void updateChildren(const sf::Time& dt);
};
#endif // SCENENODE_H

@ -0,0 +1,20 @@
#include "spritenode.h"
SpriteNode::SpriteNode(const sf::Texture& texture)
{
sprite.setTexture(texture);
}
SpriteNode::~SpriteNode()
{}
SpriteNode::SpriteNode(const sf::Texture& texture, const sf::IntRect& rect)
{
sprite.setTexture(texture);
sprite.setTextureRect(rect);
}
void SpriteNode::drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const
{
target.draw(sprite, states);
}

@ -0,0 +1,22 @@
#ifndef SPRITENODE_H
#define SPRITENODE_H
#include "scenenode.h"
class SpriteNode : public SceneNode
{
public:
explicit SpriteNode(const sf::Texture& texture);
explicit SpriteNode(const sf::Texture& texture,
const sf::IntRect& rect);
virtual ~SpriteNode();
private:
sf::Sprite sprite;
virtual void drawCurrent(sf::RenderTarget& target, sf::RenderStates states) const;
};
using SpriteNodeUPtr = std::unique_ptr<SpriteNode>;
using SpriteNodeSPtr = std::shared_ptr<SpriteNode>;
#endif // SPRITENODE_H

@ -0,0 +1,9 @@
#include "state.h"
State::State(sf::RenderWindow &window, Application *application) :
render_window(window),
app(application)
{}
State::~State()
{}

@ -0,0 +1,35 @@
#ifndef STATE_H
#define STATE_H
#include <SFML/System.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
#include <memory>
class Application;
class State
{
public:
explicit State(sf::RenderWindow& window, Application *application);
virtual ~State() = 0;
virtual void draw() = 0;
virtual bool update(const sf::Time& dt) = 0;
virtual bool processInput() = 0;
enum class Tag
{
Menu,
Game
};
protected:
sf::RenderWindow& render_window;
Application *app;
};
using StateUPtr = std::unique_ptr<State>;
using StateSPtr = std::shared_ptr<State>;
#endif // STATE_H

@ -0,0 +1,84 @@
#include "world.h"
#include "spritenode.h"
#include "enemy.h"
#include <cmath>
World::World(sf::RenderWindow& window) :
world_window(window),
world_view(window.getDefaultView()),
scene_graph(new SceneNode()),
world_bounds(0.f, 0.f, world_view.getSize().x, 2000.f),
world_spawn_pos(world_view.getSize().x / 2.f, world_bounds.height - world_view.getSize().y),
player(nullptr)
{
loadTextures();
buildScene();
world_view.setCenter(world_spawn_pos);
}
void World::update(const sf::Time &dt)
{
world_view.move(0.f, world_speed * dt.asSeconds());
player->setVelocity(0.f, 0.f);
while (!queue_commands.empty())
{
scene_graph->onCommand(queue_commands.front(), dt);
queue_commands.pop();
}
//sf::Vector2f position = player->getPosition();
sf::Vector2f velocity = player->velocity();
if (velocity.x != 0.f && velocity.y != 0.f)
player->setVelocity(velocity / std::sqrt(2.f));
player->accelerate({0.f, world_speed});
scene_graph->update(dt);
}
void World::draw()
{
world_window.setView(world_view);
world_window.draw(*scene_graph);
}
std::queue<Command>& World::getCommandQueue()
{
return queue_commands;
}
bool World::loadTextures()
{
return /*texture_holder.load(Textures::Id::Weakling, "sprite_weakling.png")
&& texture_holder.load(Textures::Id::Shotguner, "sprite_shotguner.png")
&& */texture_holder.load(Textures::Id::Background, "sprite_back.png")
&& texture_holder.load(Textures::Id::Player, "sprite.png");
}
void World::buildScene()
{
for (std::size_t i = 0; i < LayerCount; ++i)
{
SceneNodeSPtr layer(new SceneNode());
arr_layers[i] = layer;
scene_graph->attachChild(layer);
}
sf::Texture texture = texture_holder.get(Textures::Id::Background);
sf::IntRect texture_rect(world_bounds);
texture.setRepeated(true);
SpriteNodeSPtr background_sprite(new SpriteNode(texture, texture_rect));
background_sprite->setPosition(world_bounds.left, world_bounds.top);
arr_layers[Background]->attachChild(background_sprite);
player = std::make_shared<Enemy>(Enemy::Type::Player, texture_holder);
player->setPosition(world_spawn_pos);
player->setVelocity(40.f, world_speed);
arr_layers[Air]->attachChild(player);
}

@ -0,0 +1,46 @@
#ifndef WORLD_H
#define WORLD_H
#include "enemy.h"
#include "resourceholder.h"
#include "scenenode.h"
#include <queue>
#include <SFML/System.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
class World : private sf::NonCopyable
{
public:
explicit World(sf::RenderWindow& window);
void update(const sf::Time& dt);
void draw();
std::queue<Command>& getCommandQueue();
private:
bool loadTextures();
void buildScene();
enum Layer
{
Background,
Air,
LayerCount
};
std::queue<Command> queue_commands;
sf::RenderWindow& world_window;
sf::View world_view;
TextureHolder texture_holder;
SceneNodeSPtr scene_graph;
std::array<SceneNodeSPtr, LayerCount> arr_layers;
sf::FloatRect world_bounds;
sf::Vector2f world_spawn_pos;
float world_speed;
EnemySPtr player;
};
#endif // WORLD_H
Loading…
Cancel
Save