When we last visited Moai land things were getting started, hot and pink; but just a bit boring. Let’s spice it up a bit with a sprite that totally isn’t the logo from Watchmen!
screenWidth = MOAIEnvironment.screenWidth screenHeight = MOAIEnvironment.screenHeight print("Starting up on:" .. MOAIEnvironment.osBrand .. " version:" .. MOAIEnvironment.osVersion) if screenWidth == nil then screenWidth =640 end if screenHeight == nil then screenHeight = 480 end MOAISim.openWindow("Window",screenWidth,screenHeight) viewport = MOAIViewport.new() viewport:setSize(screenWidth,screenHeight) viewport:setScale(screenWidth,screenHeight) layer = MOAILayer2D.new() layer:setViewport(viewport) MOAIRenderMgr.pushRenderPass(layer) sprite = MOAIGfxQuad2D.new() sprite:setTexture("smile.png") sprite:setRect(-200,-200,200,200) prop = MOAIProp2D.new() prop:setDeck(sprite) prop:setLoc(0,0) layer:insertProp(prop) MOAIGfxDevice.setClearColor(1,1,1,1)
And when you run it:
At least half of this code we covered in the prior tutorial, so we will skip right past that and jump in to what’s new:
sprite = MOAIGfxQuad2D.new() sprite:setTexture("smile.png") sprite:setRect(-200,-200,200,200)
Our “sprite” is in fact a MOAIGfxQuad2D, which may at first sound like a remarkably more confusing name than sprite. You see, behind the scenes Moai ( and pretty much every other modern engine ) is actually working in 3D, not 2D. It’s just the way GPUs work these days. So when you see a 2D library, it is actually faking 2D by creating a 3D scene and ignoring one of the D’s. As part of the process, you don’t really have sprites anymore, instead you have textured quad’s ( 4 vertices rectangles ) that are parallel to the camera. So, we create a rectangle that is aligned to the camera and draw our texture on top of it, giving the illusion of being a simple sprite or image, but making the GPU happy at the same time. So… that’s why it’s called a MOAIGfxQuad2D instead of say… a sprite.
Anyways, we create a new MOAIGFXQuad2D, and set it’s texture to the file name we want to load onto it. Oh yeah, you need an image to display, and you need to copy it to the same folder as main.lua. While we are on the topic of “oh yeahs!’”, save the above code to a file named main.lua! Once we load our texture, we are going to size and position our quad in a single call, setRect(). Coordinates are relative to the center of the screen, so position 0,0 is exactly in the middle of your screen. So when we say –200,-200, we are saying the top left corner of the rectangle is 200 pixels to the left of center and 200 pixels above center. While the other 200,200 is saying the bottom right corner of the quad is 200 pixels to the right and 200 pixels down from the center point. End result, we create a textured quad centered to our screen that is 400×400 pixels, so I suppose that is technically a square. By changing the values in setRect, you can reposition the sprite ( for example (-400,-200,0,-200) would move the quad 200 pixels to the left ) as well as scale it ( (-100,-100,100,100) would scale it to half it’s current size ).
prop = MOAIProp2D.new() prop:setDeck(sprite) prop:setLoc(0,0) layer:insertProp(prop)
Now we create a MOAIProp2D. Remember in the last tutorial when I said layers are made up of stuff that are composed together to create the frame? Well a MOAIProp2D is one such example of “stuff”. What then does setDeck do? In the simplest term, think of a “Deck” as a data source. An image or a sprite sheet ( or texture atlas in Moai parlance ) are both examples of decks. Think of a Prop is an *instance* of a deck, or perhaps most accurately instanced from a deck. To make life easier on yourself, just think of a deck as the data source for a prop. I’ll be honest, I’m not a huge fan of the metaphor they choose, but then if you read their explanation, neither are they. Next you position the prop within the layer, keeping in mind 0,0 is dead center. Finally, the prop is inserted into the layer via insertProp(). To finish things off:
I like pink as much as the next man, but sometimes I like white a whole lot more.
That, is how you display a sprite ( erm, Prop ) on screen.
But wait! There’s more…
You do however have a couple options. You see, loading from file can be a bit expensive, especially if you are using the same image over and over. So, instead of loading the sprite from disk in the setTexture call, lets instead load it from an Image already loaded and resident in memory.
texture = MOAIImage.new() texture:load("smile.png") sprite = MOAIGfxQuad2D.new() sprite:setTexture(texture) sprite:setRect(-200,-200,200,200)
Here we create a MAOIImage in advance, load the image file into it, then use that in our setTexture() call. Now instead of loading from disk, it loads from memory, which is substantially quicker. One thing should be pointed out here, that image is in system memory and needs to be copied to the GPU each time it is drawn. Don’t worry, this makes sense and is completely normal, but on occasion can be a bit hard on performance. If you have an image that is drawn a lot, like say, the player sprite or a static part of the HUD, you may want to cut the whole copy to video memory out of the equation and store your sprite in video memory. MOAI has a way to do this as well.
texture = MOAIImageTexture.new() texture:load("smile.png")
Basically you just use MOAIImageTexture instead of MOAIImage. Keep in mind, video memory is a constrained resource, so don’t do this lightly. Also keep in mind, changing the item in video memory effectively ruins any point of it being there in the first place, so only use MOAIImageTexture if your image isn’t changing often. I would generally recommend you go with normal MOAIImage until you have a good reason not to. Be careful, your optimization can easily cause performance to get worse!
And done… you now know how to draw an image on screen, one step closer in our master plan to take over the wor… er, create a game. Stay tuned for the next exciting episode where we demonstrate how to successfully raise a peasant army… or handle touch events. One of those two topics, I’m not sure which yet.