Toon posts:

[C++] Event gestuurde collision?

Pagina: 1
Acties:

Verwijderd

Topicstarter
Beste mede-tweakers,

Ik ben nu een tijdje bezig met C++ te ontdekken en wilde iets met event gestuurde applicaties doen. Ik heb nu een klein 'spelletje' gemaakt waar de volgende klassen hebt:

code:
1
2
3
4
5
6
7
class EventControl 

class EventHandler
   class Bord
   class Ai
      class Man
      class Vrouw


Hierboven zie je de hierachie van mijn klassen. Man erft van Ai en Ai van EventHandler. Je snapt het wel.Als ik een Event wil rondsturen dan gaat dat via EventControl->SendEvent(event). EventControl kijkt dan welke pointers van een EventHandler geregistreerd zijn (de luisteraars) en stuurt dan naar al die instanties het event door. Binnen de klassen kan ik dat event dan weer afvangen.

Het probleem nu is dat ik wil dat Man en Vrouw met elkaar botsen. Op dit moment zijn het 2x TPanel met een TImage erin die een bepaalde richting hebben zoals X+ of Y-. Ze bewegen over het grid van de klasse Bord. Ik heb het nu zover dat om een bepaalde interval een event E_PING wordt gestuurd naar elke Man en Vrouw. Deze E_PING stuurt daarna een E_POS door naar de andere Mannen en Vrouwen met als argumenten van het event de huidige positie op het grid van de instantie die het event stuurt. Door de positie nu af te vangen in andere instanties en te controleren of ze gaan botsen aan de hand van hun X en Y positie kun je ze , wanneer een collision dreigt , een andere richting geven.

Wat er nu gebeurd is dat inderdaad 1 van de 2 instanties ziet dat hij gaat botsen en zijn richting wijzigt. De andere instantie krijgt pas later dat bericht en weet dus niets van een collision op zijn pad en blijft rustig doorlopen.

De vraag komt dus een beetje neer op: Hoe krijgt ik het voor elkaar dat ze bij de controle op collision bij 1 van de 2 instanties beide de richting al wijzigen. Eigenlijk moet ik dus de pointer naar de klasse Man of Vrouw meegeven met het event E_POS zodat ik niet alleen van de ontvanger E_POS de richting kan wijzigen maar ook van de verstuurder?

Hieronder is EventHandlerFunc de functie die de events afvangt wanneer ze rondgestuurd worden. Ik weet dat sommige dingen misschien wat netter kunnen maar het gaat me even om de interactie tussen die 2 klassen. PosX en posY zijn de locaties op het grid. Event &e en zijn variablen is een struct die gestuurd wordt en zo parameters aan het event kan hangen.

C:
1
2
3
4
5
struct Event {
  int Type;
  int number,number2;
  int direction;
};


C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
                void EventHandlerFunc(const Event &e) {
                        int direction = 0;

                        this->posY = this->panel->Left / gridSize;
                        this->posX = this->panel->Top / gridSize;

                        switch (e.Type) {
                                case E_PING:

                                        if (this->dirX == '+' && this->dirY == '0') { direction = 1; }
                                        if (this->dirX == '-' && this->dirY == '0') { direction = 2; }
                                        if (this->dirY == '+' && this->dirX == '0') { direction = 3; }
                                        if (this->dirY == '-' && this->dirX == '0') { direction = 4; }

                                        ec->SendEvent(E_POS,this->posX,this->posY,direction);
                                        break;

                                case E_POS:

                                        switch (e.direction) {
                                                case 1:
                                                        if ((this->posX + 1) == e.number) {
                                                                this->dirX = '-';
                                                                this->dirY = '0';
                                                         }
                                                        break;
                                                case 2:
                                                        if ((this->posX - 1) == e.number) {
                                                                this->dirX = '+';
                                                                this->dirY = '0';
                                                        }
                                                        break;
                                                case 3:
                                                        if ((this->posY + 1) == e.number2) {
                                                                this->dirY = '-';
                                                                this->dirX = '0';
                                                         }
                                                        break;
                                                case 4:
                                                        if ((this->posY - 1) == e.number2) {
                                                                this->dirY = '+';
                                                                this->dirX = '0';
                                                       }
                                                        break;
                                        }

                                        break;
                        }


Alvast bedankt,

Michel

  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je code is C++, geen C, gebruik dus ook [code=c++]...[/code] tags :)

