Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

11

13.06.2013, 02:42

Dazu ist anzumerken, dass der Schlüssel nach dem Aufruf von operator[] existiert, und zwar mit dem Standardwert des Typs/der Klasse als Wert. Bei einem enum ist dieser 0 (unabhängig davon, ob dieser Wert im enum selbst existiert).
"Theory is when you know something, but it doesn’t work. Practice is when something works, but you don’t know why. Programmers combine theory and practice: Nothing works and they don’t know why." - Anon

12

02.08.2013, 12:39

Hier ist mal mein Versuch, ein andere Konzept zu kodieren, wobei ich das nicht bewerten will. Es ist plötzlich meinem Hirn entsprungen. Vielleicht habt ihr eine Meinung dazu. Ich hab also jeweils eine Funktion für Maus und Keyboard, der ich einen Formatparameter in Form von Zeichen übergebe. Ich kann z.B. alle Ereignisse der Maus mit einer einzigen Funktion nur durch die Übergabe einer 2stelligen Zeichenkette abfragen. Das ganze sieht auf den ersten Blick so aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
inp::init();

while(Input::pollEvent()) {
    if(Input::mouse("lu")) 
        //machwatt auf 'l'eft 'u'p.

    if(Input::mouse("wd")) 
        //machwatt auf 'w'heel scroll 'd'own.

    if(Input::keyboard(SDLK_e, 'u')
        //machwas, wenn Taste e losgelassen ('u'p) wird.
     
    if(Input::keyboard(SDLK_f, 'h')
        //machwas, solange f ge'h'alten wird.
        
    if(Input::keyboard())
        str += Input::key();//Frag die Taste ab.
}


Aber man muss sich ja bloß 2 Funktionen und ein paar kleine Regeln merken, oder man verwendet die Konstanten aus dem namespace fire_on. Die Events werden direkt in der Ereignisschleife abgefragt, held-Ereignisse können auch außerhalb abgefragt werden. Die Event union muss nicht mehr erzeugt werden, da die in der Klasse verwaltet wird. Bis jetzt hab ich keine logischen Fehler gefunden, aber wer weiß.

C-/C++-Quelltext

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
92
93
94
95
#ifndef INPUT_H
#define INPUT_H

#include <map>
#include <SDL.h>
#include <Windows.h>

namespace fire_on {
    extern const char up;
    extern const char down;
    extern const char held;
    extern const char* leftUp;
    extern const char* leftDown;
    extern const char* leftHeld;
    extern const char* leftMove;
    extern const char* rightUp;
    extern const char* rightDown;
    extern const char* rightHeld;
    extern const char* rightMove;
    extern const char* middleUp;
    extern const char* middleDown;
    extern const char* middleHeld;
    extern const char* middleMove;
    extern const char* wheelUp;
    extern const char* wheelDown;
    extern const char* anyMove;
    extern const char* anyUp;
    extern const char* anyDown;
    extern const char* quit;
}

class Input 
{
    public:

        static void init(bool enableKeyRepeat=false, bool useUnicode=false);
        //Ergibt solange true, bis kein Ereignis mehr in der Eventqueue übrig ist.
        static bool pollEvent();
        static SDL_Event& event() { return _event; }  
        
        //Cursorpostion.
        static int x, y;

        //Ergibt true, wenn eine oder mehrere Steuerungstasten _und_ eine weitere _Taste_ gedrückt wurde. 
        //Tastenkombinationen müssen 'geodert' werden => keyMod(KMOD_LCTRL|KMOD_LSHIFT).
        //(!)Achtung: Das hier funktioniert _nicht_ => keyMod(KMOD_CTRL), denn KMOD_CTRL verknüpft
        //die rechte und die linke Steuerungstaste definitionsgemäß.
        static bool keyMod(int mod) { return (_event.key.keysym.mod & mod) == mod; }
        //Gibt true zurück, wenn eine der beiden Steuerungstasten _und_ eine weitere _Taste_ gedrückt wird. 
        //Bsp.: ctrl+shift+p => if(anyCtrl() && anyShift() && keyboard(SDLK_p))..
        static bool anyCtrl() { return (_event.key.keysym.mod & KMOD_CTRL) != 0; }
        static bool anyShift() { return (_event.key.keysym.mod & KMOD_SHIFT) != 0; }
        static bool anyAlt() { return (_event.key.keysym.mod & KMOD_ALT) != 0; }

        //Gültige Werte für fireOn: l left, r right, m middle, w wheel, u up, d down, h held, v motion, n none.
        //fireOn: 2er-Kombination aus obigen Formaten.
        //Bsp: mouse("lu") => Rückgabe true, wenn der linke Button losgelassen wird ('l'eft 'u'p).
        static bool mouse(const char* fireOn);
        
        //Gültige Werte für fireOn: u up, d down, h held. 
        //Bsp: keyboard(SDLK_u, 'd') => Rückgabe true, beim herunterdrücken der Taste u.
        //Wenn keine bzw. die Standardparameter übergeben werden gilt:
        //Ergibt true, wenn eine beliebige Taste gedrückt wurde. Die Taste kann mit key() abgefragt werden.
        static bool keyboard(int id=0, const char fireOn='d');

        /* mouse() und keyboard() _müssen_ innerhalb der Eventschleife aufgerufen werden, wenn ein up- oder down-Ereignis
         * abgefragt werden soll; sie _können_ innerhalb oder außerhalb der Eventschleife aufgerufen werden,
         * falls eine held-Ereignis abgefragt werden soll. */
        
        //Die zuletzt gedrückte Taste.
        static wchar_t unicode() { return _unicode; }
        static int key() { return _keycode; }
        static bool isKey(int id) { return _keycode == id; }

        static void useUnicode(bool enable) { SDL_EnableUNICODE(enable); }
        static void setKeyRepeat(int delay, int interval) { SDL_EnableKeyRepeat(delay,interval); }
 
    private:

        static std::map<const char, int> _buttonEv;
        static SDL_Event _event;
        static Uint8 _mouseState;
        static Uint8* _keyState;
        static wchar_t _unicode;
        static int _keycode;
        static int _state;
        
        /* Die Zeigerposition auch dann ermitteln, wenn sich dieser außerhalb des Fensters befindet.
         * Hier nur für Windows gelöst. */

        static HWND getWindowHandle();
        static HWND _hwnd; 
        static void screenToClientPos();
};
#endif 



C-/C++-Quelltext

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include "Input.h"
#include "SDL_syswm.h"
#include <ctime>

namespace fire_on {
    const char up = 'u';
    const char down = 'd';
    const char held = 'h';
    const char* leftUp = "lu";
    const char* leftDown = "ld";
    const char* leftHeld = "lh";
    const char* leftMove = "lv";
    const char* rightUp = "ru";
    const char* rightDown = "rd";
    const char* rightHeld = "rh";
    const char* rightMove = "rv";
    const char* middleUp = "mu";
    const char* middleDown = "md";
    const char* middleHeld = "mh";
    const char* middleMove = "mv";
    const char* wheelUp = "wu";
    const char* wheelDown = "wd";
    const char* anyMove = "nv";
    const char* anyUp = "nu";
    const char* anyDown = "nd";
    const char* quit = "qu";
}

std::map<const char, int> Input::_buttonEv;
SDL_Event Input::_event;
Uint8 Input::_mouseState = 0;
Uint8* Input::_keyState = NULL;
wchar_t Input::_unicode = 0;
int Input::_keycode = 0;
int Input::x = 0, Input::y = 0;
int Input::_state = 0;
HWND Input::_hwnd;

void Input::init(bool enableKeyRepeat, bool useUnicode)
{
    _hwnd = getWindowHandle();
    _keyState = SDL_GetKeyState(NULL);

    _buttonEv['u'] = SDL_MOUSEBUTTONUP;
    _buttonEv['d'] = SDL_MOUSEBUTTONDOWN;
    _buttonEv['v'] = SDL_MOUSEMOTION;
    _buttonEv['l'] = SDL_BUTTON_LEFT;
    _buttonEv['r'] = SDL_BUTTON_RIGHT;
    _buttonEv['m'] = SDL_BUTTON_MIDDLE;
    _buttonEv['n'] = 0;//None

    SDL_EnableUNICODE(useUnicode);
    if(enableKeyRepeat)
        SDL_EnableKeyRepeat(100, 30);
    else
        SDL_EnableKeyRepeat(0, 0);
}

bool Input::pollEvent()
{
    if(SDL_PollEvent(&_event)) {
        //Es gibt ein Event.
        if(!_state || _state == 1) {//Nur einmal pro Frame abfragen..
            _mouseState = SDL_GetMouseState(&x,&y);
            screenToClientPos();
        }
        _state = 2;//(entferne 1. Bit) setze 2. Bit => Schleife durchlaufen.
        return true;
    } else {
        //Es gibt keine Events mehr. Falls ein Key oder Button gehalten wird und das Ereignis in der
        //Eventschleife abgefragt wird, ein Dummy-Event in die Ereignisschleife schieben.
        if(_state == 3) {
            _event.type = SDL_USEREVENT;
            SDL_PushEvent(&_event);
        }
        else {
            screenToClientPos();
        }
        _state = 0;
        return false;
    }
}

bool Input::mouse(const char* fireOn)
{
    SDL_MouseButtonEvent& be = _event.button;
    const char c1 = fireOn[0], c2 = fireOn[1];
    bool result = false;

    //Held..
    if(c2 == 'h') {
        result = SDL_BUTTON(_buttonEv[c1]) == _mouseState;
        if(result) { 
            _state |= 1;//setze 1. Bit => held-Event.
        }
    }
    
    //Wheel..
    else if(c1 == 'w') {
        switch(c2) {
            case 'u': result = be.button == SDL_BUTTON_WHEELUP
                            && be.type   == SDL_MOUSEBUTTONUP; break;
            case 'd': result = be.button == SDL_BUTTON_WHEELDOWN
                            && be.type   == SDL_MOUSEBUTTONUP; break;
        }
    }
    else if(c1 == 'n')
        result =  be.type == _buttonEv[c2];

    else if(c2 == 'v')
        result = SDL_BUTTON(_buttonEv[c1]) == _mouseState 
                              && be.type == _buttonEv[c2];

    else if(strncmp(fireOn, "qu", 2) == 0)
        result = _event.type == SDL_QUIT;

    else
        result = be.button == _buttonEv[c1] 
              && be.type   == _buttonEv[c2];

    return result;
}

bool Input::keyboard(int id, const char fireOn)
{
    SDL_KeyboardEvent& ke = _event.key;
    bool isEqual = id == ke.keysym.sym;
    bool isQuery = id == 0;
    bool result = false;

    if(ke.type == SDL_KEYDOWN) {
        _unicode = static_cast<wchar_t>(_event.key.keysym.unicode);
        _keycode = _event.key.keysym.sym;
    }

    switch(fireOn) {
        case 'u': result = (isEqual || isQuery) && (ke.type == SDL_KEYUP); break;
        case 'd': result = (isEqual || isQuery) && (ke.type == SDL_KEYDOWN); break;
        case 'h': 
            if(_keyState[id]) _state |= 1;//setze 1. Bit => held-Event.
            result = _keyState[id]; break;
    }
    return result;
}

HWND Input::getWindowHandle()
{
    SDL_SysWMinfo si;
    SDL_VERSION(&si.version);
    if(SDL_GetWMInfo(&si) <= 0) return NULL;
    return si.window;
}

void Input::screenToClientPos()
{
    if(!_hwnd) return; 
    POINT p;
    if(!GetCursorPos(&p)) return;
    if(!ScreenToClient(_hwnd,&p)) return;
    x = p.x;
    y = p.y;
}

Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von »dr.hallo« (14.08.2013, 20:28)


13

09.08.2013, 01:17

^^ Also nachdem ich meinen Erguss genauer betrachtet habe, gefällt mir das alles nicht so richtig. Vor allem nicht, dass ja bei jeder Abfrage ne ganze Palette von möglichen Ereignissen abgefragt wird. In dem Moment, wo sehr viele Abfragen stattfinden, finde ich das wenig akzeptabel. Die pollEvent() - Funktion ist auch irgendwie blöde. Wahrscheinlich sollte man da besser ne Zustandsspeicherung und ne update-Funktion einbauen.

Edit: Das ist aber offensichtlich Quatsch. Denn nach ein paar Tests bekomme ich auf meinem Notebook erst bei ca. 20000 wechselnden Abfragen einen merklichen Performanceeinbruch. Die pollEvent()-Funktion hab ich nun so verändert, dass der Mausstatus nicht unnütz abgefragt wird. Und, dass die Eventschleife nicht unnütz durchlaufen wird, wenn das Held-Event außen abgefragt wird.

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »dr.hallo« (10.08.2013, 11:20)


14

12.08.2013, 19:29

Hallo dr.hallo :)

Aktuell baue ich mein ganzes Framework neu, d.h. auch den Input-Bereich. Sobald ich damit durch bin (inkl. eigene Widget-Klassen - macht mir einfach nur übelst Spaß ^^ ) stell' ich den Code vllt. auf GitHub, dann könnt ihr meine neue Lösung auseinander nehmen :D

LG Glocke

15

12.08.2013, 20:23

Da bin ich gespannt. Wäre nett, wenn du das teilen würdest. :thumbup:

16

12.08.2013, 20:39

Da bin ich gespannt. Wäre nett, wenn du das teilen würdest. :thumbup:


Soviel kann ich an der Stelle schon verraten: es ist (auch dadurch, dass ich mein eigenes Widget-System darauf aufbaue) eine Mischung aus Zustandsspeicherung und Observer-Pattern. Insgesamt wird das Framework gerade ziemlich umfangreich ... (Resource Caching etc.)

LG Glocke

17

13.08.2013, 20:54

Ja genau! mit der Zeit hat sich hier bei mir auch ein kleines, großes Framework angesammelt mit allem möglichen Zeugs drin. Ich müsste das nur mal alles vernünftig sortieren :D . Ich find, man kann sich an anderen Ideen ganz gut inspirieren.

18

22.08.2013, 15:14

Da bin ich gespannt. Wäre nett, wenn du das teilen würdest. :thumbup:


Eine erste Version:https://github.com/cgloeckner/sdlApp. Bei weitem noch nicht perfekt, aber ein guter Anfang - denke ich ^^

LG Glocke

19

22.08.2013, 20:04

Danke! Ich werde mir das demnächst mal in Ruhe anschauen. :)

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

20

22.08.2013, 21:00

Vielleicht wäre ein Blick auf die neue SDL Version 2.0 anzuraten. ;)
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Werbeanzeige