Blitz3D

Blitz3D is a BASIC derivative language specifically for creating games.


 * Step 1:** Understand how 3D is different than 2D. In 2D we used the x,y coordinate plane to position shapes, images and even text exactly where we wanted it on screen. 0,0 was in the top left corner and increasing x moves to the right while increasing y moves down. To go 3D we add the z coordinate. Z represents depth or going "into" the screen. 0,0,0 is now center of the screen. Increasing x moves to the right, decreasing x moves to the left, increasing y moves down, decreasing y moves up, increasing z move into the screen and decreasing z moves out of the screen (closer to you).

Graphics3D 800,600 - This command is just like the 2D version, except it sets up the 3D space. You still need to give it the width and height of the window you want the program to run in. There are two optional parameters, depth and mode. Depth is just like the 2D version, the color depth of the screen. Blitz will pick the highest color depth you can use if you leave it blank or set it to zero. The choices for mode are 0: windowed (if possible) in debug mode, fullscreen in non-debug mode (this is the default); 1: fullscreen always; 2. windowed always; 3: windowed/scaled always.

CreateCamera - In a 3D environment, you must create a camera or you will not see anything. You can only look at your world through a camera. You are able to create several different cameras if you want to provide your player with different views. There are even ways to set up a camera to give a race car a rear view mirror. You can also set the camera to be "Stuck" to another item or entity in the world. This is how we do 1st person, the camera is a child entity to the player entity. Then when the player moves, the camera moves too. If you want your camera to be stuck to something, put that somethings name in the parenthesis. For now, we are just creating a standard camera which will be at position 0,0,0, by default.

CreateLight - Blitz will automatically give you ambient lighting, but it's a good idea to create a light and point it at what you want illuminated. CreateLight has two optional parameters, type and parent - type of light can be either 1: directional (default); 2: point; or 3: spot. Parent is the name of the entity to which the light is stuck.

CreateCube - Creates a cube at 0,0,0 that extends from -1,-1,-1 to +1,+1,+1. If you want your cube to be a different size, you create it, then scale it to the size you want. This same idea works for CreateCone, CreateSphere, CreateCylinder.

PositionEntity - Once an entitiy is created, in this case, our Cube, we can place it exactly where we want it in the x,y,z coordinate system. PositionEntity takes several parameters. First, entity - name of entity to be positioned. Second, x# - x co-ordinate that entity will be positioned at. Third, y# - y co-ordinate that entity will be positioned at. Fourth, z# - z co-ordinate that entity will be positioned at. Last and optional is global - set to true if the position should be relative to 0,0,0 rather than a parent entity's position. False by default.

TurnEntity - Once an entity is created and positioned, you can turn it on any axis or all axis. The parameters are: entity - name of entity to be rotated; pitch# - angle in degrees that entity will be pitched (x axis, will tilt forward/backward); yaw# - angle in degrees that entity will be yawed (y axis, will turn left/right); roll# - angle in degrees that entity will be rolled (z axis, will tilt left/right).

UpdateWorld and RenderWorld go together. UpdateWorld takes no parameters normally. You can add an optional parameter to affect the animation speed. RenderWorld renders the current scene to the back buffer.


 * Step 2:** Loading a Mesh, Moving and Rotating it. Start a 3D program with the command above. Set the buffer, create the camera and create the light. This time we are going to load in a 3D object that was made in another program (Blender).

LoadMesh("filename") - where filename is the full path and filename of the 3D object. Blitz can use .x, .3DS, and .B3D files for a static mesh. LoadMesh is used like LoadImage and has to be assigned a variable name first. It looks like this: house = LoadMesh("assets/buildings/house.3ds") From then on you can use this entity by referring to house.

