Created
November 18, 2018 19:22
-
-
Save galek/31dbf20451d7a73452d88df6a027783a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright (C) 2009-2019, NG Games Ltd. All rights reserved. | |
* | |
* This file is part of the NGTech (http://nggames.com/). | |
* | |
* Your use and or redistribution of this software in source and / or | |
* binary form, with or without modification, is subject to: (i) your | |
* ongoing acceptance of and compliance with the terms and conditions of | |
* the NGTech License Agreement; and (ii) your inclusion of this notice | |
* in any version of this software that you use or redistribute. | |
* A copy of the NGTech License Agreement is available by contacting | |
* NG Games Ltd. at http://nggames.com/ | |
*/ | |
#pragma once | |
#include <vector> | |
#include <iostream> | |
#include <algorithm> | |
#include <memory> | |
#include <string> | |
namespace OperationOccasion | |
{ | |
template<class... Args> | |
class SubscriberBase { | |
public: | |
virtual void call(Args... args) = 0; | |
virtual bool instanceIs(void* t) = 0; | |
virtual ~SubscriberBase() { }; | |
}; | |
template<class T, class... Args> | |
class Subscriber : public SubscriberBase<Args...> { | |
private: | |
T * t; | |
void(T::*f)(Args...); | |
public: | |
Subscriber(T* _t, void(T::*_f)(Args...)) : t(_t), f(_f) { } | |
void call(Args... args) final { (t->*f)(args...); } | |
bool instanceIs(void* _t) final { return _t == (void*)t; } | |
~Subscriber() final { cout << "~Subscriber() hit! \n"; } | |
}; | |
// our Listener will derive from EventListener<Listener> | |
// which holds a list of a events it is subscribed to. | |
// As these events will have different sigs, we need a base-class. | |
// We will store pointers to this base-class. | |
class EventBase { | |
public: | |
virtual void removeSubscriber(void* t) = 0; | |
}; | |
template<class... Args> | |
class Event : public EventBase { | |
private: | |
using SmartBasePointer = unique_ptr<SubscriberBase<Args...>>; | |
std::vector<SmartBasePointer> subscribers; | |
public: | |
void fire(Args... args) { | |
for (auto& f : subscribers) | |
f->call(args...); | |
} | |
template<class T> | |
void addSubscriber(T* t, void(T::*f)(Args... args)) { | |
auto s = new Subscriber <T, Args...>(t, f); | |
subscribers.push_back(SmartBasePointer(s)); | |
} | |
//template<class T> | |
void removeSubscriber(void* t) final { | |
auto to_remove = std::remove_if( | |
subscribers.begin(), | |
subscribers.end(), | |
[t](auto& s) { return s->instanceIs(t); } | |
); | |
subscribers.erase(to_remove, subscribers.end()); | |
} | |
}; | |
// derive your listener classes: struct MyListener : EventListener<MyListener>, i.e. CRTP | |
template<class Derived> | |
class EventListener { | |
private: | |
// all events holding a subscription to us... | |
std::vector<EventBase*> events; | |
public: | |
template<class... Args> | |
void connect(Event<Args...>& ev, void(Derived::*listenerMethod)(Args... args)) { | |
ev.addSubscriber((Derived*)this, listenerMethod); | |
events.push_back(&ev); | |
} | |
// ...when the listener dies, we must notify them all to remove subscription | |
~EventListener() { | |
for (auto& e : events) | |
e->removeSubscriber((void*)this); | |
} | |
}; | |
// example usage: | |
class Publisher { | |
private: | |
std::string name; | |
public: | |
Event<float> eventFloat; | |
//Event<bool, int> eventB; | |
Publisher(std::string _name) : name(_name) { } | |
void triggerEvent() { | |
std::cout << name << "::triggerEvent() ~ Firing event with: 42\n"; | |
eventFloat.fire(42.0f); | |
} | |
}; | |
struct HumanPart | |
{ | |
virtual void Update() | |
{ | |
if (_emmitterActivated) | |
EmmiterWhenGetDammage(); | |
} | |
virtual void ActionOnGetDammage() | |
{ | |
} | |
virtual void EmmiterWhenGetDammage() | |
{} | |
bool _emmitterActivated = false; | |
}; | |
struct Head : public HumanPart, EventListener<Head> { | |
std::string name; | |
Head(std::string _name) | |
: name(_name) { | |
std::cout << name << "()\n"; | |
} | |
virtual ~Head() { | |
std::cout << "~" << name << "()\n"; | |
//emitter.eventFloat.removeSubscriber(this); | |
} | |
void gotEvent(float x) { std::cout << name << "::gotEvent hit with value: " << x << std::endl; } | |
}; | |
#if 1 | |
#else | |
struct EventGetDammage :Event | |
{ | |
virtual void Action() override {} | |
}; | |
struct Game { | |
void RunEvent(Event*) | |
{} | |
}; | |
struct GameState | |
{ | |
Game* _game = new Game(); | |
PlayerBase* player = new PlayerBase(); | |
}; | |
struct PlayerBase | |
{ | |
uint32_t health = 100; | |
uint32_t armor = 0; | |
Camera* camera = nullptr; | |
virtual void Dead() {} | |
virtual ~PlayerBase(); | |
}; | |
struct HumanPart | |
{ | |
virtual ~HumanPart() | |
{} | |
virtual void GetDammage(float _value, PlayerBase* _player) | |
{ | |
} | |
virtual void Update() | |
{ | |
if (_emmitterActivated) | |
EmmiterWhenGetDammage(); | |
} | |
virtual void ActionOnGetDammage() | |
{ | |
} | |
virtual void EmmiterWhenGetDammage() | |
{} | |
bool _emmitterActivated = false; | |
}; | |
// Голова, грудь, живот, левая рука, правая рука | |
// левавя нога, правая нога | |
struct Head :public HumanPart | |
{ | |
virtual ~Head() {} | |
virtual void GetDammage(float _value, PlayerBase* _player) override | |
{ | |
ASSERT(_player, "Invalid pointer"); | |
_player->Dead(); | |
} | |
}; | |
struct Body :public HumanPart | |
{ | |
virtual ~Body() {} | |
virtual void GetDammage(float _value, PlayerBase* _player) override | |
{ | |
ActionOnGetDammage(); | |
_emmitterActivated = true; | |
} | |
}; | |
struct PlayerHuman {}; | |
struct Player final :public PlayerBase | |
{ | |
Player(); | |
virtual ~Player(); | |
}; | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment