2

Making a game with OpenGL/GLUT and C++.

I've heard the easiest way to manage keyboard stuff in GLUT is to use an array of bools.

So basically, here's what I have:

bool* keys = new bool[256];

...

void keyDown(unsigned char ch, int x, int y)
{
    keys[ch] = true;    
}

void keyUp(unsigned char ch, int x, int y)
{
    keys[ch] = false;
}

Then if I want to know the state of a key, I just return keys[key].

I have a similar setup for the special keys. Now, in my game when you die, it resets all the values that need to be reset and starts the game again. Until just now, that included

keys = new bool[256];

and a similar declaration for the special keys array. What makes no sense to me is that occasionally, this supposed resetting of the arrays would cause some or all of the values in keys to become two- or three-digit integers (therefore always evaluating true and making the player character move uncontrollably until one or more of the keys that were apparently down were depressed). I have a suspicion that this happened because at time of endgame one of the keys was pressed down, thereby confusing C++ when it tried to make the whole array false and found that one thing was stuck true.

Man, that's confusing. The problem has been solved by eliminating all the extra initialisations of keys, as far as I can see. But I don't get it. Anyone got any ideas on how I managed to turn some bools into ints?

PROGRAM_IX
  • 404
  • 1
  • 5
  • 21
  • 1
    I hope you thought to `delete` the old array beforehand. – R. Martinho Fernandes Jul 02 '11 at 03:32
  • ...that would be it, yes. I'm new to C++, as I said below, but especially to tight memory management like that. – PROGRAM_IX Jul 02 '11 at 04:02
  • Maybe you don't know about RAII yet? If you want don't to do manual memory management (which you shouldn't have to), you can use [RAII and smart pointers](http://stackoverflow.com/questions/395123/). There is a [smart pointer library](http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm) in Boost. – R. Martinho Fernandes Jul 02 '11 at 07:20

3 Answers3

6

This statement

keys = new bool[256];

Allocates memory. It does not initialize that memory to any particular value. To do that, you could do a memset(keys, 0, sizeof(bool) * 256) to zero.

However, you shouldn't allocate memory (which is what new does) to reinitialize an array. You should actually reinitialize it, using memset or whatever feature you used to initialize it with "false" values.

Lastly, why are you allocating this array with new to begin with? Just make it a global array: bool keys[256]. Initialize it (with memset) before you use it, and everything will be fine.

I would have suggested a std::vector<bool>, but sadly, those are not usable. You could use a std::vector<char> though, with 0 meaning false. Or a std::bitset with 256 bits. All of these contain their allocations internally (thus being safe), and have ways to clear their memory to some value.

making a game with OpenGL/GLUT and C++.

As an aside, I wouldn't advise that. GLUT isn't a tool designed for the kinds of timings that most games need. GLFW allows you to control the main loop, rather than using callbacks, so it is a more appropriate tool for a game.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • In order: - I somehow did not know that about new. - I didn't know memset existed, but I was just thinking that such a thing would be handy before I posted. >.< - Why? Because I'm too used to Java. And even there, it's probably bad practice. - I thought about something like that but decided to stick with the array because that was what was used in the example. - So I have been hearing. I'm looking into SDL at the moment, and I plan to investigate GLFW next. I've read a lot of similar opinions today. – PROGRAM_IX Jul 02 '11 at 04:07
  • @PROGRAM_IX: Java is garbage collected, C++ is not. Also in C++ there's a design pattern called RAII: Resource Allocation Is Initialisation. Technically it means that you do not allocate most class instances with "new" but just define a variable of them. Of course this means a lot of copy work. The key idea is, that you manage large bulks of data in accessor classes, that implement smart/weak pointer semantics. Instead of pointers you pass around class instances (by copied value!) of those. The Boost libraries (http://boost.org) provide Smart Pointers exactly for this. – datenwolf Jul 02 '11 at 10:33
  • This Boost library does sound pretty nice, yes. I don't think I know enough C++ to use that pattern though. – PROGRAM_IX Jul 02 '11 at 17:18
3

Because of CPU granularity you can only access things as a byte therefore bools always resolve to some kind of unsigned char type which are 1 byte in size. This way you can get from 0-255 range in values. What happens is that any non zero value is true and 0 is false. We can't implement bool as a single bit (except in C++ STL vector etc... where they are converted to bitfields) because of that granularity unless you decide to make an array and index bits in particular entries.

Jesus Ramos
  • 22,940
  • 10
  • 58
  • 88
  • That's interesting, because I was couting all the values I was checking ('w', 's', 'a', 'd') and they were always 0 or 1, except for those times. – PROGRAM_IX Jul 02 '11 at 02:40
  • well because it's the new operator memory isnt guaranteed to be zeroed out so you could be reading data off the heap from another allocation. – Jesus Ramos Jul 02 '11 at 02:42
  • Aha. I am pretty new to C++. That was probably it. Thanks. :) – PROGRAM_IX Jul 02 '11 at 04:02
0

Since the size is small, data type (bool) is small, and array size is deterministic; I would have allocated it in stack (at class level, or global level - wherever keys are declared).

class GlutWrapper
{
    bool Keys[256];
...
};

And having a function, that would ResetKeys:

void GlutWrapper::ResetKeys()
{ 
   memset(Keys, 0, sizeof(Keys));
}
Ajay
  • 18,086
  • 12
  • 59
  • 105
  • Do you know, I was just last night thinking of putting that part of the program in a class? Heh. Perhaps I will, now. – PROGRAM_IX Jul 02 '11 at 17:15