3D_for_GML:_Flat_sprite_models - hpgDesigns/hpgdesigns-dev.io GitHub Wiki
1.1 Using sprites to create models
As you probably know Game Maker is not considered a program for creation of 3D games. Basically, what GM does is create two-dimensional games using three- dimensional graphics. But you can also still use two-dimensional graphics (sprites) in three-dimensional space. You can use 3D models but you can also use 2D models. You can use them in such a way that they always face the camera, you can use them to create virtual rotation or even use animation. There are many reasons why you would use 2D models (Flat Sprite Models) even when you could use 3D ones. This tutorial consists of four parts (A to D), each with its own gm6 file. Let’s take a look at the the first part in which we will see how to draw a sprite on the floor.
1.2 drawing a sprite on the floor
In the gm6 file (part A) we have a pretty straightforward First Person Shooter with a mouselook script scr_mouselook:
//MOUSELOOK
//get display dimensions
display_w=display_get_width();
display_h=display_get_height();
//calculate motion
change_x=(display_mouse_get_x()-display_w/2)/16;
change_y=(display_mouse_get_y()-display_h/2)/12;
//move cam
direction-=change_x
zdirection+= change_y
//set mouse back
display_mouse_set(display_w/2,display_h/2);
This means we will be able to look around in the virtual 3D space. And we will draw a ground in the script scr_draw_ground:
//draw ground
d3d_draw_floor(-8192, -8192, 0, 8192, 8192, 0,
background_get_texture(bk_ground),1024/8,1024/6);
That code will probably not raise many eyebrows. So, now that we have a ground, let’s draw a sprite on it, in the script scr_draw_arrow:
//draw arrow
d3d_set_depth(1);
draw_sprite_ext(spr_arrow, 1, x, y, 1, 1, point_direction(x,y,obj_character.x,obj_character.y), c_white, 1);
First, we set the depth to 1 (which is just above the ground which is at zero). Then we draw the sprite spr_arrow. The rotation value will be set in such a way that it always points at the Character. Of course, you can use any other value that you want. If you run the gm6 file (part A) and walk around in the virtual space, you will see that there are arrows on the ground that keep pointing at you. Okay, ready for the next step? Read on.
1.3 Making a sprite face the player
When all the enemies in your game are lying dead on the floor, the previous part (A) was useful. But what if they are still standing? Then you would need to drawsprite that is upright, facing the player. We will use an image of a ball and draw using the script draw_ball:
//draw ball
d3d_transform_set_identity();
d3d_transform_add_rotation_x(9 0);
d3d_transform_add_rotation_z(point_direction(x, y, obj_character.x, obj
_Character.y)+90);
d3d_transform_add_translation(x, y, z+32)
draw_sprite_ext(spr_ball, 1, 0, 0, 1, 1, 0, c_white, 1);
d3d_transform_set_identity();
We will have to use transformation to get the image to stay upright. This is done in the line:
d3d_transform_add_rotation_x(90);
Rotating it in this way (x axis, 90 degrees) will make it look like a traffic sign that hasn’t been knocked over yet. Next, we will have to make the traffic sign face the player at all times. Again, this is done using transformation in the line:
d3d_transform_add_rotation_z(point_direction(x, y, obj_character.x, obj_character.y)+90);
Now the traffic sign will face the player at all times (using rotation around the z axis). That’s it? Yep. If you run the gm6 (part B), you will see a ball that will always face the player. But, you might ask, what if I would want to use an animated sprite? No problem. Read on.
1.4 An animation that faces the player
You can use the exact same principle of transformation if you’re using an animated sprite as you can see if you run the gm6 file (part C). We will be using a flame sprite animation that consists of 10 subimages.
//draw flame
d3d_transform_set_identity();
d3d_transform_add_rotation_x(90);
d3d_transform_add_rotation_z(point_direction(x, y, obj_character.x, obj_character.y)+90);
d3d_transform_add_translation(x, y, z)
draw_sprite_ext(spr_flame,image_index,0,0,1,1,0,c_white,1);
d3d_transform_set_identity();
It’s the same thing (as in part B) except for the line:
draw_sprite_ext(spr_flame, image_index, 0, 0, 1, 1, 0, c_white, 1);
This time we will use ‘image_index’ so that the sprite is animated. That’s it. But what if you would want to walk around an object? Well, read on.
1.5 Using virtual rotation
Virtual rotated Flat Sprite Models are not really 3D models. They are Flat Sprite Models, so they’re 2D. The trick is to set an image for each angle. Take a look at the gm6 file (part D) and the script draw_virtual and you will see it’s basically the same code (as part C):
//don't draw if too far from camera
if distance_to_object (obj_camera)>2048 then exit;
The first part (above) is used to avoid having to draw objects that are too far to see anyway. This has nothing to do with transformation. The next part (below) of the same script has and looks like this:
//draw virtual rotating ball
d3d_transform_set_identity();
d3d_transform_add_rotation_x(90);
d3d_transform_add_rotation_z(point_direction(x, y, obj_character.x, obj_character.y)+90);
d3d_transform_add_translation(x, y, z+64)
draw_sprite_ext(spr_virtual, image_index, 0, 0, 1, 1, 0, c_white, 1);
d3d_transform_set_identity();
This time we will use almost the same code, using the image_index value but in the Step event we will run the script scr_virtual that looks like this:
//set angle and image
angle=point_direction(x, y, obj_character.x, obj_character.y)
image_index=angle*8/360;
Using the angle of the player in relation to the object, we will set the value of the image_index. Because we’re using 8 sub-images, we will use the number 8 (last line, above). If you run the gm6 (part D), you will see that the object rotates so that the player can view it from all sides. The more images you use, the more realistic the effect will be. But using more subimages will result in a larger overall file size because images take up memory.