Gideros, set Sprites on Fire

Sprites and Animation are one of the most important aspects of a Game. The lack of animation and the performance both can be detrimental for the application's success. The new release of Gideros 2012.8.2 has brought an innovative way to manage bitmaps and as a result of that, sprites and animations are going to be waaaaaaay faster.

First, let us look at how to create an image with Gideros.
local image = Bitmap.new(Texture.new("myimage.png"))
stage:addChild(image)

How do we replace this image with a new bitmap?
there are a couple of ways to do so.

1. We create two bitmaps and hide toggle the visibility of each while showing the images. When we hide image1, we showimage2, that gives us the illusion of having changed the image.

local image1 = Bitmap.new(Texture.new("image1.png"))
  local image2 = Bitmap.new(Texture.new("image2.png"))

  image2:setVisible(false)
  stage:addChild(image1)
  stage:addChild(image2)

2. We remove the object and create a new object in its place with the new image.

image1:removeFromParent()
  image1 = Bitmap.new(Texture.new("image2.png"))
  stage:addChild(image1)

While both these work, as a developer I would expect that I do not have to do all this juggling. This is true for any of the other Lua based frameworks too, that's how it works.

Note: There is however functionality called MovieClips, this can act like a tween for sprites if you want to create a frame based movement animation, you can also create frame by frame animation by setting a new image/sprite for each frame and then setting it to repeat.

When you want to load a portion of an image, more so like a region, Gideros offers us the TextureRegion.new API function. so if we wanted to pick a sprite from a spritesheet,

local texture = Texture.new("spritesheet1.png")
local sprite = Bitmap.new(TextureRegion.new(texture, 10,5, 30, 50))

Assuming that you have a sprite sheet from which you want to pick up the image starting at 10, 5 and of dimensions 30 (wd) x 50 (ht) and if you wanted to change this image, same issue and the same two options as above.

What's new then?

The new API that's added to Gideros 2012.8.2 is the ability to alter the bitmap's texture. Think of the TextureRegion as a window or a mask through which you can see the spritesheet, because the window is smaller than the spritesheet, it will display only a portion of the spritesheet. What we can now do is move this window to a new location on the spritesheet and also modify the dimensions of this window, so the Bitmap now changes to a new image (if on the same texture)

Woah!! Backup, slowly this time, please...
OK, every image that we load, the png is basically called a texture as far as OpenGL is concerned. These textures are used for rendering and are often cached in memory. So when you load a new instance with the same texture, it is already in memory.

we simply change the TextureRegion and thereby the Bitmap is now rendered with a new section of the texture which to us is the new image.


The Magic Happens with

local texture = Texture.new("image.png")
 local region = TextureRegion.new(texture, 0, 0, 30, 50)
 local bitmap = Bitmap.new(region)
 stage:addChild(bitmap)

We can simply change the region as

region:setRegion(30,0,30,50)
bitmap:setTextureRegion(region)

Now this is a drab dry way to look at things, why do we not have a look at it visually?

First there is a video, have a look

If this looks familiar, it could. The image is copyright of CoronaLabs, or atleast it is available in the SampleCode/Sprites/SpriteTiles directory. The sample demonstrates that the sample runs displaying these animations at 30 fps. Now nothing can benchmark unless we try the same image and see how it performs on another framework. So for the purpose of testing the image has been used. It is not being distributed or anything. If you need this, you can download the trial version and get the image from the directory mentioned above. The sample was run at 60fps and it runs better. Now if you want to try this and do have the dancers.png image, then here's the code that you can use to test. Please note, you need the 2012.8.2 version of Gideros, this function is not available in the previous versions.

What is Gideros?

If you have not heard of Gideros, you can download the latest version from http://www.giderosmobile.com The beauty is that if you want to try, there is no trail version that stops you, there is a Free License and you can publish your apps for Free, it just displays a splash screen "Made With Gideros" when the app starts up and It is not restricted in any way. If you feel that you want some feature, you can write Java, C, C++, Obj-C code in the form of Plug-Ins and include that functionality, you do not have to spend thousands in purchasing the Enterprise version.

The Code

--[[
NOTE: This project requires a file called dancers.png and uses it for the animation. 
This file is available in the SampleCode/Sprites/SpriteTiles directory with CoronaSDK
I am not distributing this file as I am not sure of the drama around it's ownership,
however since it is part of the samples, if you have downloaded or get this file from
a friend, you can plug it in and use it.

you can see the video at http://www.youtube.com/watch?v=Dv62ql4Zby0
]]


local _W = application:getDeviceWidth()
local _H = application:getDeviceHeight()

_SIZE_ = 64

local group = Sprite.new()
stage:addChild(group)

local texture = Texture.new("dancers.png")

local _frames = 
  {
  }

function addSprite(x, y, index)

  local texRegion = TextureRegion.new(texture, 0, (index-1)*_SIZE_, _SIZE_, _SIZE_)
  local bitmap = Bitmap.new(texRegion)
  group:addChild(bitmap)
 
  local theFrame = 
  {
    bitmap  = bitmap, 
    texture = texRegion,
    count  = 1,
    dir  = 1,
    index  = index,
  }
 
  table.insert(_frames, theFrame)
 
  bitmap:setPosition(x,y)
end 

local _cols = (_W/_SIZE_ ) + 10
local _rows = (_H/_SIZE_ ) + 10

for j=1, _rows do 
  for i=1,_cols do
    ind = math.random(1,15)
    addSprite((i-1)*_SIZE_, (j-1)*_SIZE_, ind)
  end 
end 

group.width  = group:getWidth()  - _W
group.height = group:getHeight() - _H


local _ox, _oy 
local skipCycle = true

function onEnterFrame(event)

  if skipCycle == true then 
    skipCycle = false
    --return
  end 

  for i=1, #_frames do 
    local frames = _frames[i]
    if frames.count > 15 then frames.dir = -1 end 
    if frames.count <= 1 then frames.dir = 1 end 
    frames.count = frames.count + frames.dir
  
    local _bmp = frames.bitmap
    local _tex = frames.texture
    _tex:setRegion(
        (frames.count-1) * _SIZE_, 
        (frames.index-1) * _SIZE_,
         _SIZE_, _SIZE_)
    _bmp:setTextureRegion(_tex)
 
  end
 
  skipCycle = true
end 

stage:addEventListener(Event.ENTER_FRAME, onEnterFrame)

function onMove(event)
    local x, y = event.x, event.y
    local dx, dy = _ox - x, _oy - y
    _ox, _oy = x, y
 
    local _x, _y = group:getPosition()
    _x, _y = _x - dx, _y - dy
 
    if _x> 0 then _x = 0 end 
    if _y> 0 then _y = 0 end 
 
    if _x< -group.width then _x = -group.width end 
    if _y< -group.height then _y = -group.height end 
 
 
    group:setPosition(_x, _y)
end 

function onDown(event)
    local x, y = event.x, event.y
    _ox, _oy = x, y
end 

function onUp(event)
    local x, y = event.x, event.y
    _ox, _oy = nil, nil
end 


group:addEventListener(Event.MOUSE_MOVE , onMove)
group:addEventListener(Event.MOUSE_DOWN , onDown)
group:addEventListener(Event.MOUSE_UP , onUp)

Comments

Popular Posts