Skip to content

Instantly share code, notes, and snippets.

@Rapptz
Last active December 24, 2015 06:29
Show Gist options
  • Save Rapptz/c999ec9a6fb7475e2aaf to your computer and use it in GitHub Desktop.
Save Rapptz/c999ec9a6fb7475e2aaf to your computer and use it in GitHub Desktop.
Action WIP
#ifndef FIRE_ACTION_HPP
#define FIRE_ACTION_HPP
#include <SFML/Window/Event.hpp>
#include <memory>
#include <vector>
namespace fire {
enum class ActionType : char {
PressedOnce,
Held,
Released,
Triggered
};
class Action {
private:
bool active = false;
bool state = false;
const sf::Event::EventType* event = nullptr;
const sf::Keyboard::Key* key = nullptr;
const sf::Mouse::Button* mouse = nullptr;
ActionType type = ActionType::Triggered;
enum ChainType : char { And, Or };
struct Node {
ChainType type;
std::shared_ptr<Action> action;
};
std::vector<Node> nodes;
void update(bool value) {
switch(type) {
case ActionType::Triggered:
active = value;
break;
case ActionType::Held:
active = value && state;
break;
case ActionType::PressedOnce:
active = value && !state;
break;
case ActionType::Released:
active = !value && state;
break;
}
state = value;
}
template<typename Key>
friend class ActionMap;
public:
Action() = default;
explicit Action(sf::Event::EventType event) noexcept: event(&event) {}
explicit Action(sf::Keyboard::Key key, ActionType type = ActionType::Triggered) noexcept: key(&key), type(type) {}
explicit Action(sf::Mouse::Button mouse, ActionType type = ActionType::Triggered) noexcept: mouse(&mouse), type(type) {}
Action(Action&&) = default;
Action(const Action&) = default;
friend Action operator&(const Action& lhs, const Action& rhs) {
Action result(lhs);
result.nodes.push_back({ Action::ChainType::And, std::make_shared<Action>(rhs) });
return result;
}
friend Action operator|(const Action& lhs, const Action& rhs) {
Action result(lhs);
result.nodes.push_back({ Action::ChainType::Or, std::make_shared<Action>(rhs) });
return result;
}
bool isChained() const {
return nodes.empty();
}
explicit operator bool() const noexcept {
return active;
}
};
} // fire
#endif // FIRE_ACTION_HPP
#ifndef FIRE_ACTIONMAP_HPP
#define FIRE_ACTIONMAP_HPP
#include "Action.hpp"
#include <unordered_map>
namespace fire {
template<typename Key>
class ActionMap {
private:
std::unordered_map<Key, Action> actions;
sf::Event eventdata;
void updateAction(Action& action) noexcept {
if(action.mouse != nullptr) {
action.update(sf::Mouse::isButtonPressed((*action.mouse)));
}
if(action.key != nullptr) {
action.update(sf::Keyboard::isKeyPressed((*action.key)));
}
if(action.event != nullptr) {
action.update(eventdata.type == *action.event);
}
}
void all(Action& action) {
auto first = action.nodes.begin();
auto last = action.nodes.end();
for(; first != last; ++first) {
if(!action.active) {
break;
}
updateAction(*(first->action));
if((first->type == Action::ChainType::Or) && (first + 1) != last) {
bool temporary = first->action->active;
++first;
updateAction(*(first->action));
action.active = temporary || first->action->active;
continue;
}
action.active = first->action->active;
}
}
void any(Action& action) {
auto first = action.nodes.begin();
auto last = action.nodes.end();
for(; first != last; ++first) {
if(action.active) {
break;
}
updateAction(*(first->action));
if((first->type == Action::ChainType::And) && (first + 1) != last) {
bool temporary = first->action->active;
++first;
updateAction(*(first->action));
action.active = temporary && first->action->active;
continue;
}
action.active = first->action->active;
}
}
public:
ActionMap() = default;
ActionMap(std::initializer_list<std::pair<Key, Action>> l) noexcept: actions(l.begin(), l.end()) {}
bool isActive(Key&& key) noexcept {
return actions.count(std::forward<Key>(key)) ? actions[std::forward<Key>(key)].active : false;
}
sf::Event getEvent() const noexcept {
return eventdata;
}
template<typename Window>
void update(Window& window) noexcept {
window.pollEvent(eventdata);
for(auto&& action : actions) {
updateAction(action.second);
switch(action.second.nodes.begin()->type) {
case Action::ChainType::Or:
any(action.second);
break;
case Action::ChainType::And:
all(action.second);
break;
}
}
}
};
} // fire
#endif // FIRE_ACTIONMAP_HPP
#include <SFML/Graphics.hpp>
#include "ActionMap.hpp"
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "Cynre", sf::Style::Close);
fire::Action ctrl(sf::Keyboard::LControl, fire::ActionType::Held);
fire::Action w(sf::Keyboard::W, fire::ActionType::Held);
fire::Action k(sf::Keyboard::K, fire::ActionType::Released);
fire::Action close(sf::Event::Closed);
fire::Action binded = (ctrl & w & k) | close;
fire::ActionMap<const char*> map = {
{"close", binded}
};
while(window.isOpen()) {
map.update(window);
if(map.isActive("close"))
window.close();
window.clear();
window.display();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment