Skip to content
Snippets Groups Projects
Commit d2a40a8b authored by Filip Strömbäck's avatar Filip Strömbäck
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 518 additions and 0 deletions
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <cmath>
#include <SFML/Graphics.hpp>
using std::cout;
using std::endl;
using std::shared_ptr;
using std::unique_ptr;
using std::vector;
using std::string;
using std::min;
using std::max;
extern const size_t width;
extern const size_t height;
#include "component.h"
void Component::added(Entity &) {}
bool Component::tick(sf::Time, Entity &, World &) { return true; }
void Component::render(sf::RenderWindow &, Entity &) {}
#pragma once
#include "common.h"
class World;
class Entity;
/**
* A part of an entity. It implements all of the behavior of the entity.
*/
class Component {
public:
/**
* We need a virtual destructor.
*/
virtual ~Component() = default;
/**
* Called when this component is added to an entity.
*/
virtual void added(Entity &to);
/**
* Update the object for each frame. Returns 'false' if the object wishes to
* be removed.
*/
virtual bool tick(sf::Time time, Entity &entity, World &world);
/**
* Render the object.
*/
virtual void render(sf::RenderWindow &window, Entity &entity);
};
#include "enemy.h"
#include "visual.h"
#include "behavior.h"
#include "random.h"
static shared_ptr<Entity> create_bullet(Entity &from) {
shared_ptr<Entity> e = std::make_shared<Entity>(from.center);
e->type = Tag::enemy;
e->add(std::make_shared<Particles>(10, 70.0f, sf::milliseconds(800), sf::Color::Yellow));
e->add(std::make_shared<Textured>("bullet.png"));
if (random_int(0, 2) == 1) {
e->add(std::make_shared<Down_Movement>(250.0f));
} else {
e->add(std::make_shared<Down_Center_Movement>(250.0f));
}
// Remove them when they are outside of the screen.
e->add(std::make_shared<Remove_Outside>(20.0f));
return e;
}
shared_ptr<Entity> create_enemy() {
shared_ptr<Entity> e = std::make_shared<Entity>(sf::Vector2f{});
e->type = Tag::enemy;
e->add(std::make_shared<Particles>(10, 80.0f, sf::milliseconds(1200), sf::Color::Green));
e->add(std::make_shared<Textured>("green.png"));
e->add(std::make_shared<Sine_Movement>(
float(random_int(0, width)),
sf::milliseconds(random_int(3000, 4000))));
e->add(std::make_shared<Spawn>(sf::milliseconds(500), &create_bullet));
return e;
}
#pragma once
#include "entity.h"
/**
* Create an enemy entity.
*/
shared_ptr<Entity> create_enemy();
#include "entity.h"
#include "component.h"
bool Entity::tick(sf::Time time, World &world) {
bool live = true;
for (auto &x : components) {
live &= x->tick(time, *this, world);
}
return live;
}
void Entity::render(sf::RenderWindow &window) {
for (auto &x : components) {
x->render(window, *this);
}
}
void Entity::add(shared_ptr<Component> component) {
component->added(*this);
components.push_back(std::move(component));
}
#pragma once
#include "common.h"
#include "tag.h"
class World;
class Component;
/**
* An entity in the game world.
*/
class Entity {
public:
/**
* Create a game object.
*/
Entity(sf::Vector2f center, float radius = 0.0f)
: center{center}, radius{radius}, type{Tag::unknown} {}
/**
* Position of the center of this object.
*/
sf::Vector2f center;
/**
* Radius of this object.
*/
float radius;
/**
* Tag that indicates what kind of entity this is.
*/
Tag type;
/**
* Update the object for each frame. Returns 'false' if the object wishes to
* be removed.
*/
bool tick(sf::Time time, World &world);
/**
* Render the object.
*/
void render(sf::RenderWindow &window);
/**
* Add a component.
*/
void add(shared_ptr<Component> c);
private:
/**
* All components of this entity.
*/
vector<shared_ptr<Component>> components;
};
File added
#include "game_state.h"
#include "menu_state.h"
#include "random.h"
#include "player.h"
#include "enemy.h"
Game_State::Game_State() {
world.add(create_player());
}
shared_ptr<State> Game_State::tick(sf::Time delta) {
// Create new enemies from time to time.
if (random_int(0, 100) < 7) {
world.add(create_enemy());
}
world.tick(delta);
// Pause?
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
return std::make_shared<Menu_State>(shared_from_this());
return nullptr;
}
void Game_State::render(sf::RenderWindow &to) {
world.render(to);
}
#pragma once
#include "state.h"
#include "world.h"
class Game_State : public State {
public:
/**
* Create it.
*/
Game_State();
/**
* Tick all game elements.
*/
shared_ptr<State> tick(sf::Time delta) override;
/**
* Draw all game elements.
*/
void render(sf::RenderWindow &to) override;
private:
/**
* The game world.
*/
World world;
};
components/green.png

1.24 KiB

