Moai SDK Android Tutorial

moai sdk vs cocos2d and moai sdk windows download and install moai sdk windows
Dr.KiranArora Profile Pic
Dr.KiranArora,Canada,Teacher
Published Date:27-10-2017
Your Website URL(Optional)
Comment
Moai In this chapter, we consider another framework: Moai. Among the options for developing cross-platform mobile applications, Moai is the tool for professional game developers. It is an open source platform that provides C++ classes wrapped in Lua. These allow for development of basic 2D and 3D games for a variety of platforms: iOS, Android, Windows, Mac OS X, and Chrome. Moai is available as the free-to-use Moai SDK, which requires a “Made with Moai” splash screen or a mention in the game’s credits. Moai also offers a paid service, Moai Cloud Services, which can be integrated in apps built with or without Moai. What Is Moai? The idea of Moai stemmed from its developers, who were veterans in the gaming industry. It’s not for hobbyists wanting to make a quick app; the learning curve on Moai can be a bit steep. This little hurdle can be overcome somewhat by RapaNui, an open source layer that offers Moai via some high-level APIs (discussed in Chapter 13). A few commercially available apps have been made with Moai, and more are in the works. Nearly all of them have the A-level excellence expected from large studios, and most have a large number of downloads. At the core of Moai are the C++ libraries that help you write cross-platform applications for mobile, browsers, and the desktop. However, the Lua interface takes away the need to deal with these complex libraries. These C++ libraries wrapped in Lua also allow for access to many low-level functions. Once you have learned the basics of app development, specifically gaming, Moai is a logical choice as a professional tool set. Obtaining Moai Your first step is to create an account with Moai and then download the SDK. You can choose from the following:  SDK release version 1.3 (build 98)  SDK developer build 1.3 (build 102)  Moai source code 204 CHAPTER 10: Moai Straight out of the box, Moai has no IDE or tools like Gideros Studio does. However, it does contain the moai binary to test the Lua code with. When you unpack the ZIP file (which is the same for all platforms), the bin directory contains the libraries for all platforms, and also contains the executables (which act as the simulators to test the Moai code) for Windows and Mac OS X. The Moai SDK The first thing you need to start development with Moai is a text editor (some alternatives are discussed in Chapter 13), as there is no IDE that integrates development for Moai (however ZeroBrane fills in that gap, but is not included with Moai by default). bin directory has the executables for Windows and Mac; you can run moai in the terminal moai.exe main.lua; for Mac moai main.lua. samples folder, either via run.bat or run.sh, you should see 10-1. Figure 10-1. The Moai simulator running a sample app Hello Moai There are a couple of things we need to do to get an app in Moai running. First, we need a window to display our application, which will double as the simulator on the desktop. We create a window using the MOAISim class and call the openWindow function. The openWindow function takes three parameters: a title, a width, and a height. www.it-ebookCHAPTER 10: Moai 205 MOAISim.openWindow("Hello World Window", 320,480) Then we need to create a viewport. Since Moai uses OpenGL, to create a drawing surface, we need to set the size of the surface that we want to use for rendering. This rectangular area is called a viewport. The viewport needs to be created and set before we can start rendering. Here’s how: viewport = MOAIViewport.new() viewport:setSize(320,480) viewport:setScale(320,480) We can set the size to a specific size or simply use the entire surface by not passing any parameters to the setSize function. All rendering is based on units; these units are not necessarily the same as pixels. However, you can set these units using the setScale function. These units define the size of the pixels rendered by calculating them based on the size of the viewport and the scale setting. The size of the pixel is determined with the following two equations: pixelsizeX = viewportSizeWidth / viewportScaleX pixelsizeY = viewportSizeHeight / viewportScaleY A size of 320×480 and a scale of 320, 480 sets the pixel size to 1. Setting a scale of 10, 15 with a size of 320×480 would give a pixel size of 32×32. The same scale of 10, 15 on a surface of size 640×960 would give a pixel size of 64×64. In this case, you would see the display stretch to fill in the space. The coordinate system in Moai is organized with the origin (0,0) at the center of the screen. The y-axis is positive moving up the screen. A point with a value of 100 is higher on the screen than a point with a lower value like 20. You can invert the axis to have a negative scale by setting the scale with a negative value: viewport:setScale(320, -480) The viewport can also be changed using the setOffset function. The offset is set in a projection space that is set up to be 2×2. Setting the offset as −1, 1 moves the projection system one half to the left and one half up. This will in effect place the origin at the upper-left corner of the screen. viewport:setOffset(-1,1) Moai does not render any sprite, image, or a display object directly; rather, these are rendered onto a layer. Several layers can be stacked on top of each other. Each layer needs to be associated with a viewport. layer = MOAILayer2D.new() layer:setViewport(viewport) The layer then needs to be pushed onto a render stack before it can be rendered. MOAISim.pushRenderPass(layer) Once we’ve set up the layer for rendering, we need a display object to display on this layer. In Moai, a scene graph object is called a prop; this is a combination of the location on the surface and the webooks.info 206 CHAPTER 10: Moai representation of the object. The geometry, or the representation of the object (e.g., a triangle, quad, or spline) is held in what is called a deck. A deck can hold multiple geometry items, and can also be called a set. There are several types of decks to choose from:  MOAIGfxQuad2D: This is a single textured quad.  MOAIGfxQuadDeck2D: This is an array of textured quads (from one texture). This is similar to what we would refer to as a sprite sheet.  MOAIGfxQuadListDeck2D: This is an array of lists of textured quads (from one texture). This can be used for advanced sprite sheets.  MOAIMesh: This is a custom vertex buffer object (used for 3D).  MOAIStretchPatch2D: This is a single patch that contains stretchable rows and columns.  MOAITileDeck2D: This is used for creating a tile map and sprite sheets that are accessed via an index. The texture is divided into n×m tiles, which are all of the same size. It can be used for frame animation. MOAIGfxQuad2D class and load an image to use as the gfxQuad:setRect(-32,-32, 32, 32) Once the quad is created, we need to create a prop that will display the quad. We set the rect using the setRect function or the quad, which is similar to setting the dimensions of the quad: prop = MOAIProp2D.new() prop:setDeck(gfxQuad) prop:setLoc(32,32) Finally, we need to add this prop to the layer so that it is rendered: layer:insertProp(prop) The entire block of is shown following. When we run it, we see the image on the screen. MOAISim.openWindow ( "test", 320, 480 ) viewport = MOAIViewport.new () viewport:setSize ( 320, 480 ) viewport:setScale ( 320, 480 ) layer = MOAILayer2D.new () layer:setViewport ( viewport ) MOAISim.pushRenderPass ( layer ) webooks.infoCHAPTER 10: Moai 207 gfxQuad = MOAIGfxQuad2D.new () gfxQuad:setTexture ( "moai.png" ) gfxQuad:setRect ( -64, -64, 64, 64 ) prop = MOAIProp2D.new () prop:setDeck ( gfxQuad ) prop:setLoc ( 0, 80 ) layer:insertProp ( prop ) Compared to Corona SDK and Gideros Studio, this may seem a bit excessive for displaying an image on the screen. This is the reason why Moai is known as the tool for professional developers. It offers low-level access to a very rich API. However, that does not mean that hobbyist developers cannot use Moai. As mentioned previously, you can use the RapaNui library, which gives developers an easy- to-use high-level wrapper over the lower-level API of Moai. RapaNui wraps all of the Moai functions in easier-to-use functions and reduces the number of lines of code you need to write to get things done. Quads can also be pinned, or as it is described in Moai, the pivot point can be set; the pivot point is used as the point around which the quad is rotated, where 0, 0 is the center (by default). This is similar to the anchorPoint with Gideros or the referencePoint with Corona prop:setPiv(xCenter, yCenter) Displaying Text Text can be displayed in Moai using either TrueType or bitmap fonts. MOAITextBox is the class that allows for working with text in Moai. TrueType Fonts The easiest way to display text is using TrueType font. You can create a new font object using the MOAIFont class and pass it the characters to load from the font, the size (in points), and the dpi of the font. charcodes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.?:()&/-" font = MOAIFont.new() font:loadFromTTF( 'arial.ttf', charcodes, 12, 163 ) Then you can create a text box to display the text using MOAITextBox: textbox = MOAITextBox.new() textbox:setFont(font) textbox:setRect(-160, -80, 160, 80) textbox:setLoc(0,160) textbox:setAlignment(MOAITextBox.CENTER_JUSTIFY) layer:insertProp( textbox ) textbox:setString( "Hello World from MOAI" ) webooks.info208 CHAPTER 10: Moai Note The characters passed to the MOAIFont function are created as a texture and cached, and if new glyphs are used, they are dynamically created and also cached, thereby providing faster speeds while rendering text. Bitmap Fonts The other way to display text is by using bitmap fonts (from an image file), in which each glyph (character) is divided by a solid-color guideline, as shown in Figure 10-2. This way it becomes easy to create bitmap fonts; however, kerning is not supported by this format. Figure 10-2. A bitmap font with an outline to indicate the dimensions of the glyph To use the bitmap, you can use MOAIBitmapFontReader and load the glyphs using the loadPage function of the newly created bitmapFontReader object. charcodes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 .,:;?()&/-" font = MOAIFont.new() bitmapFR = MOAIBitmapFontReader.new() bitmapFR:loadPage( "Font.png", charcodes, 16 ) font:setReader( bitmapFR ) 2 If you use an app like Glyph Designer (from 71 ; see www.71squared.com/) to create a .fnt file containing the data related to the bitmap image file, you can use the loadFromBMFont function from the MOAIFont class, like so: charcodes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 .,:;?()&/-" font = MOAIFont.new() font:loadFromBMFont( "Font2.png" ) font:preloadGlyphs(charcodes, 64) webooks.infoCHAPTER 10: Moai 209 Text Attributes A MOAITextBox can display text, which can be altered using the setString function. Note that the text can include embedded codes that alter the color of the text, similar to HTML tags: textbox:setString("This text is in c:ff0000Redc, while this one is c:00ff00Greenc.") The tag to change the color starts with c:xxxxxx and ends with c. The xxxxxx is the color in hex (in the RRGGBBAA format). You can also use c:xxx and c:xxxx for lower-precision color codes. Text Styles You can alter the font, size, and color of text. We just discussed using c tags to change color and passing font sizes while creating a MOAIFont object. If you wanted to create text that requires different sized fonts in other frameworks, you would create multiple textbox objects with different sizes and then position them accordingly. However, with Moai, you can create styles that can be used for this, as well as for changing the font and color. These styles can be embedded in text in a manner similar to the color c tags: function newStyle(font, size) local style = MOAITextStyle.new() style:setFont(font) style:setSize(size) return style end textbox:setStyle(newStyle(font, 24)) textbox:setStyle( "foo", newStyle(font, 32)) textbox:setStyle("bar", newStyle(font, 48)) text = "This text is fooLarge/ and this is barLarger/ than the normal text." textbox:setString(text) Note The tags can be nested but must not overlap—that is, a child tag must be closed before closing a parent tag. Aligning Text After creating a MOAITextBox, you can change its properties. The text alignment can be altered using the setAlignment function. The parameters passed to setAlignment can be one of the following:  MOAITextBox.LEFT_JUSTIFY  MOAITextBox.RIGHT_JUSTIFY  MOAITextBox.CENTER_JUSTIFY w nfo 210 CHAPTER 10: Moai Animating Text The MOAITextBox has a spool function, which allows for the text to be revealed character by character. This provides for some interesting effects when displaying text. textbox:spool() Drawing Vector Primitives Moai uses the class MOAIDeck to create a canvas on which drawing operations can be performed. All drawing is performed in the local space of the deck. MOAIScriptDeck type, as follows: scriptDeck object relies on a callback function to manage the drawing of the scriptDeck, which setDrawCallback function. The callback has the parameters index, xOffset, , xScale, and yScale. The index determines the deck that needs to be redrawn, and the The MOAI drawing classes allow for drawing all of the following:  Lines  Rectangles  Filled rectangles  Circles  Filled circles  Ellipses  Filled ellipses  Polygons  Points  Drawing attributes Drawing Lines A single line can be drawn using the drawRay function, the syntax for which is MOAIDraw.drawRay(x, y, dx, dy). The x and y are the absolute coordinates, and the dx and dy are the directions of the line extending from the x and y coordinates. nfoCHAPTER 10: Moai 211 Drawing Rectangles The easiest way to draw a rectangle is to use the syntax MOAIDraw.drawRect(x1, y1, x2, y2). It takes four parameters: the x and y coordinates where the rectangle starts and the endpoints that enclose the rectangle. The code below draws a rectangle on the screen as seen in Figure 10-3. Figure 10-3. Drawing a rectangle with a stroke (border) MOAISim.openWindow ( "test", 320, 480 ) viewport = MOAIViewport.new () viewport:setSize ( 320, 480 ) viewport:setScale ( 320, -480 ) layer = MOAILayer2D.new () layer:setViewport ( viewport ) MOAISim.pushRenderPass ( layer ) function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIDraw.drawRect(-150,-150,0,-50) end scriptDeck = MOAIScriptDeck.new () scriptDeck:setRect (-64, -64, 64, 64 ) scriptDeck:setDrawCallback ( onDraw ) w212 CHAPTER 10: Moai prop = MOAIProp2D.new () prop:setDeck ( scriptDeck ) layer:insertProp ( prop ) Drawing Filled Rectangles You can use the function MOAIDraw.fillRect(x1, y1, x2, y2) to draw a filled rectangle. This function takes four parameters, similar to the drawRect function. The fill color is set using the MOAIGfxDevice.setPenColor function. The code draws a filled rectangle on the screen as seen in Figure 10-4 below. Figure 10-4. Drawing a rectangle with a fill color and no stroke MOAISim.openWindow ( "test", 320, 480 ) viewport = MOAIViewport.new () viewport:setSize ( 320, 480 ) viewport:setScale ( 320, -480 ) layer = MOAILayer2D.new () layer:setViewport ( viewport ) MOAISim.pushRenderPass ( layer ) wCHAPTER 10: Moai 213 function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIGfxDevice.setPenColor(1, 0.64, 0, 1) MOAIDraw.drawRect(-150,-150,0,-50) end scriptDeck = MOAIScriptDeck.new () scriptDeck:setRect ( -64, -64, 64, 64 ) scriptDeck:setDrawCallback ( onDraw ) prop = MOAIProp2D.new () prop:setDeck ( scriptDeck ) layer:insertProp ( prop ) Drawing Circles You can use the drawCircle function to draw circles. The syntax is MOAIDraw.drawCircle(xPos, yPos, radius, steps), where xPos and yPos are the center of the circle, radius determines the radius of the circle to be drawn, and the steps determines the granularity, or number of segments used to draw the circle. A good number for steps is 100. function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIDraw.drawCircle(0, 0, 100, 100) end Drawing Filled Circles You can use the fillCircle function to draw filled circles. The syntax is MOAIDraw.fillCircle(xPos, yPos, radius, steps), just like an unfilled circle. The pen color determines the circle fill color. function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIGfxDevice.setPenColor(1, 0.64, 0, 1) MOAIDraw.fillCircle(0, 0, 100, 100) end Drawing Ellipses To draw ellipses, you can use the function drawEllipse. The syntax is MOAIDraw.drawEllipse(xPos, yPos, xRadius, yRadius, steps), where xPos and yPos are the center, xRadius and yRadius determine the vertical and horizontal radii of the ellipse, and steps determines the granularity. A good number for steps is 100. function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIDraw.drawEllipse(0, 0, 100, 100) end w 214 CHAPTER 10: Moai Drawing Filled Ellipses Similarly, you can use the function fillEllipse to draw a filled ellipse. The syntax is the same as a regular ellipse, and the pen color determines the fill color. function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIDraw.drawEllipse(0, 0, 100, 100) end Drawing Polygons drawLines function. The MOAIDraw.drawLines(-50,50,50,50,50,-50,-50,-50,-50,50) drawPoints can be used to plot points at the given list of vertices. The following code MOAIDraw.drawPoints function, the results of which are shown in 10-5. Figure 10-5. Points set in the quadrants, demonstrating the coordinate system in Moai wCHAPTER 10: Moai 215 function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIDraw.drawRay ( 0, 0, 1, 0) MOAIDraw.drawRay ( 0, 0, 0, 1) MOAIGfxDevice.setPointSize(5) MOAIGfxDevice.setPenColor(1,0,0,1) MOAIDraw.drawPoints(-50,50,50,50,50,-50,-50,-50,-50,50) end The Drawing Attributes The canvas on which MOAIDraw draws the vector primitives is called MOAIGfxDevice. You can query it and set certain drawing attributes, such as the color, line width, and point size. This section will describe each of these. Color The MOAIGfxDevice.setPenColor function is used to set the color for drawing and filling. The syntax for setting the color is setPenColor(r, g, b, a). The values for r, g, b, and a are in the range of 0 to 1. For example, the following line sets the color to green: MOAIGfxDevice.setPenColor(0,1,0,1) Line Width The MOAIGfxDevice.setPenWidth function sets the width of any line drawn after the function call. The function is passed a width value, which determines how thick the line is usually expressed in positive integer units. function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIGfxDevice.setPenWidth(3) MOAIGfxDevice.setPenColor(1,0,0,1) MOAIDraw.drawRect(-50,-50,50,50) end Point Size The MOAIGfxDevice.setPointSize function sets the size of the points that are drawn using the drawPoints function usually expresses in positive integer units. function onDraw ( index, xOff, yOff, xFlip, yFlip ) MOAIDraw.drawRay ( 0, 0, 1, 0) MOAIDraw.drawRay ( 0, 0, 0, 1) MOAIGfxDevice.setPointSize(5) MOAIGfxDevice.setPenColor(1,0,0,1) MOAIDraw.drawPoints(-50,50,50,50,50,-50,-50,-50,-50,50) end 216 CHAPTER 10: Moai Drawing Images You’ve already learned that the way to create a display object on the screen is by creating a MOAIProp that needs to be added to a layer. Similarly, to display images, you create a MOAIProp object by creating a quad object for which you set the texture as the image you want to load. This can then be set as the deck object. gfxQuad = MOAIGfxQuad2D.new () gfxQuad:setTexture ( "moai.png" ) gfxQuad:setRect ( -64, -64, 64, 64 ) prop = MOAIProp2D.new () MOAIImage class to create a blank image that can be used as a canvas, like so: Note The image that you create must be a power of 2—that is, the width and height must be a number that is a power of 2. While creating an image dynamically, if you create an image that does not conform to the power of 2, you can use the functionpadToPow2 to pad the image to the appropriate size as required. This image object created can then be used to create the Quad2D object, which is then added to the layer. gfxQuad = MOAIGfxQuad2D.new () gfxQuad:setTexture ( image ) gfxQuad:setRect ( -64, -64, 64, 64 ) prop = MOAIProp2D.new () prop:setDeck ( gfxQuad ) layer:insertProp ( prop ) This code will display nothing, as the image created is a blank image. In the following code we create a bitmap in memory and display that to the screen. This is a good way to create dynamic images via code. local image = MOAIImage.new() image:init(25, 40) image:padToPow2() wCHAPTER 10: Moai 217 image:fillRect(-70,-70,150,150,1,1,1,1) image:fillRect( 20,20,50,50,1,0.6,0,1) gfxQuad = MOAIGfxQuad2D.new () gfxQuad:setTexture ( image ) gfxQuad:setRect ( -64,-64,64,64 ) prop = MOAIProp2D.new () prop:setDeck ( gfxQuad ) layer:insertProp ( prop ) Loading Images Images can be loaded onto a MOAIImage object using the load function, as follows: theImage = MOAIImage.new () theImage:load( "myImage2.png" ) Once you’ve loaded the image, you can perform various functions on it and apply transformations. Copying Images You can copy an image from another image using either the copyRect or copyBits function. Note that copyBits makes a copy of the source (which cannot be scaled or flipped); a rectangular region from the source can be copied onto the destination at the position passed. Here’s an example of using the copyBits function: srcImage = MOAIImage.new () srcImage:load ( "myImage2.png" ) iWd, iHt = srcImage:getSize() destImage = MOAIImage.new() destImage:init(64,64) destImage:copyBits(srcImage,0,0,0,0,iWd, iHt) If you want to be able to scale or flip the image, you can use the copyRect function, which copies a rectangle from the source image to the destination image. You can flip it by reversing the min/max parameter of the rectangle. This function will draw the source image with the dimensions specified by srcMin and srcMax onto the destination space as specified by destMin and destMax. If the destination dimensions are larger, the image is scaled up and if they are smaller, the image is scaled down. copyRect(source, srcXMin, srcYMin, srcXMax, srcYMax, destXMin, destYMin, destXMax, destYMax, filter) 218 CHAPTER 10: Moai Saving Images You might need to save an image to the device or hard disk saving it for use later. The image can be saved using the writePNG function: image = MOAIImage:new() image:init(64,64) Some drawing code here image:writePNG("myimage.png") Resizing Images resize or resizeCanvas function. The function resize copies the resizeCanvas copies the image to a canvas with getRGBA getColor32 function. These return the data in RGBA or 32-bit integer format. image:getRGBA(xPos, yPos) and image:getColor32(xPos, yPos) Similarly, the pixels can be set using the setRGBA and setColor32 functions: image:setRGBA(xPos, yPos, red, green, blue, alpha) image:setColor32(xPos, yPos, colour) Animation Basic frame-by-frame animation works by changing the image in the frame at a set frequency. This is called the fps or the frames per seconds. However, with other objects such as text, rectangles, and circles, modifying their attributes over time would provide the effect of animation. To get or set the position of the prop, you can use thegetLoc or thesetLoc function. This is the equivalent of setting an attribute for a prop. x, y = prop:getLoc() is the equivalent of x = prop:getAttr( MOAISprite2D.ATTR_X_LOC ) y = prop:getAttr( MOAISprite2D.ATTR_Y_LOC ) CHAPTER 10: Moai 219 setLoc and getLoc are basically convenience methods that are used to access attributes from props. Another convenience method that is quite useful is moveRot, which is used to rotate the object by a particular angle over a specified period of time. prop:moveRot(180, 2) This code will rotate the prop 180 degrees over a period of 2 seconds. MOAIEaseDriver can operate on attributes directly; we can simply specify the objects and attributes to operate on. MOAIEaseDriver applies simple ease curves to node attributes. Here’s an example of its use. ease = MOAIEaseDriver.new() ease:reserveLinks(3) ease:setLink(1, prop, MOAIProp2D.ATTR_X_LOC, 64) ease:setLink(2, prop, MOAIProp2D.ATTR_Y_LOC, 64) ease:setLink(3, prop, MOAIProp2D.ATTR_Z_ROT, 360) ease:start() This code snippet creates an ease driver, and then sets each channel to target a specific attribute of a single prop. This will rotate and move the prop from the top-left corner of the screen to a new location. Note When you set the parent–child relation (and also a dependency) between two props (called graph nodes), the parent node is updated first and then the child node. Tile Decks Earlier in the chapter I described the various types of decks you can use. In this section, we’ll take a closer look at MOAITileDeck2D, which helps create frame-by-frame animation. The sprite sheet for a TileDeck2D requires all of the frames to be of the same size. Then when you load the texture, you set the number of frames across and the number of frames down. Since the dimensions of all the frames are the same, when you set the size using the setSize function, the sprite sheet will be divided into an equal numbers of frames, as specified by the function. The dimensions are calculated as follows: frameWidth = spriteSheetWidth / columns frameHeight = spriteSheetHeight / rows The following example shows how you can use frame animation. The results of the code are shown in Figure 10-6.220 CHAPTER 10: Moai Animating a sprite in Moai using individual frames _max_ = 11 MOAISim.openWindow("Tiles Deck Sample",320,480) viewport = MOAIViewport.new() viewport:setSize(320,480) viewport:setScale(320,-480) viewport:setOffset(-1,1) layer = MOAILayer2D.new() layer:setViewport(viewport) MOAISim.pushRenderPass(layer) tile = MOAITileDeck2D.new() tile:setTexture("stick.png") tile:setSize(_max_,1) tile:setRect(-20,31,20,-31) prop1 = MOAIProp2D.new() prop1:setDeck(tile) layer:insertProp(prop1) curve = MOAIAnimCurve.new() curve:reserveKeys(_max_) nCHAPTER 10: Moai 221 for i=1,_max_ do curve:setKey(i, i(1/_max_), i, MOAIEaseType.FLAT) end anim = MOAIAnim:new() anim:reserveLinks(1) anim:setLink(1, curve, prop1, MOAIProp2D.ATTR_INDEX) anim:setMode(MOAITimer.LOOP) anim:start() prop1:setLoc(100,100) In this example, we first create the tiles that we can use for our animation: tile = MOAITileDeck2D.new() tile:setTexture("stick.png") tile:setSize(11,1) tile:setRect(-20,31,20,-31) Our sprite sheet has 11 frames across and 1 frame down (see Figure 10-7). The dimensions of all the frames are 40×62, which we set with setRect. Figure 10-7. The stick.png image that we shall use for the animation Setting a negative value for the rect dimensions in the setRect function flips the object on the axis with the negative value. Since Moai has an ascending y-axis, we change the scale to set the top-left corner as the origin (0,0), so our images will show up flipped on the y-axis. To correct that, we use the setRect function with tile:setRect(-20,31,20,-31) instead of tile:setRect(-20,-31,20,31). prop1 = MOAIProp2D.new() prop1:setDeck(tile) layer:insertProp(prop1) We create a MOAIProp2D object and set the tile we just created to the prop’s deck, and then we insert that prop in the layer: curve = MOAIAnimCurve.new() _max_ = 11 curve:reserveKeys(_max_) for i=1, _max_ do curve:setKey(I, I (1/_max_), I, MOAIEaseType.FLAT) end We create a MOAIAnimCurve object and then designate the number of frames using the reserveKeys function. Then we create the frames and set the index and the time index for each of the frames, 222 CHAPTER 10: Moai with the value of the curve at that time index. A time index is another way of looking at the animation, but instead of it being index based, we set the time index to specify the animation/ transform at that point in time. anim = MOAIAnim:new() anim:reserveLinks(1) anim:setLink(1, curve, prop1, MOAIProp2D.ATTR_INDEX) anim:setMode(MOAITimer.LOOP) anim:start() We use theMOAIAnim class to create our animation. We set up a link betweenprop1 andcurve on the Index attribute. We set the mode to loop as a timer. Then we start the animation with thestart function. prop1 object on the screen at 100,100.  MOAITimer.EVENT_TIMER_KEYFRAME. This is called every time the keyframe is changed and is a callback function that has the following signature: onKeyFrame ( MOAITimer_self, number_keyFrame, number_timesExecuted, number_time, number_value)  MOAITimer.EVENT_TIMER_LOOP. This is called every time the function loops and has the following callback signature: onLoop(MOAITimer_self, number_timesExecuted)  MOAITimer.EVENT_TIMER_BEGIN_SPAN. This is called when the timer playback mode reaches the beginSpan time set using the setSpan function; otherwise this is 0 (i.e. as soon as the animation starts). This has the following callback signature: onBeginSpan(MOAITimer_self, number_timesExecuted)  MOAITimer.EVENT_TIMER_END_SPAN. This is called when the timer playback reaches the endSpan time set using the setSpan function otherwise this is set to the end of the animation. This has the following callback signature: onEndSpan(MOAITimer_self, number_timesExecuted) Here’s an example of using the MOAITimer.EVENT_TIMER_KEYFRAME listener: function onKeyFrame(self, index, time, value) print("Keyframe : ", index, time, value) end anim:setListener(MOAITimer.EVENT_TIMER_KEYFRAME, onKeyFrame)