Train Game: 2D Object On Path

Next in this series of tutorials comes the creation of the LinePath and the addition of the Train object. For now I’ll use 2D points for the path, but later I might change this to Vector3D elements. But here is the final result up to this point in the 2D logic:

Click on the Turn Buttons to Change the Path

I added the two classes for the LinePath logic, the same ones I've used in previous tutorials: PathPoint and LinePath2D. These were taken from Greensock's Tween engine and thoroughly butchered by me.

And then I added two more classes: Train and Car.

Inside the Main Document class the main differences are that now I have a _train object, and at the end of the trackPath method I pass this _train object the points collected in the current path.

 
len = _path.length;
 
for (i = 0; i < len; i++) {
 
 
 
	if (_path[i].point) {
 
		_pathPoints.push(_path[i].point);
 
 
 
		if (i == len - 1) {
 
			_pathPoints.push(_path[i].getExtraPoint());
 
		}
 
	}
 
 
 
}
 
 
 
_train.setTrack(_pathPoints);

The getExtraPoint method is used in the final tile of the path to force the Train to traverse the final tile and it's here merely for aesthetic reasons.

The Train object then grabs these points and use them to create a LinePath2D object the individual cars will follow.

Dealing with "Progress"

There are two parts in the code where people might get lost, and this assumption is based on the amount of trouble people have had in previous tutorials using paths. These troublesome areas have to do with converting pixels to progress percentage.

To explain the first one, take a look at this image:

A and B represent two paths. The circle represents an object moving along the paths, with the same speed in both cases.

Now notice that in both cases the circle is at the same distance from the beginning of the path. But in terms of progress, the two are different. In path A the circle has a larger progress because it has traversed, percent-wise, more of the path than in path B. So in the game when an object is travelling on a path, and this path is then changed (either increased or decreased) you must readjust the progress of the object. And here is the method that does that, inside the Train object:

private function updateSpeedAndProgress ():void {
 
	var iterations:int = _linePath.totalLength/_speed;
 
	_speedOnPath = 1/iterations;
 
 
 
	if (_oldLength != 0) {
 
 
 
		_progress = (_oldLength * _oldProgress) / _linePath.totalLength;
 
 
 
		var len:int = _cars.length;
 
		for (var i:int = 0; i < 1; i++) {
 
			_linePath.renderObjectAt(_cars[i].skin, _progress);
 
		}
 
	}
 
 
 
	_oldLength = _linePath.totalLength;
 
	_oldProgress = _progress;
 
	_gapInPercentage = _gapInPixels / _linePath.totalLength;
 
 
 
}

I must change the speed as well, since when paths are concerned movement is done through percentage and not pixels. And the percentage value of speed changes with the total length of the path as well as the current progress. (You might also notice I update the value for something called _gapInPercentage... so read on)

The second spot in the logic where this transformation of values might seem weird is in relation to the distance between the various cars. Take a look at this image:

Now I have a distance (width) in pixels being represented inside each path by the gray rectangle. But remember I must use percentage and not pixels, so in each case I must calculate what that width represents in each path percent-wise, so that I can keep the train cars apart always with the same gap between them.

The rest of the code is pretty straightforward. The main loop will update progress inside the path which will move each train car along. When the train reached the end of the path, when progress equals 1, I track to see if the train has reached the target end of the track, or a bomb, or if it got stuck somewhere in between.

Then there is the addition of various conditions related to gameplay, like for instance a button becomes inactive if the train is too close to it, or has already moved past it. But all these conditions are pretty logical and simple to follow in the code.

Next I will post the code that creates the 3D train.