Applying primitives to a layer
AndEngine's primitive types include Line
, Rectangle
, Mesh
, and Gradient
objects. In this topic, we're going to focus on the Mesh
class. Meshes are useful for creating more complex shapes in our games which can have an unlimited amount of uses. In this recipe, we're going to use Mesh
objects to build a house as seen in the the following figure:
Getting ready…
Please refer to the class named ApplyingPrimitives
in the code bundle.
How to do it…
In order to create a Mesh
object, we need to do a little bit more work than what's required for a typical Rectangle
or Line
object. Working with Mesh
objects is useful for a number of reasons. They allow us to strengthen our skills as far as the OpenGL coordinate system goes, we can create oddly-shaped primitives, and we are able to alter individual vertice positions, which can be useful for certain types of animation.
- The first step involved in creating
Mesh
objects is to create our buffer data which is used to specify the points that will make up the shape of the mesh:float baseBufferData[] = { /* First Triangle */ 0, BASE_HEIGHT, UNUSED, /* first point */ BASE_WIDTH, BASE_HEIGHT, UNUSED, /* second point */ BASE_WIDTH, 0, UNUSED, /* third point */ /* Second Triangle */ BASE_WIDTH, 0, UNUSED, /* first point */ 0, 0, UNUSED, /* second point */ 0, BASE_HEIGHT, UNUSED, /* third point */ };
- Once the buffer data is configred to our liking, we can go ahead and create the
Mesh
object.Mesh baseMesh = new Mesh((WIDTH * 0.5f) - (BASE_WIDTH * 0.5f), 0, baseBufferData, baseBufferData.length / POINTS_PER_TRIANGLE, DrawMode.TRIANGLES, mEngine.getVertexBufferObjectManager());
How it works…
Let's break down the process a little bit more in order to find out just how we ended up with a house made out of primitive Mesh
objects.
In step one, we're creating the baseMesh
object's buffer data. This buffer data is used to store points in 3D space. Every three values stored in the buffer data, separated by line-breaks, make up a single vertice in the 3D world. However, it should be understood that since we are working with a 2D game engine, the third value, which is the Z
index, is of no use to us. For that reason, we have defined the third value for each vertice as the UNUSED
constant declared within this recipe's class, which is equal to 0
. The points are represented as (x, y, z)
for each triangle, as to not get the order confused. See the following figure for a representation of the how the points defined in step one will draw a rectangle onto a mesh:
The previous figure represents the baseMesh
object's buffer data, or plotted points, as seen in the How to do it... section's first step. The black lines represent the first set of points:
0, BASE_HEIGHT, UNUSED, /* first point */ BASE_WIDTH, BASE_HEIGHT, UNUSED, /* second point */ BASE_WIDTH, 0, UNUSED, /* third point */
The second set of points in the baseMesh
object's buffer data is represented by the grey lines:
BASE_WIDTH, 0, UNUSED, /* first point */ 0, 0, UNUSED, /* second point */ 0, BASE_HEIGHT, UNUSED, /* third point */
Since BASE_HEIGHT
is equal to 200
and BASE_WIDTH
is equal to 400
, we can read that the first triangle's first point, which is (0, BASE_HEIGHT)
, is located in the upper-left corner of the rectangular shape. Moving clockwise, the second point for the first triangle is located at position (BASE_WIDTH, BASE_HEIGHT)
, which would be the upper-right corner of the rectangular shape. A triangle is obviously made up of three points, so this leaves us with one more vertice to plot. The last vertice of our first triangle is located at position (BASE_WIDTH, 0)
. As a personal challenge, use the scene graph in the previous figure to find out how the grey triangle's plotted points compare to the buffer data!
In step two, we are taking our baseMesh
object's buffer data and using it to build the Mesh
object. The Mesh
object is a subtype of the Entity
class, so once we have created the Mesh
object, we can reposition it, scale it, rotate it, and and make any other adjustments we need. The parameters, in the order they appear in the constructor are as follows; x axis position, y axis position, buffer data, vertex count, draw mode, and vertex buffer object manager. The first two and last parameters are typical for all entities, but the buffer data, vertex count and draw mode are new to us. The buffer data is the array which specifies the plotted vertices, which was covered in step one. The vertex count is simply the number of vertices that the buffer data contains. Every x, y, and z coordinate within our buffer data makes up a single vertice, which is why we are dividing the baseBufferData.length
value by three for this parameter. And finally, DrawMode
defines how the Mesh
object will interpret the buffer data, which can drastically alter the resulting shape of the mesh. The different DrawMode
types and purposes can be found within the There's more... section of this topic.
Before moving on, you may notice that the "door", or rather the blue lines that represent the door are not created in the same manner as the roof and base Mesh
objects. Instead, we've used lines rather than triangles to draw the outline of the door. Take a look at the following code, which is taken from the doorBufferData
array, defining the points in which lines connect:
0, DOOR_HEIGHT, UNUSED, /* first point */ DOOR_WIDTH, DOOR_HEIGHT, UNUSED, /* second point */ DOOR_WIDTH, 0, UNUSED, /* third point */ 0, 0, UNUSED, /* fourth point */ 0, DOOR_HEIGHT, UNUSED /* fifth point */
Once again, if we draw a scene graph and plot these points similar to the previous figure representing the baseMesh
object's points, we can actually connect the dots and the lines will result in a rectangular shape. It might seem confusing at first, especially when trying to create the shapes in our heads. The trick to getting started with drawing custom shapes from defined vertices is to keep a blank scene graph saved in a favorite document or image editing software. Create a scene graph similar to the baseMesh
object's buffer data representation figure and use it to plot points, then simply copy the points to code!
Note
It is very important to remember that the (0,0)
position on the previous scene graph figure represents the center of the Mesh
object. Since we are building the mesh vertices up and to the right, the anchor center position of the mesh will not represent the center of the manually-drawn shapes! This is very important to keep in mind when building Mesh
objects.
There's more...
Creating meshes can be a pretty daunting subject for beginners, but it's a good idea to get used to them for many reasons. One of the main reasons for AndEngine developers is that it can help us to understand how OpenGL draws shapes to a display on a lower level, which in turn allows us to grasp the higher-level game development functions more easily. The following image contains the various DrawMode
types that AndEngine has conveniently made available for us in order to create Mesh
objects in different ways:
The previous figure shows how vertices within our buffer data will be drawn to the scene by our Mesh
object depending on the DrawMode
type selected. Each p# in this figure represents a vertice (x, y, and z value)
within our buffer data array. See the following points for an explanation of the image representations of each DrawMode
type:
DrawMode.POINTS
: This selection allows us to draw single points for each vertice within the mesh's buffer data. These points will not be connected by any lines; they will simply display a dot on the mesh for each point.DrawMode.LINES
: This selection allows us to draw individual lines on the mesh. Every two vertices will be connected by a line.DrawMode.LINE_STRIP
: This selection allows us to draw points on the mesh, with each point after the first point being connected to the previous point. For example, p1 will be connected to p0, p2 will be connected to p1, and so on.DrawMode.LINE_LOOP
: This selection acts in a similar way to theDrawMode.LINE_STRIP
type, however, the first point and the final point will also be connected by a line. This allows us to create closed shapes via lines.DrawMode.TRIANGLES
:– This selection allows us to draw individual triangles on the mesh for each three vertices defined within our buffer data. We are required to keep our vertices at multiples of three for this draw mode.DrawMode.TRIANGLE_FAN
: This selection allows us to draw coned or pyramidal-shaped meshes. As we can see in the previous figure, we start by specifying a point which defines the top-most point of the cone, then continue on to specify any number of base points for the shape. This draw mode requires three or more vertices to be defined within the buffer data.DrawMode.TRIANGLE_STRIP
: This selection allows us to easily create customized polygonal meshes. Every vertice defined in the buffer data after the third vertice of the initial triangle will result in a new triangle, creating a new "strip". See the figure representation for an example. This draw mode requires three or more vertices to be defined within the buffer data.
See also
- Understanding AndEngine entities given in this chapter.