Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
greenhornsock

Getting a train with multiple waggons to move along a bezier path

Recommended Posts

Hello Folks,

 

i am trying to build a little educational application in which i need a train to follow a dynamically created bezier path.

i have alredy built the whole thing using TweenMax and the Bezierplugin. 

TweenMax.to(train, SPEED, {bezier:{type:"soft", values:path_values, autoRotate:["x","y","rotation",0,false]}, ease:Linear.easeNone});

however i would like the train to consist of at least 3 to 5 separate parts, which should move like a real train on the tracks.

 

at the moment my brain seems to be blocked, so i do not know how to do this using the TweenMax/Lite Tools.

for example how can i make the second "waggon" follow the first one?
 

Thanks for all tips!

Link to comment
Share on other sites

Hi and welcome to the GreenSock forums.

 

In order to create this train effect basically each train car needs its own Bezier tween that starts slightly after the previous car.

I have a JavaScript example which should help you understand what to do:

 

http://codepen.io/GreenSock/pen/iKcrD?editors=001

 

In that example a loop runs that creates a new creature (DOM element / image) and then inserts a Bezier tween into a timeline for that creature with an offset start time.

 

It would work exactly the same way in ActionScript except you would use MovieClips or Sprites.

  • Like 1
Link to comment
Share on other sites

hi carl,

i played around with your code.

problem is: if you see the begin and endpoints of the "track" the illusion does not work anymore.

in my case you see a closed track including the beginning and end ...

hmm
 

Link to comment
Share on other sites

Perhaps you can use repeating tweens in your timeline. This way when the first train wagon gets back to the beginning it will keep going, and the second and third will follow. 

Link to comment
Share on other sites

Hello Carl,

 

i did it now with multiple timelines.

it works pretty good.

dont know about the performance hit though ...

Link to comment
Share on other sites

I can't imagine there being any noticeable performance hit. If you are having problems please provide an example.

Thanks.

Link to comment
Share on other sites

hmm, one more thing:

 

in order to create the illusion of the "waggons" following each other, i used
 

tl.progress(1-delay*i).timeScale(0);

where delay is a factor from 

tl.totalDuration() / DELAY *100

and DELAY a constant.
the "speed" or length of the timeline depends on the number of trackparts in oder to keep the animationspeed constant no matter how long the track is.

unfortunately with this method i do not get consistent delays between the "waggons" 
 

any idea where my mistake might be?

 

thanks!

Link to comment
Share on other sites

Sorry, very difficult to know what is happening from that code fragment.

Have you tried offsetting the time() instead of progress()?

Are you sure all tweens have the same easing (preferably Linear.easeNone)

 

If your timelines are all exactly the same (same tweens, same durations, etc), they will all progress at exactly the same rate. 

Link to comment
Share on other sites

Hello Carl,

 

sorry, here is some more code (simplified for the example):
 

private const SPEEDPERTILE:Number=.2
private const NUMCARS:Number=3

// this gets computed at runtime by the trackparts the player used.
private var _path_values:Array

_speed=_path_values.length*SPEEDPERTILE;

for (var i:int = 0 ; i< NUMCARS; i++){
	var tl = new TimelineMax({repeat:1});
	tl.add(getTrainPartAnimation(i));	
	tl.progress(1-DELAY*i).timeScale(0);
	tl.pause();

}

private function getTrainPartAnimation(i:int):TweenMax {

	var car:Sprite=_train["train_"+i];
	
	TweenLite.set(car, {x:_path_values[0].x,y:_path_values[0].y});
 	var tween:TweenMax = new TweenMax(element, _speed, {
   		bezier:{
     		type:"soft", 
     		values:_path_values,
     		autoRotate:true
   			},
   		ease:Linear.easeNone
		}
		
		);
	
	return tween;
}

the time() method gives me the same issue ...

hmmm

Link to comment
Share on other sites

Yeah, I'm having a tough time looking at the code and imagining the discrepancy in the output.

If each track is identical and the only thing that varies is the initial starting position... I don't know why they would get out of sync.

If you start them all at time or progress of 0 do they run perfectly in synch?

 

If you could provide a simple file (zipped) that only has enough code and assets to replicate the issue it would probably help us better see what is happening. 

Link to comment
Share on other sites

hi carl,

 

no each track is different in its lengths.

this is why i used the SPEEDPERTILE multiplier and then used the progress/delay per car as a relativ value based on percentage.

Link to comment
Share on other sites

Is there a reason you don't have the wagons using the same length path as suggested by Carl? That solution appears to work perfectly and keeps the wagons synchronised, so it's hard to understand how or why you've introduced different length paths. If all you needed to add was an on-screen start/end point, you could just restrict the times of the timeline like this:

See the Pen Lsgbf?editors=001 by jamiejefferson (@jamiejefferson) on CodePen

 

Could you please provide the requested reduced sample so we can better understand this issue.

Link to comment
Share on other sites

hello and thanks!

 

 

 

Is there a reason you don't have the wagons using the same length path as suggested by Carl?

well the reason for doing so, is that i want the train to have the same speed no matter what the length of the track is.

to do this i introduced the SPEEDPERTILE multiplier. this way the speed stays constant no matter how long the track is.

i hacked up a little simplified example with fixed path values. ( in my original, the tracks get created dynamically and always a little different.

you can click on the switch to see the difference. 
Thanks!

 

 

Link to comment
Share on other sites

Sorry I suppose my Flash cs5 isn't all that up to date :( I think Carl has it so hopefully he can take a look.

Link to comment
Share on other sites

hmm, ok, maybe i produce a version which works with ye olde flash 5 ;)

Link to comment
Share on other sites

hi guys,

i hacked together a new version with external assets.

will work now also with older flash versions.

 

you just need to define the DocumentClass as TrainDemo and add the greensock classes.

 

cheers!

TrainDemo.zip

Link to comment
Share on other sites

Thanks for the polite bump, I had started working on this and then got distracted.

 

You were sooooo close.

 

Replace your buildTimelines method with

 

private function buildTimelines():void{


_timelines=new Array();
for (var i:int = 0 ; i < NUMCARS; i++){


var tl = new TimelineMax();


tl.add(getTrainPartAnimation(i));


//advance each train by a tiny amount and make sure the first car is the farthest away


tl.pause((NUMCARS-i)*0.15);


_timelines.push(tl);
}
};
Link to comment
Share on other sites

Hello Carl, 

 

thanks for your time.

Unfortunately though, this is still not the answer.

When changing the length of the track, the distance between the "wagons" still changes.

with the Value 0.15 and the length of this demo "track" it is barely noticable.

however when you change the values to something a higher it is there.

 

hmm 

Link to comment
Share on other sites

hmm, once you determine the length of your track you can use the duration() of the animation to figure out the speed of each wagon (pixels per second)

Since you know the width of each wagon, you can then figure out how much time it will take to travel the width of one wagon. This is the value that will use as the offset of each wagon's animation.

Link to comment
Share on other sites

hmm, is there anyway TweenMax / TimeLineMax gives me the length of the path?

 

i only found duration() totalDuration() as a time value.

Link to comment
Share on other sites

No, sorry, the BezierPlugin does not provide the length of the path.

Link to comment
Share on other sites

  • 2 weeks later...

For whom it may concern... :)
I came up with an ugly but effective hack as a solution:
 

private const MAXDIST:Number=44;

//and at the end of the buildTimelines function
var car0:Sprite=_train.cars[0]
var car1:Sprite=_train.cars[1] 
//
var delay:Number=0
while (dist(car0.x, car1.x,  car0.y, car1.y)<MAXDIST){
	
	for (i = 0 ; i< _timelines.length; i++){
		delay+=0.00001
	   	var tl=_timelines[i]
	   	tl.progress(1-delay*i).timeScale(0);
		tl.pause();
	}

};
// just a little distance check
function DistanceTwoPoints(x1:Number, x2:Number,  y1:Number, y2:Number):
	    Number {
	    var dx:Number = x1-x2;
	    var dy:Number = y1-y2;
	    return Math.sqrt(dx * dx + dy * dy);
}
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.
×