/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Boat = Container.expand(function () { var self = Container.call(this); var boatGraphics = self.attachAsset('boat', { anchorX: 0.5, anchorY: 0.5 }); self.floatSpeed = 1; self.update = function () { self.x += self.floatSpeed; if (self.x > 2048 + 40) { self.x = -40; } }; return self; }); var Cloud = Container.expand(function () { var self = Container.call(this); var cloudGraphics = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); self.driftSpeed = 0.5; self.update = function () { self.x += self.driftSpeed; if (self.x > 2048 + 60) { self.x = -60; } }; return self; }); var TrackPiece = Container.expand(function () { var self = Container.call(this); var trackGraphics = self.attachAsset('track', { anchorX: 0.5, anchorY: 0.5 }); self.isPlaced = false; return self; }); var Train = Container.expand(function () { var self = Container.call(this); var trainGraphics = self.attachAsset('train', { anchorX: 0.5, anchorY: 0.5 }); self.isMoving = false; self.speed = 3; self.targetX = 0; self.targetY = 0; self.currentTrackIndex = 0; self.down = function (x, y, obj) { if (!self.isMoving && trackPieces.length > 0) { self.isMoving = true; self.currentTrackIndex = 0; self.moveToNextTrack(); } }; self.moveToNextTrack = function () { if (self.currentTrackIndex < trackPieces.length) { var track = trackPieces[self.currentTrackIndex]; self.targetX = track.x; self.targetY = track.y; } else { // Reached the end self.isMoving = false; if (self.targetX >= station.x - 50 && self.targetX <= station.x + 50) { // Reached station LK.effects.flashObject(station, 0x00FF00, 1000); LK.setScore(LK.getScore() + 10); scoreText.setText('Score: ' + LK.getScore()); } } }; self.update = function () { if (self.isMoving && trackPieces.length > 0) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } else { self.currentTrackIndex++; self.moveToNextTrack(); } } }; return self; }); var Whistle = Container.expand(function () { var self = Container.call(this); var whistleGraphics = self.attachAsset('whistle', { anchorX: 0.5, anchorY: 0.5 }); self.down = function (x, y, obj) { LK.getSound('choo').play(); tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200 }); tween(self, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ var trackPieces = []; var clouds = []; var boats = []; var isBuilding = true; var tutorialStep = 0; // Create scenery var river = game.addChild(LK.getAsset('river', { anchorX: 0, anchorY: 0, x: 0, y: 1800 })); var tunnel = game.addChild(LK.getAsset('tunnel', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1200 })); var station = game.addChild(LK.getAsset('station', { anchorX: 0.5, anchorY: 0.5, x: 1700, y: 2400 })); // Create clouds for (var i = 0; i < 5; i++) { var cloud = game.addChild(new Cloud()); cloud.x = Math.random() * 2048; cloud.y = 200 + Math.random() * 300; cloud.driftSpeed = 0.2 + Math.random() * 0.8; clouds.push(cloud); } // Create boats for (var j = 0; j < 3; j++) { var boat = game.addChild(new Boat()); boat.x = Math.random() * 2048; boat.y = 1850; boat.floatSpeed = 0.5 + Math.random() * 1; boats.push(boat); } // Create train var train = game.addChild(new Train()); train.x = 200; train.y = 2200; // Create whistle button var whistle = game.addChild(new Whistle()); whistle.x = 150; whistle.y = 150; // Create UI var scoreText = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); var instructionText = new Text2('Tap to place tracks!', { size: 50, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0); instructionText.y = 80; LK.gui.top.addChild(instructionText); var modeText = new Text2('Building Mode', { size: 40, fill: 0xFFFF00 }); modeText.anchor.set(0.5, 1); LK.gui.bottom.addChild(modeText); // Game event handlers game.down = function (x, y, obj) { if (isBuilding) { // Place track piece var newTrack = game.addChild(new TrackPiece()); newTrack.x = x; newTrack.y = y; newTrack.isPlaced = true; trackPieces.push(newTrack); LK.getSound('place').play(); // Update instruction based on progress if (trackPieces.length === 1) { instructionText.setText('Great! Keep building your track!'); } else if (trackPieces.length === 5) { instructionText.setText('Tap the train to start its journey!'); } else if (trackPieces.length === 10) { instructionText.setText('Build toward the blue station!'); } // Check if player has built enough track if (trackPieces.length >= 3) { modeText.setText('Tap train to start journey!'); } } }; // Main game loop game.update = function () { // Update train movement if (train.isMoving) { // Check if train reached station var distanceToStation = Math.sqrt(Math.pow(train.x - station.x, 2) + Math.pow(train.y - station.y, 2)); if (distanceToStation < 100) { train.isMoving = false; LK.effects.flashScreen(0x00FF00, 500); LK.setScore(LK.getScore() + 50); scoreText.setText('Score: ' + LK.getScore()); instructionText.setText('Train reached station! Tap to build new track!'); // Reset for new round LK.setTimeout(function () { // Clear old tracks for (var i = trackPieces.length - 1; i >= 0; i--) { trackPieces[i].destroy(); } trackPieces = []; // Reset train position train.x = 200; train.y = 2200; train.isMoving = false; train.currentTrackIndex = 0; instructionText.setText('Build a new track!'); modeText.setText('Building Mode'); isBuilding = true; }, 2000); } } // Animate whistle button whistle.y = 150 + Math.sin(LK.ticks * 0.1) * 5; // Update score display if (LK.ticks % 60 === 0) { LK.setScore(LK.getScore() + 1); scoreText.setText('Score: ' + LK.getScore()); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boat = Container.expand(function () {
var self = Container.call(this);
var boatGraphics = self.attachAsset('boat', {
anchorX: 0.5,
anchorY: 0.5
});
self.floatSpeed = 1;
self.update = function () {
self.x += self.floatSpeed;
if (self.x > 2048 + 40) {
self.x = -40;
}
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudGraphics = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
self.driftSpeed = 0.5;
self.update = function () {
self.x += self.driftSpeed;
if (self.x > 2048 + 60) {
self.x = -60;
}
};
return self;
});
var TrackPiece = Container.expand(function () {
var self = Container.call(this);
var trackGraphics = self.attachAsset('track', {
anchorX: 0.5,
anchorY: 0.5
});
self.isPlaced = false;
return self;
});
var Train = Container.expand(function () {
var self = Container.call(this);
var trainGraphics = self.attachAsset('train', {
anchorX: 0.5,
anchorY: 0.5
});
self.isMoving = false;
self.speed = 3;
self.targetX = 0;
self.targetY = 0;
self.currentTrackIndex = 0;
self.down = function (x, y, obj) {
if (!self.isMoving && trackPieces.length > 0) {
self.isMoving = true;
self.currentTrackIndex = 0;
self.moveToNextTrack();
}
};
self.moveToNextTrack = function () {
if (self.currentTrackIndex < trackPieces.length) {
var track = trackPieces[self.currentTrackIndex];
self.targetX = track.x;
self.targetY = track.y;
} else {
// Reached the end
self.isMoving = false;
if (self.targetX >= station.x - 50 && self.targetX <= station.x + 50) {
// Reached station
LK.effects.flashObject(station, 0x00FF00, 1000);
LK.setScore(LK.getScore() + 10);
scoreText.setText('Score: ' + LK.getScore());
}
}
};
self.update = function () {
if (self.isMoving && trackPieces.length > 0) {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
self.currentTrackIndex++;
self.moveToNextTrack();
}
}
};
return self;
});
var Whistle = Container.expand(function () {
var self = Container.call(this);
var whistleGraphics = self.attachAsset('whistle', {
anchorX: 0.5,
anchorY: 0.5
});
self.down = function (x, y, obj) {
LK.getSound('choo').play();
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200
});
tween(self, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var trackPieces = [];
var clouds = [];
var boats = [];
var isBuilding = true;
var tutorialStep = 0;
// Create scenery
var river = game.addChild(LK.getAsset('river', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 1800
}));
var tunnel = game.addChild(LK.getAsset('tunnel', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1200
}));
var station = game.addChild(LK.getAsset('station', {
anchorX: 0.5,
anchorY: 0.5,
x: 1700,
y: 2400
}));
// Create clouds
for (var i = 0; i < 5; i++) {
var cloud = game.addChild(new Cloud());
cloud.x = Math.random() * 2048;
cloud.y = 200 + Math.random() * 300;
cloud.driftSpeed = 0.2 + Math.random() * 0.8;
clouds.push(cloud);
}
// Create boats
for (var j = 0; j < 3; j++) {
var boat = game.addChild(new Boat());
boat.x = Math.random() * 2048;
boat.y = 1850;
boat.floatSpeed = 0.5 + Math.random() * 1;
boats.push(boat);
}
// Create train
var train = game.addChild(new Train());
train.x = 200;
train.y = 2200;
// Create whistle button
var whistle = game.addChild(new Whistle());
whistle.x = 150;
whistle.y = 150;
// Create UI
var scoreText = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var instructionText = new Text2('Tap to place tracks!', {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0);
instructionText.y = 80;
LK.gui.top.addChild(instructionText);
var modeText = new Text2('Building Mode', {
size: 40,
fill: 0xFFFF00
});
modeText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(modeText);
// Game event handlers
game.down = function (x, y, obj) {
if (isBuilding) {
// Place track piece
var newTrack = game.addChild(new TrackPiece());
newTrack.x = x;
newTrack.y = y;
newTrack.isPlaced = true;
trackPieces.push(newTrack);
LK.getSound('place').play();
// Update instruction based on progress
if (trackPieces.length === 1) {
instructionText.setText('Great! Keep building your track!');
} else if (trackPieces.length === 5) {
instructionText.setText('Tap the train to start its journey!');
} else if (trackPieces.length === 10) {
instructionText.setText('Build toward the blue station!');
}
// Check if player has built enough track
if (trackPieces.length >= 3) {
modeText.setText('Tap train to start journey!');
}
}
};
// Main game loop
game.update = function () {
// Update train movement
if (train.isMoving) {
// Check if train reached station
var distanceToStation = Math.sqrt(Math.pow(train.x - station.x, 2) + Math.pow(train.y - station.y, 2));
if (distanceToStation < 100) {
train.isMoving = false;
LK.effects.flashScreen(0x00FF00, 500);
LK.setScore(LK.getScore() + 50);
scoreText.setText('Score: ' + LK.getScore());
instructionText.setText('Train reached station! Tap to build new track!');
// Reset for new round
LK.setTimeout(function () {
// Clear old tracks
for (var i = trackPieces.length - 1; i >= 0; i--) {
trackPieces[i].destroy();
}
trackPieces = [];
// Reset train position
train.x = 200;
train.y = 2200;
train.isMoving = false;
train.currentTrackIndex = 0;
instructionText.setText('Build a new track!');
modeText.setText('Building Mode');
isBuilding = true;
}, 2000);
}
}
// Animate whistle button
whistle.y = 150 + Math.sin(LK.ticks * 0.1) * 5;
// Update score display
if (LK.ticks % 60 === 0) {
LK.setScore(LK.getScore() + 1);
scoreText.setText('Score: ' + LK.getScore());
}
};