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:
parent
e04be824aa
commit
aa5522497b
59
tests/test_state.cpp
Normal file
59
tests/test_state.cpp
Normal 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()
|
@ -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
109
viewer/State.hpp
Normal 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
|
149
viewer/main.cpp
149
viewer/main.cpp
@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user