Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Confused -how to animate sprite from a texture sheet? — Gideros Forum

Confused -how to animate sprite from a texture sheet?

MauMauMauMau Member
edited August 2013 in General questions
After switching from Corona to Gideros I was looking for a method to create animated sprites / movie clips from a texture sheet. The docs are more than confusing regarding that. There is a class named MovieClip but it seems that those MovieClip thingies are static images whose properties can be tweened only. So obviously not what I am looking for.

Then I searched the example codes and found three different things: the bird animation, gtween and the Texture Pack example.

1. So which one should be preferred? I am using a texture atlas exported from Texture Packer (non-uniform / different sized frames) and want to create an animated sprite from it.


2. In the Texture Pack example, TexturePack.new() is used like this:

local pack = TexturePack.new("anim.txt", "anim.png")

Whereas the docs specify TexturePack.new() like this:

TexturePack.new(textures, padding, filtering, options)

Which one is correct?

And how should the "textures" parameter look like? A string? Or a table? And if this parameter is a table, what properties should it contain and in what order?


3. What does the content in an anim.txt file stand for? I assume that the strings are just name identifiers for each individual frame (and can be changed to anything else), while the next four numbers on a row define the x,y,width and height of this individual texture region -but what about the other four numbers?

The reference is very unclear and confusing on that -or did I miss some "magic" tutorial section here where all this is explained in detail? o.O



