1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-01 16:32:31 +01:00

Initial game state tracking

This commit is contained in:
Daniel Evans 2013-12-26 23:18:55 +00:00
parent e04be824aa
commit aa5522497b
4 changed files with 294 additions and 27 deletions

59
tests/test_state.cpp Normal file
View File

@ -0,0 +1,59 @@
#include <boost/test/unit_test.hpp>
#include "test_globals.hpp"
#include <State.hpp>
BOOST_AUTO_TEST_SUITE(StateUnitTests)
BOOST_AUTO_TEST_CASE(state_test_generic)
{
bool entered = false;
bool exited = false;
bool ticked = false;
GenericState ls(
[&](State*) { entered = true; },
[&](State*, float) { ticked = true; },
[&](State*) { exited = true; },
[](State*, const sf::Event&){}
);
ls.enter();
BOOST_CHECK( entered );
ls.tick(1.f);
BOOST_CHECK( ticked );
ls.exit();
BOOST_CHECK( exited );
}
BOOST_AUTO_TEST_CASE(state_test_switch)
{
bool entered = false;
bool exited = false;
bool ticked = false;
GenericState ls(
[&](State*) { entered = true; },
[&](State*, float) { ticked = true; },
[&](State*) { exited = true; },
[](State*, const sf::Event&){}
);
StateManager::get().enter(&ls);
BOOST_CHECK( entered );
StateManager::get().tick(1.f);
BOOST_CHECK( ticked );
StateManager::get().exit();
BOOST_CHECK( exited );
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -20,7 +20,7 @@ public:
MenuEntry(const std::string& n) : name(n) {} MenuEntry(const std::string& n) : name(n) {}
float getHeight() { return 50.f; } float getHeight() { return 30.f; }
virtual void draw(const sf::Font& font, sf::RenderWindow& window, sf::Vector2f& basis) virtual void draw(const sf::Font& font, sf::RenderWindow& window, sf::Vector2f& basis)
{ {
@ -29,7 +29,7 @@ public:
t.setPosition(basis); t.setPosition(basis);
t.setString(name); t.setString(name);
window.draw(t); window.draw(t);
basis.y += 50.f; basis.y += getHeight();
} }
virtual void activate(sf::Vector2f click) = 0; virtual void activate(sf::Vector2f click) = 0;

109
viewer/State.hpp Normal file
View File

@ -0,0 +1,109 @@
#ifndef _GAME_STATE_HPP_
#define _GAME_STATE_HPP_
#include <functional>
#include <queue>
#include <SFML/Graphics/RenderWindow.hpp>
#include "MenuSystem.hpp"
struct State
{
// Helper for global menu behaviour
Menu* currentMenu;
State()
: currentMenu(nullptr) {}
virtual void enter() = 0;
virtual void exit() = 0;
virtual void tick(float dt) = 0;
virtual void draw(sf::RenderWindow& w)
{
if(currentMenu) {
currentMenu->draw(w);
}
}
void enterMenu(Menu* menu)
{
currentMenu = menu;
}
virtual void handleEvent(const sf::Event& e)
{
switch(e.type) {
case sf::Event::MouseButtonReleased:
if(currentMenu) {
currentMenu->click(e.mouseButton.x, e.mouseButton.y);
}
break;
default: break;
};
}
};
struct GenericState : public State
{
typedef std::function<void (State*)> StateChange;
typedef std::function<void (State*, float)> Tick;
typedef std::function<void (State*, const sf::Event&)> Event;
StateChange enter_lambda;
Tick tick_lambda;
StateChange exit_lambda;
Event event_lambda;
GenericState(StateChange start, Tick think, StateChange end, Event event)
: enter_lambda(start), tick_lambda(think),
exit_lambda(end), event_lambda(event) {}
virtual void enter() { enter_lambda(this); }
virtual void exit() { exit_lambda(this); }
virtual void tick(float dt) { tick_lambda(this, dt); }
virtual void handleEvent(const sf::Event& event) {
event_lambda(this, event);
State::handleEvent(event);
}
};
struct StateManager
{
static StateManager& get()
{
static StateManager m;
return m;
}
std::deque<State*> states;
void enter(State* state)
{
states.push_back(state);
state->enter();
}
void tick(float dt)
{
states.back()->tick(dt);
}
void draw(sf::RenderWindow& w)
{
states.back()->draw(w);
}
void exit()
{
// TODO: Resole states being leaked.
states.back()->exit();
states.pop_back();
if(states.back()) {
states.back()->enter();
}
}
};
#endif

View File

@ -15,11 +15,13 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "MenuSystem.hpp" #include "MenuSystem.hpp"
#include "State.hpp"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <getopt.h> #include <getopt.h>
#include <boost/concept_check.hpp>
constexpr int WIDTH = 800, constexpr int WIDTH = 800,
HEIGHT = 600; HEIGHT = 600;
@ -46,7 +48,7 @@ int debugMode = 0;
sf::Font font; sf::Font font;
bool showControls = true; bool showControls = false;
bool hitWorldRay(glm::vec3& hit, glm::vec3& normal, GTAObject** object = nullptr) bool hitWorldRay(glm::vec3& hit, glm::vec3& normal, GTAObject** object = nullptr)
{ {
@ -73,6 +75,12 @@ bool hitWorldRay(glm::vec3& hit, glm::vec3& normal, GTAObject** object = nullptr
return false; return false;
} }
void lockCursor(bool lock)
{
mouseGrabbed = lock;
window.setMouseCursorVisible(! lock);
}
// Commands. // Commands.
std::map<std::string, std::function<void (std::string)>> Commands = { std::map<std::string, std::function<void (std::string)>> Commands = {
{"pedestrian-vehicle", {"pedestrian-vehicle",
@ -266,12 +274,6 @@ void handleGlobalEvent(sf::Event &event)
{ {
switch (event.type) { switch (event.type) {
case sf::Event::KeyPressed: case sf::Event::KeyPressed:
switch (event.key.code) {
case sf::Keyboard::Escape:
window.close();
break;
default: break;
}
break; break;
case sf::Event::GainedFocus: case sf::Event::GainedFocus:
inFocus = true; inFocus = true;
@ -297,8 +299,7 @@ void handleInputEvent(sf::Event &event)
} }
break; break;
case sf::Keyboard::M: case sf::Keyboard::M:
mouseGrabbed = ! mouseGrabbed; lockCursor(! mouseGrabbed);
window.setMouseCursorVisible(! mouseGrabbed);
break; break;
case sf::Keyboard::P: case sf::Keyboard::P:
debugMode+=1; debugMode+=1;
@ -383,7 +384,9 @@ void handleCommandEvent(sf::Event &event)
command("object-info"); command("object-info");
break; break;
break; break;
default: break;
} }
default: break;
} }
} }
@ -631,6 +634,110 @@ void render()
} }
} }
GenericState pauseState(
[](State* self)
{
Menu *m = new Menu(font);
m->offset = sf::Vector2f(50.f, 100.f);
m->addEntry(Menu::lambda("Continue", [] { StateManager::get().exit(); }));
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
m->addEntry(Menu::lambda("Exit", [] { window.close(); }));
self->currentMenu = m;
lockCursor(false);
},
[](State* self, float dt)
{
},
[](State* self)
{
delete self->currentMenu;
},
[](State* self, const sf::Event& e)
{
switch(e.type) {
case sf::Event::KeyPressed:
switch(e.key.code) {
case sf::Keyboard::Escape:
StateManager::get().exit();
break;
default: break;
}
break;
default: break;
}
}
);
GenericState gameState(
[](State* self)
{
lockCursor(true);
// TODO: create game state object
// so we can track if we already
// Started or not.
if(! player) {
command("player");
}
},
[](State* self, float dt)
{
},
[](State* self)
{
},
[](State* self, const sf::Event& e)
{
switch(e.type) {
case sf::Event::KeyPressed:
switch(e.key.code) {
case sf::Keyboard::Escape:
StateManager::get().enter(&pauseState);
break;
default: break;
}
break;
default: break;
}
}
);
GenericState menuState(
[](State* self)
{
Menu *m = new Menu(font);
m->offset = sf::Vector2f(50.f, 100.f);
m->addEntry(Menu::lambda("Test", [] { StateManager::get().enter(&gameState); }));
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
m->addEntry(Menu::lambda("Exit", [] { window.close(); }));
self->currentMenu = m;
lockCursor(false);
},
[](State* self, float dt)
{
},
[](State* self)
{
delete self->currentMenu;
},
[](State* self, const sf::Event& e)
{
switch(e.type) {
case sf::Event::KeyPressed:
switch(e.key.code) {
case sf::Keyboard::Escape:
StateManager::get().exit();
default: break;
}
break;
default: break;
}
}
);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
if (argc < 2) { if (argc < 2) {
@ -664,7 +771,7 @@ int main(int argc, char *argv[])
sf::ContextSettings cs; sf::ContextSettings cs;
cs.depthBits = 32; cs.depthBits = 32;
window.create(sf::VideoMode(w, h), "GTA3 Viewer", sf::Style::Close, cs); window.create(sf::VideoMode(w, h), "", sf::Style::Default, cs);
window.setVerticalSyncEnabled(true); window.setVerticalSyncEnabled(true);
window.setMouseCursorVisible(false); window.setMouseCursorVisible(false);
@ -672,29 +779,20 @@ int main(int argc, char *argv[])
sf::Clock clock; sf::Clock clock;
/*Menu mainMenu(font); StateManager::get().enter(&menuState);
mainMenu.offset = sf::Vector2f(50.f, 100.f);
mainMenu.addEntry(Menu::lambda("Test", [] { std::cout << "Test" << std::endl; }));
mainMenu.addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
mainMenu.addEntry(Menu::lambda("Exit", [] { window.close(); }));*/
float accum = 0.f; float accum = 0.f;
float ts = 1.f / 60.f; float ts = 1.f / 60.f;
while (window.isOpen()) { // Loop until the window is closed or we run out of state.
while (window.isOpen() && StateManager::get().states.size()) {
sf::Event event; sf::Event event;
while (window.pollEvent(event)) { while (window.pollEvent(event)) {
handleGlobalEvent(event); handleGlobalEvent(event);
handleCommandEvent(event); handleCommandEvent(event);
handleInputEvent(event); handleInputEvent(event);
if(! mouseGrabbed) { StateManager::get().states.back()->handleEvent(event);
switch(event.type) {
case sf::Event::MouseButtonPressed:
mainMenu.click(event.mouseButton.x, event.mouseButton.y);
break;
}
}
} }
accum += clock.restart().asSeconds(); accum += clock.restart().asSeconds();
@ -705,8 +803,9 @@ int main(int argc, char *argv[])
} }
render(); render();
mainMenu.draw(window); StateManager::get().draw(window);
window.display(); window.display();
} }