Saturday 14 April 2012

Sprites and Animation

Creating great animations and sprites within your games is important to make your game stand out amongst 100,000s of apps. The challenge with being an indie developer is you have to be a master of a lot of skills and typically your skills fall into either designer / arty or coder.

I did't have the time to create a load of keyframe animations from scratch but I knew I wanted to have the rocket within Astavoid banking front and back. The way I went about this was to use one of my kids toys and skewer it so I had a steady x axis and then film myself doing the transitions that I was looking for.



Once I had the video in place I had a number of options open to me to extract the relevant frames. This could have cost me some money such as QuickPlayer Pro or similar but I decided to use the more manual command+shift+4+spacebar on Mac Lion to capture the selections I wanted. This was a little laborious but certainly far quicker than drawing from scratch.

Next I imported my keyframes (of the movie) into Flash CS3 and simply traced over the top of them. This was a pretty quick exercise and had all 250 keyframes done within a day. I later reduced the number of keyframes to 60 which I will discuss below as well as in memory optimisation post to follow.

Again, at this stage once you have your frames you have choices. As I had done my work within Flash exclusively I could have used the excellent SpriteLoq to aid the scaling and texture pack I have ended up with but at the time I wanted to use something more universal to learn techniques that weren't exclusive to Flash.

What I chose was to export my now traced images and apply relevant scaling using Preview for Mac Lion (again free) and then importing my images into TexturePacker. As I said in my previous post (http://mygamingproject.blogspot.co.uk/2012/01/physic-and-texture-editors.html) TexturePacker is an excellent tool and very quick to work with. What I will note here is and to save you a few months of redoing your work is that Corona SDK has significantly changed with its sprite and image optimisation and as such I downloaded (at time of writing) the beta version (TexturePacker-3.0.0b3.dmg (MacOS X 10.6/10.7 – 32/64bit)) to make use of the changes.




In Corona SDK daily build 2012.759 significant changes were made to help with the challenges around the infamous texture memory on older devices. While the use of sprite sheets has been simplified for all the benefits come for older devices (iPhone 3GS) in handling more sophisticated sequences. As I put in my post the other day the daily builds are a blessing and a curse as I probably spent about 3 weeks optimising performance but still struggled on older devices, this was a change I was prepared to make.

I won't repeat what is already an excellent blog post by Jonathan Beebe (http://blog.anscamobile.com/2012/03/image-sheets-image-groups-and-sprites/) but the bit I was most concerned with was was optimising my sprite sequence but using an interim technique while third party tools caught up with the 2012.759 changes. At time of writing SpriteLoq is the only one making full benefit of this.

So in order to use TexturePacker and the new Sprite Api I do something like this:

display.setStatusBar( display.HiddenStatusBar )
-- Enable physics so that we can determine collisions
local physics = require ("physics")
physics.start()
-- Normally the gravity to simulate earth is around 9.8 but we don't
-- want a gravitorial effect in this game just the benefit of collision detection
physics.setGravity(0,0)
--physics.setDrawMode( "hybrid" ) 

physicsData = (require "astavoidPhysics").physicsData(1.0)

local oldStyleSpriteSheetData = require("rocket").getSpriteSheetData()
rocketPosition = "middle"

local options = { spriteSheetFrames = oldStyleSpriteSheetData.frames }
local imageSheet = graphics.newImageSheet( "rocket.png", options )

local sequenceData = {
    { name="back", start=1, count=32, time=750, loopCount=1 },
    { name="forward", start=33, count=32, time=750, loopCount=1 }
}

local gameRocket = display.newSprite( imageSheet, sequenceData )
gameRocket.x = 200
gameRocket.y = 200
physics.addBody(gameRocket, physicsData:get("middle"))

-- The use has clicked on the screen 
function screenTouched (event)

    if event.phase == "began" then
     if not(rocketPosition == "background") then
      local currentFrame = gameRocket.frame
      gameRocket:setSequence( "back" )
      if(currentFrame > 1) then
    currentFrame = 32 - currentFrame 
    gameRocket:setFrame(currentFrame)
   end
   gameRocket:play()
   rocketPosition = "background"
   physics.removeBody(gameRocket)
   physics.addBody(gameRocket, physicsData:get("back"))
  end 
 elseif event.phase == "ended" then 

  if not(rocketPosition == "middle") then
   local currentFrame = gameRocket.frame
   gameRocket:setSequence( "forward" )
   
   if(currentFrame < 32) then 
    currentFrame = 32 - currentFrame
    gameRocket:setFrame(currentFrame)
   end
   gameRocket:play()
   rocketPosition = "middle"
   physics.removeBody(gameRocket)
   physics.addBody(gameRocket, physicsData:get("middle"))
  end
 end 
  
 return true
end

Runtime:addEventListener( "touch", screenTouched )

Pretty simply huh!!!

There are always different or better ways of doing these things but pretty happy having worked this out with minimal cost and what has turned out to be a reasonably professional effect.

Let me know your thoughts or techniques if you are happy to share.

0 comments:

Post a Comment

 
;