Hello, Sailors!
I thought it was pretty interesting how Casey tied the keyboard to mimic controller input, though I was disappointed when I was building a tetris game for my class, I decided to not do SMFL because, well that's too easy I have quite a bit of experience with high level engines... So I did the handmade hero way and followed Casey (though my assignment was 10 days late because of this type of input thing)
Casey, at least at around day 25, the input was passed through UpdateAndRender, it's very handy if you want to, every frame, check if a key is down. But I found it in my assignment when I did it that it is not good of course, if you just want to check if a key is pressed, and not trigger the same event until the key is released, then pressed again.
So a few months later, while going back to rebuilding everything from episode 1 to do a full 3D offshoot, I fixed this problem with how Löve does it's input (in a nutshell). Löve has a function you can call to see if a key is down, useful when you're in the update function and want to check every frame. It then has two separate functions KeyPressed and KeyReleased, that run every time a key is pressed or released (respectively). But instead of a function to see if a key is down, In the gameinput structure I put a 256 bool array, the position in the array being for the ascii code of the key. I then made defines so I don't have to look up
every number to a corresponding key like key_f11 or pad_0, stuff like that.
Here's some code for you guys to get an idea of what I got. (Keep in mind this is choppy to cut out the stuff that's not related to the input)
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 | struct game_input
{
float dt;
bool KeyDown[256];
};
#define KEY_PRESSED(name) void name(char Key, int Uni, game_memory *Memory)
typedef KEY_PRESSED(key_pressed);
KEY_PRESSED(KeyPressedStub)
{
}
#define KEY_RELEASED(name) void name(char Key, int Uni, game_memory *Memory)
typedef KEY_RELEASED(key_released);
KEY_RELEASED(KeyReleasedStub)
{
}
/*
Removed a bunch of key defines from here
*/
#define MOUSE_PRESSED(name) void name(char Button, int X, int y, game_memory *Memory)
typedef MOUSE_PRESSED(mouse_pressed);
MOUSE_PRESSED(MousePressedStub)
{
}
#define MOUSE_RELEASED(name) void name(char Button, int X, int y, game_memory *Memory)
typedef MOUSE_RELEASED(mouse_released);
MOUSE_RELEASED(MouseReleasedStub)
{
}
local void
ProcessInputMessages(game_input *Input, game_memory *GameMemory,
win32_platform_code *Game, win32_state *Win32State)
{
MSG Message;
while(PeekMessage(&Message, 0, 0, 0, PM_REMOVE))
{
switch(Message.message)
{
case WM_QUIT:
{
GLOBAL_RUNNING = false;
}break;
case WM_SYSKEYUP:
case WM_KEYUP:
{
// NOTE(Jesse): Keyreleased
uint32 VKCode = (uint32)Message.wParam;
bool32 AltKeyDown = (Message.lParam & (1 << 29));
char Key = (char)VKCode;
Game->KeyReleased((char)tolower(Key), VKCode, GameMemory);
Input->KeyDown[VKCode] = false;
}break;
case WM_SYSKEYDOWN:
case WM_KEYDOWN:
{
bool32 WasDown = ((Message.lParam & (1 << 30)) != 0);
bool32 AltKeyDown = (Message.lParam & (1 << 29));
uint32 VKCode = (uint32)Message.wParam;
if(!WasDown)
{
char Key = (char)VKCode;
Game->KeyPressed((char)tolower(Key), VKCode, GameMemory);
if(VKCode == VK_ESCAPE)
{
GLOBAL_RUNNING = !GLOBAL_RUNNING;
}
Input->KeyDown[VKCode] = true;
}
if(VKCode == VK_F11)
{
if(Message.hwnd)
{
ToggleFullscreen(Message.hwnd);
}
}
if(VKCode == VK_F1)
{
if(Win32State->InputRecordingIndex == 0)
{
Win32BeginRecordingInput(Win32State, 1);
}
else
{
Win32EndRecordingInput(Win32State);
Win32BeginInputPlayback(Win32State, 1);
}
}
}break;
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_XBUTTONUP:
{
int X = (int)(WORD)(Message.lParam);
int Y = (int)(Message.lParam >> 16);
char Button = 0;
switch(Message.message)
{
case WM_LBUTTONUP:
{
Button = 'l';
}break;
case WM_MBUTTONUP:
{
Button = 'm';
}break;
case WM_RBUTTONUP:
{
Button = 'r';
}break;
}
Game->MouseReleased(Button, X, Y, GameMemory);
}break;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_XBUTTONDOWN:
{
int X = (int)(WORD)(Message.lParam);
int Y = (int)(Message.lParam >> 16);
char Button = 0;
switch(Message.message)
{
case WM_LBUTTONDOWN:
{
Button = 'l';
}break;
case WM_MBUTTONDOWN:
{
Button = 'm';
}break;
case WM_RBUTTONDOWN:
{
Button = 'r';
}break;
}
Game->MousePressed(Button, X, Y, GameMemory);
}break;
default:
{
TranslateMessage(&Message);
DispatchMessageA(&Message);
}break;
}
}
}
|
It works. I succeeded in creating separate functions from which to only trigger once per key event. And also allows, every frame for the key to be checked if it's down. Though it also creates a problem...
Casey and his beautiful live looped input recording and playback only handle for his conjoined controller/keyboard input method. I however am stumped trying to find how to not only ready the one key/mouse pressed/released system for saving into file write, but also how to write it. The only thing I can think of to relieve the problem is to make 4 arrays of bools, and when a key is pressed it switches the pressed array ascii index to 1, but every frame 0 out all 4 arrays. Which sounds unfavorable.
If anyone has any ideas on how to alleviate this solution, or have a different solution entirely, I'm welcome to suggestions.