Ik vind je opzet een beetje onhandig, maar je zou bijvoorbeeld de verandering van positie uit kunnen stellen tot je event alle listeners langs is geweest.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Je kan natuurlijk een "change direction" event maken, en er daar dan twee van in de queue stoppen als er een botsing wordt ontdekt. Dan moet je uitkijken dat er geen 4 opkomen te staan, dus je kan ook het event bv alleen voor zichzelf, of alleen voor de ander maken. Zoiets...

(overigens zou ik je event structuur anders op zetten, in ieder geval event classes afleiden van een event base class, en dan mbv overloading die events rondsturen. Dan verwijder je dat switch statement op event-type...duidelijker, en onderhoudbaarder) Ik had dit nog liggen, kan wel wat aanpassingen gebruiken (zoals thread safety...) maar ter inspiratie:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
namespace Gaia {

    class Event {
    public:
        typedef int EventIdentifier;
        typedef Factory<Event, EventIdentifier> Builder;
    
        virtual ~Event() {std::cout << "event destroyed" << std::endl;}
        virtual void notify() = 0;

        virtual void init(std::istream& istr) = 0;
    protected:
        Event() {std::cout << "event created" << std::endl;}

        template <class T>
        void dispatch(T* e) {Handler<T>::notify(*e);}
    };


#define DEFINE_CATCHABLE virtual void notify() {dispatch(this);}
#define REGISTER_EVENT(name, id) template class Gaia::ConcreteFactory<name, Event, Event::EventIdentifier, (id)>

////////////
namespace Gaia {

    template <class T>
    class Handler {
    public:
        typedef std::list<Handler<T>*> InstanceList;

        Handler() {instances_.push_back(this);}
        ~Handler() {instances_.remove(this);}


        static void notify(const T& e) {
            for (InstanceList::iterator i = instances_.begin(); i != instances_.end(); ++i) {
                (*i)->onEvent(e);
            }
        }

        virtual void onEvent(const T& e) = 0;

    private:
        static InstanceList instances_;
    };

    template <class T>
    Handler<T>::InstanceList Handler<T>::instances_;

} /* namespace */

/////////////
    class MyEvent : public Event {
    public:
        DEFINE_CATCHABLE;

        virtual void init(std::istream& istr) {
            istr >> msg_;
        }

        virtual void display() const {
            std::cout << msg_ << std::endl;
        }

    protected:
        std::string msg_;
    };
    REGISTER_EVENT(MyEvent, 1);

    class MyDerivedEvent : public MyEvent {
    public:
        virtual void display() const {
            std::cout << "Derived display says: " << msg_ << std::endl;
        }
    };
    REGISTER_EVENT(MyDerivedEvent, 2);
///////////////
namespace Gaia {

    class MyHandler 
        : public Handler<MyEvent>
    {
        virtual void onEvent(const MyEvent& e) {
            std::cout << "EventHandler caught MyEvent!" << std::endl;
            e.display();
        }


    };

}

[ Voor 81% gewijzigd door Zoijar op 05-01-2005 14:24 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17-05 17:19
Waarom stuurt er maar 1 Man/Vrouw een E_POS bij een E_PING? Hoe komt de Man/Vrouw die de E_POS verstuurt bij de instanties van de andere Ai instanties?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

In je huidige aanpak stuurt iedereen signalen aan iedereen. De AI's verzuipen daardoor in de events. Ook reageren de AI's op elke event afzonderlijk. Hierdoor is wanneer een botsing tussen meer dan 2 individuen optreedt hun reactie anders dan "natuurlijk".

Een alternatieve aanpak is het onderbrengen van de fysica van het systeem in het bord (de wereld). Ligt ook wat dichter bij de werkelijkheid ;). AI's kunnen dan kijken hoe het er in de wereld voor staat, en sturen events naar het bord met het verzoek een mutatie uit te voeren. Het bord kijkt dan vervolgens of dit wel kan en kan ook events samenvoegen/uitmiddelen/etc en een gecombineerde verandering opleggen.
In deze aanpak doen de AI's dus verzoeken tot verandering en het bord legt veranderingen op. De AI kan hierdoor ook speelbal raken van acties van andere AI's (bv trap iemand van je vrouw af ;) ).

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17-05 17:19
bloog beschreef op woensdag 05 januari 2005 een andere aanpak:

