Jump to content

New to PIXIjs, need help moving sprites smoothly


barrard
 Share

Recommended Posts

Hey everyone, thanks for taking time to read, and for any help.

 

I'm using PIXI to show a replay of a simulation that has already run, storing all the times/locations of my objects (squares).  Basically, I have squares that i render as sprites, and i has known positions and times for the squares.  I then use that data to visually show the simulation.

 

Example.  at Time = 0 I have a square at x= 0 and y = 0,  My next data point is at Time = 1, and x = 10 y = 10.

Currently I can just set the new position of the square, but it will jump to the new location, and I would like to smoothly animate the square to its new location.

One question i have:  Would I need to implement a ticker function to do this, or would there be another way?

Also, the time spent moving the sprite can vary, as I can adjust the playback speed of the time.  1x speed would be one data point per second, and 20x speed would be 20 data points per second.

Thanks for any help/input you may have!

Link to comment
Share on other sites

Hi and welcome to the forums!

You have multiple options on how you could do animations:

- Use a tweening library (for example tweenjs, pixi-tween, tweenmax etc).
- Update the positions manually with every render tick.

Using a tweening library would be the easiest. This is an example how you could use one with createjs's Tweenjs library to move sprite from it's current position to 100,50 in 500 milliseconds with quadratic easing in&out:

createjs.Tween.get(sprite).to({x:100, y:50}, 500, createjs.Ease.quadInOut );

For the custom timing function you would then tell the tweening library to not use timer on it's own (most do) and instead call the updates manually with elapsed milliseconds * your speed. 

 

The second option could be something like this for example:

// List of your objects. The data structure here is very shortened from what might be really the case.
const squares = [
  { sprite, positionsAtTime: [{time, point}] },
  ...
];

// A simple linear interpolation function. Returns value between a & b when t is [0,1]
const lerp = (a,b,t) => a*(1-t)+b*t;

// Total elapsed time.
let time = 0;
// Speed on how fast time moves.
let speed = 1;
// Add ticker.
app.Ticker.shared.add( delta => {
  // Advance time by elapsed milliseconds and multiply by speed.
  time += app.Ticker.elapsedMs * speed;
  
  // Go through all the squares.
  for(let i = 0; i < squares.length; i++)
  {
    const s = squares[i];
    // Find the first config that has larger time value that we currently have.
    const to = s.positionsAtTime.find( tp => tp.time >= time);
    // Find out the previous one.
    const was = s.positionsAtTime.indexOf(to)-1;
    // Make sure both exists. Replacing the find & indexof with better data structure would be really good performancewise. 
    if(to && was){
      // Calculate the x&y positions with linear interpolation.
      // (time-was.time)/(to.time-was.time) returns [0,1] when time is between was.time and to.time.
      s.sprite.x = lerp( was.point.x, to.point.y, (time-was.time)/(to.time-was.time) );
      s.sprite.y = lerp( was.point.x, to.point.y, (time-was.time)/(to.time-was.time) );
    }
  }
});

Hopefully these help.

Link to comment
Share on other sites

Exca, Thank you so much for your response.  

I attempted to manually move my sprites in the ticker function which worked initially.  But some things have changed.

                                                          //time = 0,       1,         2,          3

Previously, I would get data like `path = [[0,0], [10, 0], [20, 0], [30,0]]`//movement along a straight line is simple enough

each index would represent 1 second of real time, and, so i would calculate the distance, divide by 60 fps, and update the position to animate between each new position

We changed our path data, and adjusted movement speeds.  So now my sprites can do more complex pathing within each 1 second time frame.

Example:  at time = 0 my sprite could be at [0,0], and at time = 1, they could be at [20, 20], however, the path they take to get there cannot be assumed a straight line, as the path here could be

`path = [[0,0], [10, 0], [10,10], [20, 10], [20,20]]`    

The createjs tween library might be exactly what i need. 

could I feed createjs a complex path, and tell it to animate that over 1 second?  would this happen outside of my pixijs ticker function?  

Thank you so much for your suggestions!

Link to comment
Share on other sites

18 hours ago, barrard said:

could I feed createjs a complex path, and tell it to animate that over 1 second?  would this happen outside of my pixijs ticker function? 

What I usually do in cases like this is to animate a custom property from 0...1. Lets call that property "progress". And then on each update I would calculate the path from that value:

// SplineCurve in this is just a placeholder class that would calculate the curve.
const spline = new SplineCurve(points);
const progress = {value:0};
createjs.Tween.get(progress, {onChange:()=>{
  mySprite.position.set( spline.evaluate(progress.value ));
  // Maybe the progress has some other stuff also like opacity changes & scaling, easy to add others here as well:
  mySprite.scale.set( progress.value );
  mySprite.alpha = progress.value < 0.1 ? progress.value/0.1 : progress.value > 0.9 ? (1-progress.value)/0.1 : 1;
}).to("value",1, 500, createjs.Ease.linear);

 

Link to comment
Share on other sites

Thanks for the feedback Exca, sorry for the delayed response.

I found `gsap.to()`  with the MotionPath plug did 99% of the heavy lifting for moving my sprites along the path.  But I'm experiencing a strange bug when my sprites are arriving at the end of the path, they randomly get

assigned a (0,0) position.  I think it happens when the path they get includes two node that are identical, i.e. path = [{x:120, y:200},{x:120, y:200}].

Has anyone experienced this?

Link to comment
Share on other sites

Are you sure they go to 0,0 and not NaN,NaN? That sounds like they might end up as not a number due to the path being of a zerolength one. You could either see if they are same or just add some really really tiny value to numbers so that no NaN happens.

Though first you should make sure that NaN is the issue. Looks like the MotionPathPlugin has a getPositionOnPath -function, or then you could just log the objects value you are updating when it goes to wrong position.

 

Link to comment
Share on other sites

Good idea Exca.  Yeah my little square sprites would snap up to the top left corner.  It's possible that gsap was freaking out from my path having duplicate path nodes. 

After fixing my code to ensure the path didn't have duplicate/consecutive nodes with identical values, this (0, 0) bug stopped happening

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

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