barrard Posted June 9, 2021 Share Posted June 9, 2021 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! Quote Link to comment Share on other sites More sharing options...
Exca Posted June 10, 2021 Share Posted June 10, 2021 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. ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
barrard Posted June 11, 2021 Author Share Posted June 11, 2021 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! Quote Link to comment Share on other sites More sharing options...
barrard Posted June 11, 2021 Author Share Posted June 11, 2021 I just found this codepen, and it looks very similar to what I'm doing. https://codepen.io/osublake/pen/WpVMoO This uses greenSock, TweenMax Quote Link to comment Share on other sites More sharing options...
Exca Posted June 12, 2021 Share Posted June 12, 2021 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); Quote Link to comment Share on other sites More sharing options...
barrard Posted June 15, 2021 Author Share Posted June 15, 2021 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? Quote Link to comment Share on other sites More sharing options...
Exca Posted June 15, 2021 Share Posted June 15, 2021 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. Quote Link to comment Share on other sites More sharing options...
barrard Posted June 16, 2021 Author Share Posted June 16, 2021 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 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.