Hey! In this tutorial, you’ll learn to make a 3D cube using sprites.

This is the final result:

## Theory

For drawing our cube, we’ll need 8 points, which are the vertices of two rectangles:

We can then join these points to draw a cube, and draw a sprite on each face.

Based on its distance from the camera’s center, we can offset the bigger rectangle to give a 3D effect, something like this:

## Code

It’s time to get to the coding, now.

### Create

I’ll create obj_block and in its Create event, I’ll add:

//macros #macro X 0 #macro Y 1 //properties height = 0.1; length = 128; width = 128; top_length = length * (1+height); top_width = width * (1+height); //sprites sprite_face = spr_rock;

The macros X and Y will be used in arrays to store x and y values. It’s not required; but it makes the code feel neater. If you don’t get it, you will when we get to the Draw event.

I’m setting the height to 0.1. This will determine how tall the block is.

Then I’m setting the length and width for the base rectangle. After that come the length and width of the bigger rectangle. Its size will be determined by the height.

Then I’m assigning the sprite to be used to a variable. Not necessary, but I prefer it this way.

### Draw

The real deal will be in the Draw event, where the 8 points will be calculated and the sprites will be drawn. So this is the code I’ll add there, with explanations inside the comments:

//Four arrays that will contain the locations of the four vertices //of the two rectangles var topLeft, topRight, bottomRight, bottomLeft; //Calculate vertices of the base rectangle, 0 topLeft[0, X] = x - length/2; topLeft[0, Y] = y - width/2; topRight[0, X] = x + length/2; topRight[0, Y] = y - width/2; bottomRight[0, X] = x + length/2; bottomRight[0, Y] = y + width/2; bottomLeft[0, X] = x - length/2; bottomLeft[0, Y] = y + width/2; //Distance to camera center, so that the bigger rectangle can be offset //for the 3D effect var cam_x = camera_get_view_x(view_camera); var cam_y = camera_get_view_y(view_camera); var cam_w = camera_get_view_width(view_camera); var cam_h = camera_get_view_height(view_camera); var camCenter; camCenter[X] = cam_x + cam_w/2; camCenter[Y] = cam_y + cam_h/2; //Calculate offset to camera center var camOffset; camOffset[X] = x - camCenter[X]; camOffset[Y] = y - camCenter[Y]; //Set center point of the bigger rectangle var topPos; topPos[X] = x + (camOffset[X] * height); topPos[Y] = y + (camOffset[Y] * height); //Calculate vertices of the bigger rectangle, 1 topLeft[1, X] = topPos[X] - top_length/2; topLeft[1, Y] = topPos[Y] - top_width/2; topRight[1, X] = topPos[X] + top_length/2; topRight[1, Y] = topPos[Y] - top_width/2; bottomRight[1, X] = topPos[X] + top_length/2; bottomRight[1, Y] = topPos[Y] + top_width/2; bottomLeft[1, X] = topPos[X] - top_length/2; bottomLeft[1, Y] = topPos[Y] + top_width/2; //Determine which faces are visible var topVisible = topLeft[1, Y] > topLeft[0, Y]; var rightVisible = topRight[1, X] < topRight[0, X]; var bottomVisible = bottomLeft[1, Y] < bottomLeft[0, Y]; var leftVisible = topLeft[1, X] > topLeft[0, X]; //Draw the base sprite draw_sprite_pos(sprite_face, 0, topLeft[0, X], topLeft[0, Y], topRight[0, X], topRight[0, Y], bottomRight[0, X], bottomRight[0, Y], bottomLeft[0, X], bottomLeft[0, Y], 1); //Draw the other four faces //Up draw_sprite_pos(sprite_face, 0, topLeft[1, X], topLeft[1, Y], topRight[1, X], topRight[1, Y], topRight[0, X], topRight[0, Y], topLeft[0, X], topLeft[0, Y], topVisible); //Right draw_sprite_pos(sprite_face, 0, topRight[0, X], topRight[0, Y], topRight[1, X], topRight[1, Y], bottomRight[1, X], bottomRight[1, Y], bottomRight[0, X], bottomRight[0, Y], rightVisible); //Down draw_sprite_pos(sprite_face, 0, bottomLeft[0, X], bottomLeft[0, Y], bottomRight[0, X], bottomRight[0, Y], bottomRight[1, X], bottomRight[1, Y], bottomLeft[1, X], bottomLeft[1, Y], bottomVisible); //Left draw_sprite_pos(sprite_face, 0, topLeft[1, X], topLeft[1, Y], topLeft[0, X], topLeft[0, Y], bottomLeft[0, X], bottomLeft[0, Y], bottomLeft[1, X], bottomLeft[1, Y], leftVisible); //Draw the bigger rectangle sprite draw_sprite_pos(sprite_face, 0, topLeft[1, X], topLeft[1, Y], topRight[1, X], topRight[1, Y], bottomRight[1, X], bottomRight[1, Y], bottomLeft[1, X], bottomLeft[1, Y], 1);

So this code will draw the sprites at the correct places. This is the final result:

You can see that the 3D effect works pretty well, but there are two problems: the depth and the side faces.

The faces on the side should look a bit darker, shouldn’t they? So to fix this, I created another sprite, which was just a darker version of the original one. Then I used that one inside the draw functions where I drew the side faces.

Looks better now:

## Depth

Now, to fix the depth, I’ll add this code in the Step event:

```
//depth
var cam_x = camera_get_view_x(view_camera);
var cam_y = camera_get_view_y(view_camera);
var cam_w = camera_get_view_width(view_camera);
var cam_h = camera_get_view_height(view_camera);
var camCenter;
camCenter[X] = cam_x + cam_w/2;
camCenter[Y] = cam_y + cam_h/2;
var depth_x, depth_y;
depth_x = abs(x - camCenter[X]);
depth_y = abs(y - camCenter[Y]);
depth = abs(depth_x + depth_y);
```

This will calculate the absolute horizontal and vertical distances to the center of the camera; then add them both to the final depth. This works perfectly:

## Conclusion

So what cool effects can you make using this technique? I can’t wait to see! Post your work on Twitter and tag me (@itsmatharoo).

You can download the project here: GMS 2 Project

**See you later, and till then, happy dev’ing!**