3D_for_GML:_Overlays - hpgDesigns/hpgdesigns-dev.io GitHub Wiki
19.1 Understanding overlays
You are probably familiar with 2D games and the way things are drawn on the screen. It’s a straight-forward principle: the x and y position in the room editor is pretty much the same when running a game. When creating a 3D game, it’s not so simple. Most of the time, the x and y in the room editor are no longer projected in a simple way like in 2D games. This is because in 3D games you’re using a camera. Viewing the world through the virtual camera’s lense means you’re looking at the world from a different perspective than the room editor window. Once you’ve switched to 3D mode, almost nothing looks the way you’re used to in 2D. To allow drawing in 2D while in 3D mode, the orthographic projection exist. Imagine viewing a garden through a clear glass window. The garden is the 3D world, the glass is the 2D overlay. Any time you want to draw on the glass, you would use orthographic projection. It’s like projecting an image on the glass of the windshield of your car or the cockpit of your jet fighter airplane: a Heads-Up Display (HUD). Let’s see how overlays can be created in GM6.
19.2 Drawing what the camera sees
If you run the gm6 file that comes with this tutorial, you’ll see a world, consisting of a ground, sky and fog, viewed through a camera (that can be moved with the WASD keys) and a transparent overlay in two parts: a text part and an animated sprite part. Take a look at the gm6 file and you’ll see this is done by using three objects: obj_camera, obj_overlay and obj_world. Which scripts are used to make this thing work? Let’s see. From top to bottom. The first script is draw_camera, holding this code:
//Draw what the camera sees
//set point to look from
xf=x;
yf=y;
zf=z+64;
//set point to look to
xt=x;
yt=y+64;
zt=zf;
//look from & to
d3d_set_projection(xf, yf, zf, xt, yt, zt, 0, 0, 1);
The points that determine the 3D camera projection are set here, points to look from and to. These are drawn in every Draw event.
19.3 Drawing the overlay
The next script is draw_overlay, containing the following code:
//draw overlay
//set overlay
d3d_set_projection_ortho(0, 0, 640, 480, 0);
//draw text in overlay
draw_text(4, 4, 'SCORE: 0000 LEVEL: 00 00 PLAYER: 0000');
//draw sprite in overlay
draw_sprite_ext(spr_crosshairs, -1, 320, 240, 2, 2, 45, c_white, 0.5);
Again, in each Draw event this script is executed. It draws the overlay, first setting the overlay to fit the dimensions of the room. From now on, all drawing will be in 2D, like drawing on the glass window that looks out on the garden. The text is drawn at a location.
19.4 Drawing overlay sprites
The sprite is also drawn, using this code:
draw_sprite_ext(sprite, subimg, x, y, xscale, yscale, rot, color, alpha);
Not only can a sprite be drawn using this code, but also an animated sprite, atposition on the screen, scaled horizontally and vertically, rotated, colored and transparent. If we take a closer look at the gm6 file, we’ll see the code used to draw the sprite is:
//draw sprite in overlay
draw_sprite_ext(spr_crosshairs, -1, 320, 240, 2, 2, 45, c_white, 0.5);
This means the sprite spr_crosshairs is drawn, using sub-image (-1) which means all sub-images are drawn as an animation, at a position on the screen (320,240), scaled both horizontally and vertically (2,2), at a rotated angle in 2D (45), using a standard white color (c_white), with an alpha value (0.5) to make it transparent. The next script is draw_world in which the sky and ground are drawn to create the 3D world.
19.5 Setting depth of camera
The usual 3D initialisation is performed in the script init_camera below. But the last couple of lines are important here:
//set values
z = 0; //height of camera
friction = 0.1; //friction of camera
depth = 8192; //depth of camera
//create instances
instance_create(0, 0, obj_overlay);
instance_create(0, 0, obj_world);
First, the height of the camera is set. This determines how high the camera is above the ground. Next the friction is set to gradually stop the camera when it is moving. The next line, in which the depth of the camera is set, is crucial. Important here is that the depth of the camera is set higher than all other objects. This makes sure the scene is drawn right. In other words, it ensures the camera projection is drawn at the right depth. The last two lines of this script create the instances of the overlay and world objects.
19.6 Setting depth of overlay
Let’s take a look at the next script: init_overlay:
//ini overlay
depth=-8192;
image_speed=0.1;
Again, there’s a crucial line there in which the depth of the overlay object is set lower than all the other objects. This makes sure the overlay is drawn right. In other words, it ensures the orthographic projection is drawn at the right depth. The last line sets the image speed of the animated sprite used in the overlay. The last script mot_camera allows you to move the camera in a simple way through the 3D scene. As you can see, setting the depths of certain objects is crucial when using overlays. This is due to the fact that the drawing order is determined based on depth. When two objects have the same depth, the order of creation determines the drawing order which can give unexpected and unwanted results. This tutorial shows how to remedy this problem.