Dat betekent echter wel dat de interface van het bord uit de klauwen kan lopen. Het houdt ook in dat als er een uitbreiding komt op de 'Ai object tree' je het bord ook moet aanpassen.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

farlane schreef op woensdag 05 januari 2005 @ 15:47:
bloog beschreef op woensdag 05 januari 2005 een andere aanpak:

Dat betekent echter wel dat de interface van het bord uit de klauwen kan lopen. Het houdt ook in dat als er een uitbreiding komt op de 'Ai object tree' je het bord ook moet aanpassen.
Bord hangt al onder EventHandler in de classtree. Maar als er geen andere events zijn dan updates van de fysieke wereld kan AI er misschien uit. Er kunnen natuurlijk ook andere events zijn waarvan het wel mogelijk is laat of niet te reageren, dan zou ik AI onder EventHandler houden.

De interface van Bord blijft klein; bord is een event-driven container van AI's. De interface van AI zal misschien groter worden omdat bord bij de eigenschappen van AI moet kunnen komen. Er valt wat voor te zeggen de fysieke status van AI helemaal uit de AI te plaatsen immers het bord heeft hier meer over te zeggen dan AI zelf. Misschien is AI zelfs als flyweight te bouwen.

Ik ben er nog niet uit, dit is een leuk onderwerp. Blijf posten !

Verwijderd

Topicstarter
Ten eerste, Ik dank u allen voor reageren :)

Ten tweede, Ik kan pas vanavond weer reageren. We hebben een autobotsing gehad op de weg en moeten nu vanalles regelen met de verzekering :(. Ik zie wel wat in de aanpak die de gebruiker Bloog voor schreef. Het bord voert de veranderingen door terwijl Ai's het aanvragen. Ik zal dus een groot gedeelte code moeten ombouwen maarach dat is nou ook weer niet zoveel werk.



Aanvulling:

Dit zijn mijn EventHandler en EventControl klassen:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class EventControl {
        private:
                EventHandler *deviceList;

        public:
                EventControl() : deviceList(0) {;}
                void RegisterHandler(EventHandler *device);
                void SendEvent(int eventType, int number = 0, int number2 = 0, int direction = 0);

};

EventControl *ec = new EventControl;

class EventHandler {
        private:
                EventHandler *nextHandler;

        public:
                EventHandler() : nextHandler(0) {
                        ec->RegisterHandler(this);
                }
                void SetNextHandler(EventHandler *next) { nextHandler = next; }
                EventHandler * GetNextHandler() { return nextHandler; }
                virtual void EventHandlerFunc(const Event &e) = 0;

};

[ Voor 53% gewijzigd door Verwijderd op 05-01-2005 16:40 ]


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17-05 17:19
Zoijar schreef op woensdag 05 januari 2005 @ 14:19:
Je kan natuurlijk een "change direction" event maken, en er daar dan twee van in de queue stoppen als er een botsing wordt ontdekt. Dan moet je uitkijken dat er geen 4 opkomen te staan, dus je kan ook het event bv alleen voor zichzelf, of alleen voor de ander maken. Zoiets...
Eventjes voor mijn beeld, als je een object meerdere events wilt laten afhandelen, is het dan de bedoeling dat je de van meerdere Handler<EventType> gaat inheriten met verschillende void onEvent(const T& e) 'callbacks' ?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

farlane schreef op woensdag 05 januari 2005 @ 17:09:
Eventjes voor mijn beeld, als je een object meerdere events wilt laten afhandelen, is het dan de bedoeling dat je de van meerdere Handler<EventType> gaat inheriten met verschillende void onEvent(const T& e) 'callbacks' ?
Ja, precies. En dan hoef je dus niet op "event type" te checken, verschillende functies krijgen verschillende events.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 17-05 17:19
Zoijar schreef op woensdag 05 januari 2005 @ 17:16:
[...]

Ja, precies. En dan hoef je dus niet op "event type" te checken, verschillende functies krijgen verschillende events.
Ok, dat elimineert dus de switch

Hoe zou je dit uitbreiden als custom informatie aan een event wilt hangen? ( Bijv state infomatie van het object dat het event maakte ). Zou je hiervoor bv in het event een state 'object' hangen en dus je event tree uitbreiden, of op een of andere manier de ontvanger duidelijk maken wie het event gooide en die een callback naar de 'originator' laten doen (Die daarvoor waarschijnlijk een of andere interface moet implementeren )?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1