Let’s add the final piece to the puzzle: the dwarf first person camera. Irrlicht has already a built in first person camera, but I looked over the code and it would be hard to make it behave the way I want to. So we are going to write one. Actually, we are not going to write a specialized camera class like Irrlicht has for different roles; we are just going to create a normal camera and make it behave like a first person one only by handling keyboard and mouse movement. There are a few popular first person models and behaviors in games out there. I’ll pick one that I like the most. For starters, mouse look will be what I call normal: moving the mouse up (away from you) will raise your head and moving the mouse down (closer to you) will lower your head. Some people out there suffer from a very strange condition and consider this model to be “inverted”: they want to look down when you move your mouse up. This behavior is even more confusing when you play something with a game pad. What up for a mouse means can be debated if you are silly. But you can’t debate that for a thumbstick. In the future I might add the option for inverted controls to cater for all audiences. For 4.99$.
Another convention that I will be adopting: directional keys or WASD are for forward, backwards and strafing. No turning. You turn with the mouse.
Before I continue, let me explain again how the world is set up in 3D space. This passage will be doubly important to people who would like to send me some meshes. Let’s consider that you are standing somewhere in the middle of a perfectly horizontal surface. Your head points to the north. You raise your arms sideways, with your left arm pointing exactly to the west and your right to the east. Like a lot of humans before you, you consider yourself the center of the universe: the origin point (0, 0, 0) is exactly under your feet. The X axis goes along the line created by your arms, with left/west being negative and right/east being positive. To the north, the direction you are looking at in front of you we get the positive Y coordinates, and behind you we have the negative ones. The Z coordinate decreases as things get farther away from the level of the floor. You are very tall and have a height of exactly 2 meters, so the top of your head has a Z coordinate of -2 meters. If you were to go fishing, a 100 meters deep lake would have its bottom at 100 meters on the Z axis and you would look form -2 to 100 over a distance of 102. I hope I did not confuse you even more.
On the other hand, 3D modelers should be fairly familiar with this model as long as they mind the Z axis.
So the first step is to set camera coordinates. We determine the Z coordinate based on elevation and set the rest to zero for the camera position. We do the same for the target, but this time we increase the Y coordinate with some number. I put 100 and need to test if this has any effect based on FOV (field of view). Setting these coordinates should place the camera on the floor so you probably won’t even see it. We decrease both Z coordinates with the height of a dwarf and this should fix it. If it does not work we check the camera up vector, which should be (0, 0, -1).
For the first phase of movement, we add or subtract the same constant form either the X or Y axis for both camera position and target. For forward we add to Y and for backwards we subtract. And we modify X for strafing. And that it. Now we have a four direction smooth strafe.
Next we add camera look with mouse. To achieve this I’ll keep the same camera model and rely on camera rotation. Irrlicht can adjust your camera target based on camera position and camera rotation. To achieve rotation we rotate on the X and Z axis. By setting the starting X rotation to -90 degrees and the Y rotation to 0 we get the same north facing viewpoint.
Then we set the mouse cursor to center of the screen and keep this center in a variable. We create another variable for the mouse position that we update every time we get a mouse move event. We use relative position with floating point numbers. Every time the current position is different from the center, we calculate the X and Y difference, update rotations and set the current to center. Getting the X and Y is as simple as:
float y = (0.5f - cursorPos.Y) * 100
float x = (0.5f - cursorPos.X) * 100
And that’s it again! Mouse movement triggers head rotation. For the final step we must make forward/backwards movement take into account these angles. I tried a lot of complicated matrix and vector math, but in the end I solved this by the simplest formula ever. Forward:
- AdjustCamera(-sin(rotz * M_PI / 180), cos(rotz * M_PI / 180), 0);
- AdjustCamera(sin(rotz * M_PI / 180), -cos(rotz * M_PI / 180), 0);
Let’s see all of this put together in video form:
Things are not perfect yet:
- Proportions are a little of. Dwarves are too small. Trees are too big. Walls are about right.
- I’m not sure about the FOV. Need to experiment with a lot of different values.
- Pressing two movement keys at the same time composes the effect and you move faster. Need to adjust for this.
- Need to adjust for framerate. With FRAPS reducing my framerate to around 30 I ended up walking slower than usual. You should have the same movement speed with all framerates.
But still a nice result. Did you notice the dwarf? It comes with Irrlicht and I have no idea why the default animation is tee bagging. I swear I did not do this on purpose! Or did I? :P
And I can’t shake the feeling that at least one of the coordinates in my space model is inverted! GAAHHHHH!!!!