MoveEntity - Once an entity is created and positioned, you can move it during game play by changing the x,y,z, coordinates. It looks like this: MoveEntity cube, 0, 0.5, 0 This will move the cube up along the y axis. Direction is relative to the object itself.


 * Step 3:** Control your camera. There is no new code for this since Blitz3D uses entities for everything. Write a program that allows the user to move the camera with the up and down arrows and turn the camera with the left and right arrows. Don't forget to give the camera something to look at. If you want your camera to appear as though it is being held by a walking human, write a loop to make it bob a little.


 * Step 4:** Importing animated models. So far you've learned how to create primitive shapes, import static models and control the camera, now it's time to get a look at importing animated models. Blitz3D can import animated models in the following formats: DirectX (X), 3D Studio Max (3DS) and the MD2 used by the Quake 2 engine. You can find many free models online, just be sure to carefully read the copyright information, not all of them are free to use in your project.

LoadMD2("Md2_filename") - where MD2_filename is the full path and filename of the MD2 animated object. Note that in MD2, object and skin are separate and must be loaded separately. This command will only work with MD2. Always assign to a handle or variable name.

LoadAnimMesh("filename") - where filename is the full path and filename of the X, 3DS or B3D animated model. Always assign to a handle or variable name.

AnimateMD2(handle, [mode], [speed#], [first frame], [last frame], [transition#]) - where handle is the handle assigned to the previously loaded MD2 animation. Mode can be 0 for stop, 1 for loop (default), 2 for ping-pong animation and 3 for one-shot animation. Speed defaults to 1, you can make it faster or slower with a multiplier. First frame and last frame refer to keyframes from the modelling program, the defaults are first and last, but you can have a model that is programmed to perform several actions and if you know the starting and ending keyframes for the action you want, you can code them in. Transition refers to smoothness. Remember in Alice when you could set the transition to abrupt? It's like that. The default is 1 which is very smooth, 0 is abrupt.

Animate(handle, [mode], [speed#], [sequence], [transition#]) - where handle is the handle assigned to the previously loaded animation. Mode and speed are the same as above. Sequence refers to animation sequences. Animations load initially with one sequence, perhaps walk, but you can add more sequences with LoadAnimSeq or AddAnimSeq. These sequences are numbered 0,1,2, etc. and can be referred to here by that number. Transition is the same as above.


 * Step 5:** Creating and using a heightmap. Without a heightmap, the ground in your game will be perfectly flat. If your game is set in the endless corn fields of Kansas or a desert, that may be appropriate. Most of us want a little variety in our terrain, however. The way to get that variety is to use a heightmap. Heightmaps are grayscale images (256 shades of gray) where pure white represents the highest points and pure black represents the lowest points.

Using your favorite image editor (Fireworks and PhotoShop Elements are installed) set the mode to grayscale and create a new image that is 256x256 pixels at a resolution of 72 dpi. To practice, just fill the square with a gradient in a pattern you like, a radial gradient will create a mountain (if the center of the circle is white) or a well (if the center of the circle is black). Save it as a .bmp or .jpg file.

Before applying the heightmap to your 3D world, you will want to have a texture to apply to it. In your favorite image editor, create another file that is 256x256 pixels at a resolution of 72 dpi. Play around with colors, textures, etc. until you have an image you like. Save it as a ,jpg or .bmp file.

To apply the heightmap and texture to your world. Create a basic world with a camera and a light. Position the camera a little up on the y axis. terrain=LoadTerrain("filename.bmp") This is where you load the heightmap and give it an entity name. I gave mine the name terrain. ScaleEntity terrain, 5, 100, 5 This takes the 256x256 image and stretches it out to cover the world. You can stretch it on all axis. Remember it goes x, y, z. Play around with these numbers until you have something you like. I stretched out the y axis more than the x and z so that my mountains still look like mountains. PositionEntity terrain, -500, 0, -500 This places the terrain where we want. I set it at 0 for y and -500 for x and z. tex=LoadTexture ("filename.jpg") This creates the texture that we will apply. ScaleTexture tex, 50, 50 Since we scaled our terrain, we should also scale our texture. Remember that the texture is two dimensional and does not have a z coordinate. Here, I scaled it by 50 in both x and y. EntityTexture terrain, tex This command applies the texture called tex to the terrain called terrain


 * Step 6:** Creating a skybox. Simple shapes are important to your game. In Blitz3D you can create a cube and move all the action inside the cube. Like a soundstage in the movies, you can trick the eye by painting a panoramic scene on the inside of the box. As far as the player character is concerned, there is a horizon, a sky above him and the ground below him. You've already created shapes, now lets go inside of one. Create a basic world with a camera and a light. Position the camera a little up on the y axis.

room=CreateCube Create a cube and give it an entity name, I used room. You don't have to give the cube a size, because we will do that next. FitMesh room, -250, 0, -250, 500, 500, 500 The FitMesh command takes the entity name of the shape, the next three numbers indicate the location of the mesh on the x, y and z axis. The last three numbers are the width, height and depth of the mesh that is now bonded to our shape. However, this mesh is actually on the outside of our room. FlipMesh room This command flips the mesh from the outside of the cube to the inside of the cube. This is important, because now when we apply a texture to the cube, it will go on the inside instead of the outside. tex = LoadTexture ("filename.jpg") Same LoadTexture command as before. You can use .jpg or .bmp ScaleTexture tex, 0.5, 0.5 You may find that you need to reduce the texture somewhat, this command is cutting the texture in half. EntityTexture room, tex This command applies the texture to the room. EntityFX room, 1 EntityFX is a way of applying effects to our entities. In this case, 1 means fill the area with light.

Since we can combine the heightmap and terrain with the cube, we can apply a sky texture to the cube and position the terrain above the bottom of the cube. This is called a skybox.


 * Step 7:** Let's Collide! Since you already know how to handle collisions in the 2D world, I will just tell you what's different in the 3D world. The command is Collisions and the four parameters are src_type, dest_type, method, response. Source type is what is doing the colliding, usually your player controlled character, destination type is what may be collided with, method can be 1 (sphere to sphere) or 2 (sphere to polygon) or 3 (sphere to box), response can be 1 (stop) or 2 (slide down) or 3 (slide sideways). You need to define what type your objects are before trying to collide them. The code for that is EntityType and the parameters are the entity name and type name. You need to declare types as variables and assign them integers.

To try this out, create a basic world, add a camera and light. You can then add the following code:

type_player=1 type_obstacle=2
 * Create types

sphere=CreateSphere ScaleEntity sphere, 0.5, 0.5, 0.5 PositionEntity sphere, -3, 0, 5 EntityType sphere, type_player
 * Create a sphere

cone=CreateCone Scale Entity cone, 1.5, 1.5, 1.5 PositionEntity cone, 1, 0, 5 EntityType cone, type_obstacle
 * Create a cone

Collisions type_player, type_obstacle, 2, 2

While Not KeyDown(1) x#=0 y#=0 z#=0 If KeyDown(203)=True Then x#=-0.1 If KeyDown(205)=True Then x#=0.1 If KeyDown(208)=True Then y#=-0.1 If KeyDown(200)=True Then y#=0.1 MoveEntity sphere, x#, y#, z# UpdateWorld
 * loop the game

RenderWorld Flip Wend End

Run this and you'll notice that the sphere can't really get into contact with the cone. That's because the default collision radius of the sphere is larger than the sphere is itself. You can control the collision radius of your objects. Right after setting the EntityType add a line of code to the sphere that sets the EntityRadius. EntityRadius takes two parameters, the name of the entity and the radius of the sphere. Play around with numbers in this program and see how changing this line changes the look of your collisions.


 * Step 8:** What to do after a collision? Once you've figured out collisions, you probably want something to happen or change when the collision occurs. The easiest effect is to make the collided object disappear. You need to write an if statement that checks to see if your player object has had a collision. (If CountCollisions(sphere)=True Then ...) If this is true you can simply hide the collided object with the following code (HideEntity cone).