13.09.2011 18:23
3D engine for beginners II [advanced]
In the previous part of this guide I've described how to create a basic 3D engine capable of creating a three-dimensional cube, however only in a static image which admittedly wasn't very impressive. That is why this time around we will expend it by adding camera movement.
Lets start by creating two keyboard events within the constructor of our box3d class:
Those listener were attached to the stage because any other object would require changes to the "focus" value which we don't need nor want to as stage is completely sufficient. Anyway, we need two functions to handle those events:
In the next step we will work on the actual key presses capture and translation into camera movement, which even though can be done this way:
OK, I admit, this might look a bit confusing at first (especially for people that are not familiar with bitwise operations or hexadecimal numbers), but in few moments everything will become clear. This code sets key variable to certain values depending on the pressed keys, so for example holding "up" and "left" keys will result with "0x000f0f" value being set to key. It is the outcome of bitwise operations done on hexadecimal numbers - by taking "0x000f00" and "0x00000f" and applying | (OR) to them we get "0x000f0f". That line symbol | represents a bitwise "or" and in some situations works a bit like addition - 100|1 will return 101 (more information can be found in ActionScript's documentation). But anyway, we don't really care about that, it is easier to think of key as a kind of light-board where 0 = light is off (a key is not pressed) and f = light is on (a key is pressed). 0x00ffff = all keys pressed, 0x00f00f0 = only up and right, 0x000000 = no keys are pressed etc.
However eventKeyDown only servers to switch the light on. For the full picture we need the opposite function:
Well, I think the worst is behind us and now we only need to convert key value into the proper camera movement. To achieve this lets had back into the render function (which we created in the previous part of this guide) and before the graphics.clear(); line add the following code:
In any case, there is still one more little thing - moving diagonally. Using two keys at once will set key to a number that the switch(key) does not handle, so to finish things off we need to add four more clauses:
And the application itself is presented here: box3d.swf
Lets start by creating two keyboard events within the constructor of our box3d class:
stage.addEventListener(KeyboardEvent.KEY_DOWN,eventKeyDown); stage.addEventListener(KeyboardEvent.KEY_UP,eventKeyUp);(Don't forget to import flash.events.KeyboardEvent!)
Those listener were attached to the stage because any other object would require changes to the "focus" value which we don't need nor want to as stage is completely sufficient. Anyway, we need two functions to handle those events:
private function eventKeyDown(e:KeyboardEvent):void { } private function eventKeyUp(e:KeyboardEvent):void { }Before we continue I would suggest checking if Flash correctly handles key presses with trace(e.keyCode); put into one of the listeners.
In the next step we will work on the actual key presses capture and translation into camera movement, which even though can be done this way:
if(e.keyCode == Keyboard.LEFT) cx -= 20; else if(e.keyCode == Keyboard.RIGHT) cx += 20;We won't bother with it as it results in a jerky and limiting animation. Instead we will implement a bit more advanced solution based on bitwise operations - but before that, we need a new variable in our class: var key:Number = 0; which we will use in the following way:
private function eventKeyDown(e:KeyboardEvent):void { switch(e.keyCode) { case Keyboard.UP: key = key | 0x00000f; break; case Keyboard.DOWN: key = key | 0x0000f0; break; case Keyboard.LEFT: key = key | 0x000f00; break; case Keyboard.RIGHT: key = key | 0x00f000; break; } }(Don't forget to import flash.ui.Keyboard!)
OK, I admit, this might look a bit confusing at first (especially for people that are not familiar with bitwise operations or hexadecimal numbers), but in few moments everything will become clear. This code sets key variable to certain values depending on the pressed keys, so for example holding "up" and "left" keys will result with "0x000f0f" value being set to key. It is the outcome of bitwise operations done on hexadecimal numbers - by taking "0x000f00" and "0x00000f" and applying | (OR) to them we get "0x000f0f". That line symbol | represents a bitwise "or" and in some situations works a bit like addition - 100|1 will return 101 (more information can be found in ActionScript's documentation). But anyway, we don't really care about that, it is easier to think of key as a kind of light-board where 0 = light is off (a key is not pressed) and f = light is on (a key is pressed). 0x00ffff = all keys pressed, 0x00f00f0 = only up and right, 0x000000 = no keys are pressed etc.
However eventKeyDown only servers to switch the light on. For the full picture we need the opposite function:
private function eventKeyUp(e:KeyboardEvent):void { switch(e.keyCode) { case Keyboard.UP: key = key ^ 0x00000f; break; case Keyboard.DOWN: key = key ^ 0x0000f0; break; case Keyboard.LEFT: key = key ^ 0x000f00; break; case Keyboard.RIGHT: key = key ^ 0x00f000; break; } }In this case the bitwise ^ (XOR) acts a little like subtraction, where "0x000f0f ^ 0x00000f" will result in "0x000f00".
Well, I think the worst is behind us and now we only need to convert key value into the proper camera movement. To achieve this lets had back into the render function (which we created in the previous part of this guide) and before the graphics.clear(); line add the following code:
switch(key) { case 0x00000f: // ^ cz += 20; break; case 0x0000f0: // v cz -= 20; break; case 0x000f00: // < cx -= 20; break; case 0x00f000: // > cx += 20; break; }Almost over. Compile the application and make sure everything is working as intended. If you had tried operating the camera straight from the eventKeyDown or eventKeyUp functions you will surely notice an improvement in animation (if not I suggest going back and comparing it to the current solution).
In any case, there is still one more little thing - moving diagonally. Using two keys at once will set key to a number that the switch(key) does not handle, so to finish things off we need to add four more clauses:
case 0x000f0f: cz += 20; cx -= 20; break; case 0x00f00f: cz += 20; cx += 20; break; case 0x000ff0: cz -= 20; cx -= 20; break; case 0x00f0f0: cz -= 20; cx += 20; break;That is it. Just in case you can download the whole class from here: box3d_2.zip
And the application itself is presented here: box3d.swf