#include "common.h"
#include "menu_state.h"
const size_t width = 1024;
const size_t height = 768;
int main() {
sf::RenderWindow window{sf::VideoMode{width, height}, "Demo"};
window.setKeyRepeatEnabled(false);
window.setVerticalSyncEnabled(true);
State::run(window, std::make_shared<Menu_State>(nullptr));
return 0;
}
#include "menu_state.h"
#include "game_state.h"
Menu_State::Menu_State(shared_ptr<State> resume)
: selected(0), enter_pressed(false), delay(sf::milliseconds(300)) {
font.loadFromFile("font.ttf");
if (resume) {
add("Resume", [resume]() { return resume; });
background = resume;
}
add("New game", []() { return std::make_shared<Game_State>(); });
add("Exit", []() { return std::make_shared<Exit_State>(); });
}
void Menu_State::add(const string &text, Action action) {
entries.push_back({ sf::Text{text, font, 60}, 0.0f, action });
}
void Menu_State::on_key_press(sf::Keyboard::Key key) {
switch (key) {
case sf::Keyboard::Down:
if (selected + 1 < entries.size())
selected++;
break;
case sf::Keyboard::Up:
if (selected > 0)
selected--;
break;
case sf::Keyboard::Return:
enter_pressed = true;
break;
default:
break;
}
}
shared_ptr<State> Menu_State::tick(sf::Time time) {
float diff = float(time.asMicroseconds()) / float(delay.asMicroseconds());
for (size_t i = 0; i < entries.size(); i++) {
Entry &e = entries[i];
if (i == selected) {
e.state += diff;
if (e.state > 1.0f)
e.state = 1.0f;
} else {
e.state -= diff;
if (e.state < 0.0f)
e.state = 0.0f;
}
}
if (enter_pressed)
return entries[selected].action();
else
return nullptr;
}
void Menu_State::render(sf::RenderWindow &to) {
if (background)
background->render(to);
float y{100};
auto windowSize = to.getSize();
for (auto &e : entries) {
auto bounds = e.text.getLocalBounds();
e.text.setPosition((windowSize.x - bounds.width) / 2, y);
y += bounds.height * 2.0f;
int state = static_cast<int>(255 * e.state);
e.text.setFillColor(sf::Color(state, 255, state));
to.draw(e.text);
}
}
#pragma once
#include "state.h"
#include <functional>
/**
* State responsible for showing either the start menu or the pause menu.
*/
class Menu_State : public State {
public:
/**
* Create the state. If 'resume' is set, the menu will show a "resume"
* option to return to that state.
*/
Menu_State(shared_ptr<State> resume = nullptr);
/**
* Handle key presses.
*/
void on_key_press(sf::Keyboard::Key key) override;
/**
* Tick.
*/
shared_ptr<State> tick(sf::Time time) override;
/**
* Render.
*/
void render(sf::RenderWindow &drawTo) override;
private:
/**
* What to do when an item is selected.
*/
using Action = std::function<shared_ptr<State>()>;
/**
* Menu item.
*/
struct Entry {
/**
* Text to draw.
*/
sf::Text text;
/**
* Determine the color (i.e. how selected it is). 0-1.
*/
float state;
/**
* Action to perform when selected.
*/
Action action;
};
/**
* Font to use.
*/
sf::Font font;
/**
* All menu entries.
*/
vector<Entry> entries;
/**
* Which one is currently selected?
*/
size_t selected;
/**
* Was the enter key pressed?
*/
bool enter_pressed;
/**
* Animation delay.
*/
sf::Time delay;
/**
* State to use as a background (if any).
*/
shared_ptr<State> background;
/**
* Helper to add an element.
*/
void add(const string &text, Action action);
};
#include "player.h"
#include "visual.h"
#include "behavior.h"
shared_ptr<Entity> create_player() {
shared_ptr<Entity> e = std::make_shared<Entity>(sf::Vector2f(width / 2, height * 4 / 5));
e->type = Tag::player;
// e->add(std::make_shared<Particles>(10, 70.0f, sf::milliseconds(800), sf::Color::Red));
e->add(std::make_shared<Textured>("player.png"));
e->add(std::make_shared<Player_Control>(300.0f));
e->add(std::make_shared<Shield>(Tag::enemy));
// e->add(std::make_shared<Remove_Outside>(5.0f));
return e;
}
#pragma once
#include "entity.h"
shared_ptr<Entity> create_player();
components/player.png

2.69 KiB

#include "random.h"
#include <random>
/**
* Random number generator.
*/
class Generator {
public:
Generator() : g(time(nullptr)) {}
std::mt19937 g;
};
static Generator generator;
int random_int(int min, int max) {
std::uniform_int_distribution<int> dist(min, max);
return dist(generator.g);
}
#pragma once
/**
* Get a random integer.
*/
int random_int(int min, int max);
#include "state.h"
State::State() {}
State::~State() {}
void State::on_key_press(sf::Keyboard::Key) {}
void State::on_key_release(sf::Keyboard::Key) {}
void State::run(sf::RenderWindow &window, shared_ptr<State> state) {
sf::Clock clock;
while (state) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
return;
case sf::Event::KeyPressed:
state->on_key_press(event.key.code);
break;
case sf::Event::KeyReleased:
state->on_key_release(event.key.code);
break;
default:
break;
}
}
window.clear();
if (auto new_state = state->tick(clock.restart())) {
if (std::dynamic_pointer_cast<Exit_State>(new_state)) {
return;
} else {
state = new_state;
}
continue;
}
state->render(window);
window.display();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment