By MA SNART
This time: translation and rotation across 2d planes...
Introduction to Translation and Rotation...
First off I will need to describe what it is I'm trying to do here:
Do you remember the old arcade game 'asteroids'?. Well, guess what? That is exactly what I hope you could make after reading this article! Well, not exactly; as I'm only going to get you going with how the 'player's ship' works. You'll have to work out the rest. So the code that follows [once you type it into the IDE] will display a small ship that you can rotate and move around, just like the 'Asteroids' ship :). Please NOTE that I wrote the code without testing [so it may not work :( ] and it isn't optimized and is very un-structured...Sorry!
Because this is only [for the time being] going to be 2D, we will only need to concentrate on 2 dimentions: The X and Y [just like regular sprite graphics :)]. What this also means is that all of our rotations will be along the Z-axis: there isn't going to be a test on this, but keep this in mind for later articles. Our points are in the X and Y plains and we are rotating along the Z-axis.
First of we are defining all variables beginning A-Z as integers [helps speed things up!]. We are then going to enter into SCREEN 7 mode [moan all you want...I can't hear ya] and the extra 0,1,0 stuff tells QB that we are using the default setting [the first 0] and the active page is number 1 [this is where all the drawing will happen] and finally that the visible page is number 0 [this is what you will see on the screen]. I hope none of that was very new to you :)
The last line will put the display into a 'window', or what you can see, on screen, is what is visible within the range of numbers passed. Basically what this does is re-number the screen. If you were to PSET a pixel at 0,0 it would now show up at the center of the screen; likewise, if you PSET to -100,-100, it would show up in the upper-left corner [as if you had PSET at 0,0]. This is very handy in that it turns the screen into a cartesian graphing system: From the screen center -Y travels up, +Y down, -X travels left and +X right. This is the same type of system used in real 3D graphics [It also has the side benefit of negating the need to 'transform' World space to Camera space...more on this later].
Now enter this into QB:
These are going to be our custom variable classes...
Now we're getting to the meat of the proggy. 'lns' [LINES] stores the model of the ship, and 'player' stores our only active ENTITY...
What this will do is enter our space ship into the space provided by the 'lns' array. The ship model, of course, exists in the DATA statements [all values are in relation to Object space's reference point [or 0,0]].
First we set-up our DO/LOOP routine. Then we draw a black box to erase the screen [remember that the top-left corner of the screen is at -100,-100 and the bottom right is at 100,100]
Now comes the fun part....
co! = COS( player.ang * 3.141593 / 180)
What we do here is get the SINE and COSINE of the angle indicating the direction that the player is facing. In order to do that we must convert the integer angle measurement into radians [ you do that by multiplying by PI then dividing by 180 :) ].
Here we go again...
FOR i = 1 TO 4
rx1 = lns(i).v1.x * co! + lns(i).v1.y * si!
rx2 = lns(i).v2.x * co! + lns(i).v2.y * si!
There you have it: the rotation. Each end-point of the line [indicated by v1 and v2] is rotated around the reference point of Object space [again at 0,0]. This formula is actually the same as a z-axis rotation in a true 3D system. The formula explained:
rotated_x = ( original_x * cosine_of_angle ) + ( original_y * sine_of_angle )
rotated_y = ( original_y * cosine_of_angle ) - ( original_x * sine_of_angle )
The reasoning behind how it works isn't a subject for this article, but at this point in time, rotated_x and y are STILL in Object space. If it was transferred to World space it would always be located at the World space reference point [0,0]. So what we will do is add the VECTOR indicated by the player's location to each end-point:
fx1 = rx1 + player.loc.x
fx2 = rx2 + player.loc.x
Now at this point the line has been 'transformed' to World space, but because the Camera doesn't move and the World space has already been transformed by the WINDOW statement earlier, we can draw the line now.
Alright!...there you go...one Object transformed to World space!...
Now type in:
SELECT CASE INKEY$
IF player.ang < 0 THEN player.ang = player.ang + 360
IF player.ang > 360 THEN player.ang = player.ang - 360
CASE " "
vx! = (-.3) * si!
player.vect.x = player.vect.x + vx!
Okay that's our 'get key press' routine. The 'ESC' key will quit the demo, the left arrow will cause the angle to decrease, the right will increase the angle, and 'SPACE BAR' will make the ship thrust forward [I will explain this formula at a later time].
player.loc.x = player.loc.x + player.vect.x
IF player.loc.x > 100 then player.loc.x = player.loc.x - 201
IF player.loc.y > 100 then player.loc.y = player.loc.y - 201
This will enable the ship to have 'zero gravity' effects. If you constantly add the ENTITIES vector back into it's location, then the next bit of code will 'wrap' the ship around to the other side of the World space.
Finish the proggy with:
LOOP UNTIL quit = 1
Okay that SHOULD give you a little white ship to move around on the screen [and hopefully a bit of knowledge of translation and rotation]. Just so you can remember: To 'transform' from Object to World space, you rotate THEN transform [try switching the rotate and translate order to see what happens :) ]. This is NOT a rule written in stone however, BUT for this series of articles, keep it in mind!
Next time I'll add multiple ENTITIES to the mix and transform the World to Camera space as well...see ya!
Back to Top