Make a 3D Cube Using Sprites

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

This is the final result:

3.gif



Theory

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

Untitled Diagram.png

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

Untitled Diagram (1).png

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

Untitled Diagram (2).png



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:

1.gif
(I made the blocks moveable)

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:

2.PNG


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:

3.gif


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!

 

 

 

 

 

 

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s