Dynamic Sprite sequences

Hi

I have a touch event that when user touches the screen will perform an animation. When they release it performs the reverse animation back to the original state.

I normally setup my sequences at the beginning but obviously the user may well decided to release before its completed. I got a little confused with the explanation between sprite.prepare and sprite.play in potentially handling this.

Do I keep the keyframes in an array, determine current frame number at point of release then calculate the reverse frames in real time to create a dynamic sequence and play that? Or is there a whole lot simpler method that I didn’t gauge from reading the docs?

Thanks

J [import]uid: 103970 topic_id: 24115 reply_id: 324115[/import]

Hi.

There is indeed a much simpler way to do that.

when the event.phase = ended, use the spriteSheet.currentFrame api to get the frame you are on, then call

local function reverseAnim()  
 if spriteSheet.currentFrame \> 0 then  
 spriteSheet.currentFrame = spriteSheet.currentFrame - 1  
 end  
end  
tmr = timer.performWithDelay(33, reverseAnim, 0)  

Hope that helps.

Dan

[import]uid: 67933 topic_id: 24115 reply_id: 97334[/import]

Interesting approach thank you Dan I’ll give it a try [import]uid: 103970 topic_id: 24115 reply_id: 97338[/import]

@Dan as a follow up this doesn’t work with the new sprite sheet logic (http://blog.anscamobile.com/2012/03/image-sheets-image-groups-and-sprites/) as currentFrame is deprecated to a readonly Frame property.

Any other suggestions? [import]uid: 103970 topic_id: 24115 reply_id: 97758[/import]

Hmmm, I’m not sure.

Strikes me as very strange to not be able to change the frame currently being displayed by a simple api, e.g. mySprite.currentFrame = x

I couldn’t actually see that it’s been depreciated, (only had a minute to scan through whilst pasta is cooking) but did see that spriteObject.frame is read only. I’m not convinced they are the same thing.

I’ll put in some research when I can as this completely changes the way I’ll have to work…

In the meantime, if anyone in the know can chime in, that’d be great.

If AParachutingFrog is correct, how do we set the frame to be displayed simply? Is there a difference between spriteObject.frame and spriteObject.currentFrame?

Thanks

[import]uid: 67933 topic_id: 24115 reply_id: 97774[/import]

Hey.

I’ve done a little digging and it seems that: character.currentFrame = x has been superceded by:

character:setFrame(1)

There’s a lot of info available on the following thread, which should be useful.

http://developer.anscamobile.com/forum/2012/03/14/issues-imagesheetsimage-groupssprites-build-759

Hope that helps.

Dan [import]uid: 67933 topic_id: 24115 reply_id: 97860[/import]

Thanks Dan good spot I missed that daily build thread. A little hidden away from my tired eyes!

So your code would look something like this now:

[lua]local function reverseAnim()
local currentFrame = spriteObject.frame
if currentFrame > 0 then
currentFrame = currentFrame -1
spriteObject:setFrame(currentFrame )
end
end
tmr = timer.performWithDelay(33, reverseAnim, 0)[/lua]

Presumably that moves the animation back a frame and this is reflected on the device with no need to do a play or some equivalent [import]uid: 103970 topic_id: 24115 reply_id: 97885[/import]

I’d imagine that’d work, but as a non subscriber, I can’t download the latest daily build!

Here is an example of the old method I used for a skating game. In the example I’m simply looking at the currentFrame for the sprite itself, then if the spritesheet has finished playing, resetting the players frame to idle. I appreciate it isn’t exactly what you’re asking for, but it is a working piece of code.

function whichSpriteFrame() --controls sprite events.   
  
 ---------------------------------------------GRAB---------------------------------------------------------  
 if player1.sequence == "grab" then  
  
 if player1.currentFrame == 4 then   
 player1:pause("grab")  
 end  
  
 if player1.currentFrame == 8 then  
 resetToIdle()  
 end  
 end -- end of grab  
  
 ---------------------------------------------FLIP---------------------------------------------------------  
  
 if player1.sequence == "flip" then  
 if player1.currentFrame == 6 then  
 player1:prepare("flipr")  
 player1:play("flipr")  
 end  
  
 if player1.currentFrame == 10 then  
 resetToIdle()  
 end  
 end  
  
 ---------------------------------------------CRASH---------------------------------------------------------  
  
 if player1.sequence == "crash" then  
 if player1.currentFrame == 9 then  
 --resetToIdle()  
 player1:pause("crash")  
 end  
 end  
  
 ---------------------------------------------PUMP---------------------------------------------------------  
  
 if player1.sequence == "pump" then  
 if player1.currentFrame == 5 then  
 resetToIdle()  
 end  
 end  
  
 ---------------------------------------------TURN---------------------------------------------------------  
  
 if player1.sequence == "turn" then  
 if player1.currentFrame == 8 then  
 resetToIdle()  
 end  
 end  
  
 ---------------------------------------------FLIPR---------------------------------------------------------   
  
 if player1.sequence == "flipr" then  
 if player1.currentFrame == 8 then  
 resetToIdle()  
 end  
 end  
  
 end --end of whatSpriteFrame Function  
  
 player1:addEventListener("sprite", whichSpriteFrame) --listens specifically for sprite events  
  
 function resetToIdle() -- resets sprite back to idle state  
 player1:prepare("idle")  
 player1:play("idle")  
 print("IDLE")   
 end  
  
end  

I haven’t played with the new APIs for sprites yet, so can’t really offer much advice on the correct implementation. The method I posted above worked pretty well and allowed a good deal of control, but I’ll need to re-work it again what with the API changes.

If you need more advice feel free to ask and I’ll do what I can, but you’d probably get a better quality answer from asking johnbeebe on the thread he created.

I hope my code helps.

Dan [import]uid: 67933 topic_id: 24115 reply_id: 97907[/import]

Thanks for your help Dan

I’ll try it later and report back [import]uid: 103970 topic_id: 24115 reply_id: 97911[/import]

Not sure if I was doing some wrong but I found it kept resetting the frame as well as playing the animation.

However, I got it to work with the following using the latest sprite logic

[lua]local oldStyleSpriteSheetData = require(“mysprite”).getSpriteSheetData()
myspriteposition = “middle”

local options =
{
spriteSheetFrames = oldStyleSpriteSheetData.frames
}

local imageSheet = graphics.newImageSheet( “mysprite.png”, options )

local sequenceData = {
{ name=“movement”, start=1, count=32, time=750, loopCount=1 }
}

local mysprite = display.newSprite( imageSheet, sequenceData )
mysprite.x = 200
mysprite.y = 200
local currentFrame

– The user has clicked on the screen
function screenTouched (event)

if event.phase == “began” then
if not(myspriteposition == “background”) then

mysprite:setSequence( “movement” )
mysprite:play()
myspriteposition = “background”
end
elseif event.phase == “ended” then
if not(myspriteposiiton== “middle”) then
currentFrame = mysprite.frame
tmr = timer.performWithDelay(15, reverseAnim, 1)
myspriteposition = “middle”
end
end

return true
end

function reverseAnim()
if currentFrame > 1 then
currentFrame = currentFrame -1
mysprite:setFrame(currentFrame)
tmr = timer.performWithDelay(15, reverseAnim, 1)
else
mysprite:setFrame(1)
myspritet:pause()
end
end
Runtime:addEventListener( “touch”, screenTouched )[/lua]

Note: I am using TexturePacker and the old style technique to pull the sheet in.

Thanks Dan for pointing me in the right direction [import]uid: 103970 topic_id: 24115 reply_id: 98050[/import]