Comments

  • @MauMau
    1) from what I understood MovieClip is exactly what you need, just enter each frame and it's length in it and thats all.
    Tweening of frames is only additionally if needed, but not required, MovieClip is meant for frame animations.

    So if you have a TexturePack, you wold go like this.
    local anim1 = Bitmap.new(pack:getTextureRegion("frame1.png"))
    anim1:setAnchorPoint(0.5, 0.5)
    local anim2 = Bitmap.new(pack:getTextureRegion("frame2.png"))
    anim2:setAnchorPoint(0.5, 0.5)
     
    --of course you can do the previous part in the loop also
     
    local animation = MovieClip.new{
    	--specify start frame, end frame and bitmap to render in those frames
    	{1, 10, anim1},
    	{11, 20, anim2}
    }
     
    --use it as any sprite, add to the scene, set position, etc
     
    --and goto first image and play
    animation:gotoAndPlay(1)
     
    --you can also set up looping different animations
    animation:setGotoAction(20, 1)
    2) as specified in docs, there are two constructors for the TexturePack, both what you have specified and both valid

    3) anim.txt contains the references to the original images, so you could use original image names to get textures instead of providing positions, dimensions and offsets.
  • MauMauMauMau Member
    edited August 2013
    Hm, when I define a texure pack like this:

    local pack = TexturePack.new("anim.txt", "textureSheet.png")

    it uses the .txt file (where all images used on the sheet are already defined by name).

    But as I understood, I additionally have to "hardcode" the image names in my code then:

    self.anim =
    {
    Bitmap.new(pack:getTextureRegion("anim_01.png")),
    Bitmap.new(pack:getTextureRegion("anim_02.png")),
    Bitmap.new(pack:getTextureRegion("anim_03.png")),
    .......
    }

    I'd prefer to only specify the .txt file as exported from Texure Packer and avoid hardcoding the image names in my actual code. So is it possible to extract the image names from a texture pack and create a list of images like this?

    self.anim = {}
    for i = 1, pack.numImages do
    self.anim[i] = pack.getTextureRegion[i]
    end

    Also, if it would be possible to numerally loop through a texture pack's texture regions like this, there would be no need to use self.anim anymore to store references to them.

    Is there a way to do so to avoid hardcoding the image names of a texture atlas in the actual project code? I want to avoid unnecessarily blowing up my code, but also the need to change my code again if I decide to replace the anim.txt with another one at a later time.

    Likes: Platypus

    Dislikes: shandiaobd

    +1 -1 (+1 / -1 )Share on Facebook
  • john26john26 Maintainer
    AFAIK texturepack has nothing to do with animations per se, it's just a convenient way to specify lots of Bitmap objects from a single PNG file. MoveClip is all very well if your animation doesn't depend on anything but, say, you have a man walking along and you want to play a sequence of frames synchronised with his movement, then MovieClip is not so useful. In that case you can use bitmap:setTexture() to alter what texture is being displayed in each Bitmap and you need to do this in your ENTER_FRAME listener, updating the texture displayed as you update the sprite position.

    The bird example is out of date (at least in my version) as it precedes the introduction of the setTexture function. In this example the bird is a sprite with several children bitmaps. At any given time all but one are invisible which gives the illusion of animation but its a complex, clunky way to write code and not practical for anything complex. Use setTexture instead.

    Likes: Platypus

    +1 -1 (+1 / -0 )Share on Facebook
  • @MauMau only like:
    self.anim = {}
    -- number of images
    local imgNum = 100
    for i = 1, imgNum do
     self.anim[i] = pack.getTextureRegion["anim_"..i..".png"]
    end

    Likes: Platypus

    +1 -1 (+1 / -0 )Share on Facebook
  • MauMauMauMau Member
    edited August 2013
    @ar2rawseen: meanwhile I came up with this method to read out a data file as exported from Texture Packer to get the image names list (_strExplode is a helper function to split a string into segments, as known from PHP). This avoids hardcoding any image names or number of images used. This works well so far:
            Images = {}
    	for line in io.lines(dataFile) do
    		Region  = Pack:getTextureRegion(_strExplode(line,", ")[1])
    		table.insert( Images, Bitmap.new(Region) )
    	end
    	numFrames = #Images
    @john26: thanks for the hint, I'll try setTexture then. So bitmap objects also support displaying a specific texture region on a texture atlas? How should this be efficiently done then -by reading the exported Texture Packer .txt file to know the individual texure regions and using this data to change the texture region of the bitmap dynamically?

    It feels a bit like solving a puzzle, always jumping around in the reference and collecting things together. I wish there would be a clear, complete, up-to-date guide on how to efficiently animate sprites (or bitmaps) with Gideros. Or is there one that I just missed yet?
  • I don't know, I was usually using MovieClips and was completely satisfied with it. :)
    Oh another option I forgot to mention is TNT Animator Studio:
    http://www.tntparticlesengine.com/?cat=14

    And there were also other community released classes/libs to help with animations on the forum
  • @MauMau
    As @ar2rsawseen suggested, I highly recommend that you take a look at TNT Animator Studio provided by @GregBUG.

    Likes: Platypus

    twitter@TheWindApps Artful applications : The Wind Forest. #art #japan #apps
    +1 -1 (+1 / -0 )Share on Facebook
  • Ok, I tried to create a little helper class to automatically create an animated MovieClip from a specified Texture Packer .txt and .png. The class reads the .txt file as exported from texture packer to get the individual frame names and creates a MovieClip to play all the frames.

    It basically works (the MovieClip is created and plays correctly) -but for some reason my class does not return a valid handle to the created MovieClip:

    "class_movieclip.lua"
    Create a MovieClip from a specified Texture Packer .txt and .png and return its handle:
    AnimClip = Core.class()
     
    ------------------------------------------------------------------------
    -- METHOD: CREATE NEW ANIMATED MOVIECLIP FROM A TEXTURE ATLAS
    ------------------------------------------------------------------------
    function AnimClip:init(dataFile, imgFile, loop)
    	local line, Region, name
    	local Pack         = TexturePack.new(dataFile, imgFile)
    	local maxWidth     = 0
    	local maxHeight    = 0
    	local frames       = {}
    	local timeline     = {}
    	-- READ TEXTURE ATLAS DATA, CREATE TIMELINE FROM IT
    	for line in io.lines(dataFile) do
    		name    = line:match'(%S+),%s+'
    		Region  = Pack:getTextureRegion(name)
    		x,y,w,h = Region:getRegion()
    		if w > maxWidth  then maxWidth  = w end
    		if h > maxHeight then maxHeight = h end
    		table.insert( frames  , {name=n, x=x, y=y, w=w, h=h} )
    		table.insert( timeline, {#frames,#frames,Bitmap.new(Region)})
    	end
    	-- CREATE MOVIECLIP
    	local Clip     = MovieClip.new(timeline)
    	Clip.numFrames = #frames
    	Clip.frames    = frames
    	Clip.maxWidth  = maxWidth
    	Clip.maxHeight = maxHeight
    	if loop == nil or loop == true then Clip:setGotoAction(#frames,1) end
     
    	stage:addChild(Clip)
    	Clip:play()
     
    	return Clip
    end

    This seems to work since the MovieClip is displayed on the stage and animates. But when I try to access the returned MovieClip handle ("Clip") from my main.lua, it gives me an error:

    main.lua
    local Clip = AnimClip.new("gfx/anim.txt", "gfx/anim.png")
    Clip:setPosition(150,150)
    Error: attempt to call method 'setPosition' (a nil value)

    What did I do wrong..?
  • @MauMau you can't return Clip from the init method, because init method automatically returns the instance of the AnimClip class.
    And since AnimClip class does not inherit from Sprite, it does not have setPosition method
  • Hm, so I guess I'd have to extend the MovieClip class to read a specified data txt file and generate an animation from that data. But if so, how can we set or change a MovieClip's timeline at any later time? According to the reference, there is only one way to specify a MovieClip's timeline -and this is at creation time, or isn't it?








  • Unfortunately, probably performance wise, MovieClip represents only one specific set of frames.
    What you can do is to inherit your AnimClass as Sprite
    AnimClip = Core.class(Sprite)
    And then add Clip as a child of AnimClass
    self:addChild(Clip)
  • I am currently trying to 'abuse' the Bitmap class and add animation stuff to it. Since Bitmap allows to specify a texture region, this should fit my needs (plus, Bitmap supports setAnchorPoint).

    However, I am not sure how to extend the class properly. My approach is like this:
    AnimClip = Core.class(Bitmap)
     
    ------------------------------------------------------------------------
    -- CREATE ANIMATED BITMAP FROM A SPECIFIED TEXTURE ATLAS
    ------------------------------------------------------------------------
    function AnimClip:init(dataFile, imgFile, frameDuration)
    	local line, region
    	local Pack        = TexturePack.new(dataFile, imgFile)
    	local frames      = {}
    	self.currFrame    = 1
    	self.maxWidth     = 0
    	self.maxHeight    = 0
    	-- READ TEXTURE ATLAS DATA, CREATE TIMELINE FROM IT
    	for line in io.lines(dataFile) do
    		region         = Pack:getTextureRegion(name)
    		x,y,w,h        = region:getRegion()
    		if w > maxWidth  then maxWidth  = w end
    		if h > maxHeight then maxHeight = h end
    		table.insert( frames  , {
    					name=line:match'(%S+),%s+', 
    					region=region, 
    					x=x, 
    					y=y, 
    					w=w, 
    					h=h} )
    	end
    	self.numFrames = #frames
    end
     
    -- ANIMATION METHOS GO HERE
    But this results in an error, of course, since the Bitmap class awaits a texture as the first parameter. Is it possible to extend the Bitmap class' init parameters to accept parameters as shown above isntead of a texture or region?

  • Again similar to what I suggested above, AnimClip inherits from Sprite, and you create and manage Bitmap internally as instance property.
  • NascodeNascode Guru
    edited August 2013
    Looking at this thread makes me suggest that gideros examples should be updated with recent API changes and good practices.

    We could also remove included examples and move it online somewhere. Or we could show online page on gideros studio welcome screen ala Netbeans or Visual Studio.

    It takes time to create examples, but it should help many newcomers. I think there are many newcomers recently on this forum (which is good for business!)

    @ar2rsawseen @atilim

    Likes: Platypus

    have fun with our games~
    http://www.nightspade.com
    +1 -1 (+1 / -0 )Share on Facebook
  • Scary thread that one...
    I make games for children: http://www.kidoteca.com
Sign In or Register to comment.