Jump to content
Search Community

gsap tween with Pixi AnimatedSprite

Baxter85 test
Moderator Tag

Recommended Posts

Hi guys,

i'm trying to find out how to use gsap in conjunction with Pixi to be able to control a spritesheet through the gsap tick but i'm having difficulties to understand how to make it work.

Here's how i generate the animatedSprite dynamically from a json feed:

texture = images[layer.name].texture
const fw = 300
const fh = 250
const sprW = texture.width
const sprH = texture.height
const cols = Math.floor(sprW / fw)
const rows = Math.floor(sprH / fh)
const totalFrames = layer.frames
let frameCounter = 0
const spriteSheetFrames = []
for(let r=0; r < rows; r++) {
  for(let c=0; c < cols; c++) {
    console.log(c * fw, r * fh)
    if(frameCounter < totalFrames) spriteSheetFrames.push(new PIXI.Texture(texture, new PIXI.Rectangle(c*fw, r*fh, fw, fh)))
    frameCounter++
  }
}
const animation = {}
animation["sequence"] = spriteSheetFrames
const spritesheet  = new PIXI.AnimatedSprite(animation.sequence)
spritesheet.alpha = layer.alpha || 0
spritesheet.x = layer.x || 0
spritesheet.y = layer.y || 0
spritesheet.animationSpeed = layer.speed

Now, i have a main timeline that run a sequence of animations on different elements, how i can play the AnimatedSprite and control it with gsap? 

i tried to do something like this:

tl.to(layer.spritesheet, duration, { onStart: () => layer.spritesheet.play(), onComplete: () => layer.spritesheet.stop() }, start)

which it works but first is just a hack, second i need to set the duration exactly as the duration of the original animation and third i cannot control it, if i stop the timeline the spritesheet does not stop at all, and that's because i think it does not use the timeline timer.

Any suggestion?

 

thanks.

Link to comment
Share on other sites

guys an update, i found an example here on the forum made by Carl that animates the background property to move the sprite and i thought to adapt it to my needs with PIXI and it works.

 

const playSpritesheet = (tl, layer, start) => {
  const fw = 300
  const fh = 250
  const cols = Math.floor(layer.spritesheet.width / fw)
  const rows = Math.floor(layer.spritesheet.height / fh)
  let count = 0
  let interval = layer.interval
  for (let r = 0; r < rows; r++){
    for (let c = 0; c < cols; c++){ 
      if(count < layer.frames) {
        let xpos = -c * fw;
        let ypos = -r * fh;
        tl.set(layer.spritesheet, { pixi: {x: xpos, y: ypos} }, start + count * interval)
        count++
      }
    }
  }
}

now i need to understand one thing, my guess is that this approach is more performant since i use 1 texture instead of 187 in my case, but i would like to know your opinion, the second thing is that now i can control it with gsap but i still trying to figure out how i can calculate the interval base on the fps and duration i want to give to the animation. Right now i found that the value 0.03 (which is stored in layer.interval) is a perfect match but i would like to calculate that dynamically based on the duration and fps i want. How the heck i can do that? :D

 

thanks.

Link to comment
Share on other sites

1 hour ago, Baxter85 said:

this approach is more performant since i use 1 texture instead of 187 in my case, but i would like to know your opinion

How are you defining "performance"?  Total file size? Time to first load? Something else? 

 

1 hour ago, Baxter85 said:

calculate that dynamically based on the duration and fps i want. How the heck i can do that?

The calculation is simply:

start + count * interval

start is an optional start time in seconds. count is simply the index. Your interval variable is the main determinant of the rate of which your sprite is changed. The total duration of your timeline is simply start + layer.frames * interval (unless you do use .timeScale() or something on the timeline).

Link to comment
Share on other sites

Hi Zach, thanks for the reply.

For the performance, i meant how heavy is on the gpu having 187 textures created at runtime compared to have one only changing position. I know the GPU is really fast but just a thought to understand which method is more convenient being just a simple banner.

For the calculation, yes, is what i have done already, maybe i explained it badly (sorry), what i meant is that i used a 0.03 interval just with trial and error, and i would like to know how do i calculate that number in case i have a different a frame rate for the spritesheet ?(unless that inerval number is static since it is based on the fps set on the ticker?).

In case i have a spritesheet with different fps than 30 for example, the interval need to change (i suppose if not based on the ticker), how do i find that number (interval) without me trying different values?

I know the length in seconds, fps and total frames of the spritesheet, which formula i can use to calculate that number?

I'm not a master in Math, so any suggestion to drive me towards the goal is appreciated.

 

Thanks.

Link to comment
Share on other sites

3 hours ago, Baxter85 said:

i meant how heavy is on the gpu having 187 textures created at runtime compared to have one only changing position. I know the GPU is really fast but just a thought to understand which method is more convenient being just a simple banner.

I am not sure. You could measure the difference :) 

 

3 hours ago, Baxter85 said:

I know the length in seconds, fps and total frames of the spritesheet, which formula i can use to calculate that number?

If I'm not mistaken, it's just:

thatNumber = targetFPS / 360

 

Link to comment
Share on other sites

After a bit i made it work in the way i wanted. Now i can set the duration i want and based on that i can speed up or slow down the animation and also control it through gsap if i need to bind it to a input range for debugging.

 

here the final code in case somebody need it for PIXI:

 

const spritesheetTween = (tl, layer, start) => {
  const fw = 300
  const fh = 250
  const cols = Math.floor(layer.spritesheet.width / fw)
  const rows = Math.floor(layer.spritesheet.height / fh)
  let count = 0
  let interval = layer.seconds / layer.frames
  for (let r = 0; r < rows; r++){
    for (let c = 0; c < cols; c++){ 
      if(count < layer.frames) {
        let xpos = -c * fw;
        let ypos = -r * fh;
        tl.set(layer.spritesheet, { pixi: {x: xpos, y: ypos} }, start + count * interval)
        count++
      }
    }
  }
}

thanks Zach!

 

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...