Welcome! Last 3D can be downloaded at the following link (the archive contains also a copy of the documentation):
Last 3D is a simple 3D engine made with Game Maker; it allows extending 3D Game Maker functionalities through a set of functions. With the level editor you can create maps. Then, you can load them in your game.
- map divided into squared blocks
- animated map textures
- heightmaps loading
- water plane
- billboard objects: they appear frontal to the camera (Wolfenstein 3D style)
- adhesive objects: you can attach them on the walls
- collision checking functions
- objects pointing (you can identify the object the player is looking at)
- support for persistent rooms
The sample game is distributed under the Unlicense license (public domain equivalent). It includes all Last 3D functions, and can be used as a starting point to make games. The editor can be downloaded separately under BSD license from the sources page.
Where to start
The level editor is supplied with a step by step tutorial that starts automatically every time the program is launched.
To make your game, instead, you should make a copy of “Sample Game.gmx” and edit it in Game Maker Studio.
You can link a map to each room of your game (through the l3d_set_map command). The map is loaded automatically every time you enter the room.
I hope the rest of the documentation is clear, and that the engine can be useful to you.
Textures and heights
The map (two-dimensional) is divided into squared blocks. Every block has a height (along the z axis). The editor allows you to raise the blocks and make, for example, walls, towers, stairs and other. For every block, 6 textures are saved: a texture for the ground, 4 lateral, one for the ceiling.
When a heightmap is loaded, it is blended with the map.
Level editor and objects
All the objects that will animate our 3D space must be child of obBase. The solid ones should have obBaseSolid as parent.
Although you can place objects using the Game Maker room editor, I suggest you use this one only to make the GUIs (objects with depth smaller than 6000000 will appear in 2D, overlapped on the 3D view).
To place objects in 3D space, please use the Last 3D level editor instead. When you create an object, you can choose a name. When the map will be loaded in your game, Last 3D will automatically search in the project the object that has the specified name, and will make an instance of that type. If no name is specified, the default object (obBase) will be created.
Important: textures for the objects must be placed in the “textures” folder, numbered from 1.
You can use events, variables and the various Game Maker functions. However, there are some guidelines to follow to ensure that the objects live together with the Last 3D without problems.
Instead of the Create event, you better use User Defined 15. Why? Because, when User Defined 15 is triggered, we are sure that the object is completely loaded (whereas the Create event is triggered earlier).
To make an object, instead of instance_create, you should use l3d_create(x, y, z, object), which also requires the z coordinate and performs the User Defined 15 event.
Finally: preferably don’t modify neither the objects position nor the camera in End Step, because the ordering of objects is triggered then, and we want this to be executed after that the camera and all instances were moved to their new positions.
More about objects
If you set a sprite for an object, this one will override the texture used in the level editor.
Since our objects extend obBase, we could want to modify some variables that determine for example the appearance of the object in space. Let’s look at them:
- z: it’s the z coordinate of our object (x and y are provided by Game Maker)
- oh: it’s the height of the collision box (along the z axis)
- type: identifies the type of the object: 0 horizontal, 1 vertical, 2 ceiling object
- rot: rotation in degree; if the object is billboard, this setting is not considered
- s_tag: 0 for object visible from only one side, 1 visible from both sides, 2 billboard object, 3 billboard + move slightly towards the camera (very useful to overlap graphic effects to objects)
- mult: scale factor for the texture
Finally, we can set the collision box, using the l3d_set_cbox function that we will see later.
A texture atlas is a big image containing a collection of smaller sub-textures. We can link one (and only one) atlas per map, in order to use the sub-textures in the level editor.
To use an atlas, we first need to create a text file containing information about the atlas (let’s call it atlas information file). Informations are: image size, number of frames, filenames, size and positions of the textures. In the working directory, there will be the “atlas_model.txt” file, that represents a model of information file. You can create a copy of this and replace the text with the desired values.
Warning: textures_count specifies the maximum number of textures that you can define (from 1 to textures_count – 1), but you don’t have to define them all (you can define them jagged). For every texture, you need to specify its number. Don’t use 0, because it represents the “no texture” value.
When Last 3D is active, it sets an orthogonal projection, in order that 2D objects of the room are drawn above the 3D view. This is very useful to make GUIs. The initialization function requires the height of the room area that will be projected in 2D; the width is calculated from time to time in order to maintain aspect ratio, according to room or view size (in case the views are active). Even if this seems rather complex, it’s very useful, because it allows you to change the resolution of the game in order that also the GUI is scaled. (Someone probably will remember some old 3D games in which, by changing the resolution, the GUI got smaller. This was because the size of GUI objects didn’t change.)
Last 3D functions
Initializes the Last 3D engine. It must be called only one time, when the game starts. It takes as parameter the height of the room area that will be projected in 2D.
This is a useful function that, given in input the window size, it sets all the rooms in order that they appear of the required dimensions. Please note that in Game Maker Studio you also need to call window_set_size(hres, vres) and surface_resize(application_surface, hres, vres) functions.
It enables the Last 3D for the current room. It should be called in the creation code of every room in which we want to use the engine. Every time we enter the room, the engine starts automatically.
It disables the Last 3D for the current room.
It is used to associate a map to the current room. Every time we enter the room, the map is loaded.
Collisions with the map
It allows testing the maximum height that the map assumes in all the points of the collision box of the current object, placed in position (x, y). This function is very useful, for example if we want the z of the player to change according to the terrain height (but it works also for collisions with walls). In case of collision with solid objects, the constant MAX_H is returned.
Similar to l3d_test_h: it just tests the ceiling instead of floor.
Equivalent to l3d_test_h but more efficient, at the expense of precision. This function is okay for objects that don’t follow terrain height (eg. useful to test the collision of a projectile with the map).
Equivalent to l3d_test_ceil but more efficient.
l3d_coll_line(x1, y1, z1, x2, y2, z2, solid)
Given two points, it tests if the line through (x1, y1, z1) and (x2, y2, z2) intersects the map. solid specifies whether to test collisions also with obBaseSolid objects (true or false). This function is very useful to implement the view of the enemies: if the line that connects the head of the enemy with the body of the player is not colliding with the map, it means that the enemy can see the player. The farther the extremities of the line are, the more expensive the function is.
Gets the texture number of the block of the map in the position (x, y). Eg. collision test with fire/toxic.
Computes the slope of the block of the map in the position (x, y). This can be useful to avoid that the player can climb sloped zones of the map.
Functions for the camera
l3d_set_cam(x, y, z, ang1, ang2)
Sets camera position and rotation. ang1 is the angle around z, ang2 is the pitch.
Functions about objects
l3d_create(x, y, z, object)
Similar to the instance_create Game Maker function, but it also allows specifying the z coordinate. You should always use this function instead of instance_create, because it performs the User Defined 15 event.
To know if two objects collide on x and y, we can use Game Maker functions. However we also need to use this function to know if the two objects collide also on z.
Destroys an object if too high (eg. projectiles outside the map).
l3d_set_cbox(type, width, height, oh)
It sets the collision box for the current object. type specifies the base: 0 for rectangular base, 1 for round one. width and height are the xy collision box size, oh is the height along the z axis.
l3d_pointing(object, max_distance, solid)
It allows you to find the object pointed by the camera. object states the type of object to consider (specify obBase if you want to test all types of objects). max_distance specifies the maximum distance: objects with distance greater than max_distance aren’t considered. The function makes a collision test to discard objects that are not visible (eg. beyond a wall), solid states if to test collisions also with obBaseSolid objects. Note: the function considers the objects like spheres.
l3d_vx(module, ang1, ang2)
l3d_vy(module, ang1, ang2)
l3d_vz(module, ang1, ang2)
These functions allow you to find the components of a vector, given the module and two angles. ang1 is the angle around z, ang2 is the pitch. It can be very useful if we want to compute the speed of projectiles shot in 3D space according to a certain angle.