/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
carsUnlocked: 1
});
/****
* Classes
****/
var Car = Container.expand(function () {
var self = Container.call(this);
// Properties
self.velocity = {
x: 0,
y: 0
};
self.speed = 0;
self.maxSpeed = 15;
self.acceleration = 0.2;
self.deceleration = 0.1;
self.direction = 0; // Angle in radians
self.drifting = false;
self.driftDirection = 0;
self.driftPower = 0.5;
self.driftFactor = 0;
self.steeringPower = 0.05;
self.turningRadius = 0.04;
// Graphics
var carGraphics = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
// Trail container to hold drift trails
self.trailContainer = new Container();
self.addChild(self.trailContainer);
// Drift trail particles
self.trailParticles = [];
// Methods
self.accelerate = function () {
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
if (self.speed > self.maxSpeed) {
self.speed = self.maxSpeed;
}
}
};
self.decelerate = function () {
if (self.speed > 0) {
self.speed -= self.deceleration;
if (self.speed < 0) {
self.speed = 0;
}
}
};
self.startDrift = function (direction) {
self.drifting = true;
self.driftDirection = direction;
LK.getSound('drift').play();
};
self.stopDrift = function () {
self.drifting = false;
self.driftFactor = 0;
};
self.addTrailParticle = function () {
if (self.speed > 1 && self.drifting) {
var trail = LK.getAsset('driftTrail', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
trail.x = 0;
trail.y = 0;
self.trailContainer.addChild(trail);
// Store the global position for this trail particle
var globalPos = self.trailContainer.toGlobal({
x: 0,
y: 0
});
trail.globalX = globalPos.x;
trail.globalY = globalPos.y;
self.trailParticles.push(trail);
// Fade out the trail particle
tween(trail, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
if (trail.parent) {
trail.parent.removeChild(trail);
}
var index = self.trailParticles.indexOf(trail);
if (index !== -1) {
self.trailParticles.splice(index, 1);
}
}
});
}
};
self.update = function () {
// Apply physics
if (self.drifting) {
self.driftFactor = Math.min(1, self.driftFactor + 0.05);
self.direction += self.driftDirection * self.driftPower * self.driftFactor;
// Add trail particles at a rate based on speed
if (LK.ticks % Math.max(1, Math.floor(10 / self.speed)) === 0) {
self.addTrailParticle();
}
} else {
// Normal steering
self.direction += self.driftDirection * self.steeringPower;
}
// Update velocity based on speed and direction
self.velocity.x = Math.sin(self.direction) * self.speed;
self.velocity.y = -Math.cos(self.direction) * self.speed;
// Apply velocity to position
self.x += self.velocity.x;
self.y += self.velocity.y;
// Set rotation to match direction
carGraphics.rotation = self.direction;
// Natural speed decay
self.decelerate();
// Update position of trail container
self.trailContainer.x = -self.x;
self.trailContainer.y = -self.y;
};
return self;
});
var ScorePopup = Container.expand(function (value, x, y) {
var self = Container.call(this);
// Create the popup
var popup = self.attachAsset('scorePopup', {
anchorX: 0.5,
anchorY: 0.5
});
// Add score text
var scoreText = new Text2("+" + value, {
size: 40,
fill: 0x000000
});
scoreText.anchor.set(0.5, 0.5);
self.addChild(scoreText);
// Set initial position
self.x = x;
self.y = y;
// Animate the popup
tween(self, {
y: y - 100,
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
return self;
});
var Track = Container.expand(function () {
var self = Container.call(this);
// Track background
var trackBackground = self.attachAsset('track', {
anchorX: 0.5,
anchorY: 0.5
});
// Track elements
self.borders = [];
self.checkpoints = [];
self.corners = [];
// Create track layout
self.createTrack = function (level) {
// Clear existing track elements
for (var i = 0; i < self.borders.length; i++) {
self.removeChild(self.borders[i]);
}
self.borders = [];
for (var i = 0; i < self.checkpoints.length; i++) {
self.removeChild(self.checkpoints[i]);
}
self.checkpoints = [];
for (var i = 0; i < self.corners.length; i++) {
self.removeChild(self.corners[i]);
}
self.corners = [];
// Track width and height
var trackWidth = trackBackground.width;
var trackHeight = trackBackground.height;
// Create border walls
// Top border
var topBorder = self.createBorder(0, -trackHeight / 2, trackWidth, 50);
// Bottom border
var bottomBorder = self.createBorder(0, trackHeight / 2, trackWidth, 50);
// Left border
var leftBorder = self.createBorder(-trackWidth / 2, 0, 50, trackHeight);
// Right border
var rightBorder = self.createBorder(trackWidth / 2, 0, 50, trackHeight);
// Add obstacles based on level
if (level >= 1) {
// Center obstacle
self.createBorder(0, 0, 500, 100);
// Create checkpoints
self.createCheckpoint(-trackWidth / 4, -trackHeight / 4, 0, 200, 50);
self.createCheckpoint(trackWidth / 4, trackHeight / 4, Math.PI / 2, 200, 50);
// Create corners for drift points
self.createCorner(-trackWidth / 4, trackHeight / 4, 300);
self.createCorner(trackWidth / 4, -trackHeight / 4, 300);
}
if (level >= 2) {
// Add more obstacles
self.createBorder(-trackWidth / 4, -trackHeight / 3, 100, 400);
self.createBorder(trackWidth / 4, trackHeight / 3, 100, 400);
// Additional checkpoints
self.createCheckpoint(0, trackHeight / 3, Math.PI, 200, 50);
self.createCheckpoint(0, -trackHeight / 3, 0, 200, 50);
// More corners
self.createCorner(-trackWidth / 3, 0, 250);
self.createCorner(trackWidth / 3, 0, 250);
}
};
self.createBorder = function (x, y, width, height) {
var border = LK.getAsset('trackBorder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: width / 50,
scaleY: height / 50
});
border.x = x;
border.y = y;
border.width = width;
border.height = height;
self.addChild(border);
self.borders.push(border);
return border;
};
self.createCheckpoint = function (x, y, rotation, width, height) {
var checkpoint = LK.getAsset('checkpoint', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: width / 200,
scaleY: height / 50,
alpha: 0.7
});
checkpoint.x = x;
checkpoint.y = y;
checkpoint.rotation = rotation;
checkpoint.width = width;
checkpoint.height = height;
checkpoint.passed = false;
self.addChild(checkpoint);
self.checkpoints.push(checkpoint);
return checkpoint;
};
self.createCorner = function (x, y, size) {
var corner = LK.getAsset('corner', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: size / 300,
scaleY: size / 300,
alpha: 0.3
});
corner.x = x;
corner.y = y;
corner.size = size;
self.addChild(corner);
self.corners.push(corner);
return corner;
};
// Check collision between car and track elements
self.checkCollisions = function (car) {
// Check border collisions
for (var i = 0; i < self.borders.length; i++) {
if (car.intersects(self.borders[i])) {
return {
type: 'border',
element: self.borders[i]
};
}
}
// Check checkpoint collisions
for (var i = 0; i < self.checkpoints.length; i++) {
if (!self.checkpoints[i].passed && car.intersects(self.checkpoints[i])) {
self.checkpoints[i].passed = true;
return {
type: 'checkpoint',
element: self.checkpoints[i]
};
}
}
// Check if in corner for drift points
for (var i = 0; i < self.corners.length; i++) {
if (car.intersects(self.corners[i])) {
return {
type: 'corner',
element: self.corners[i]
};
}
}
return null;
};
// Check if all checkpoints have been passed
self.allCheckpointsPassed = function () {
for (var i = 0; i < self.checkpoints.length; i++) {
if (!self.checkpoints[i].passed) {
return false;
}
}
return self.checkpoints.length > 0;
};
// Reset checkpoints
self.resetCheckpoints = function () {
for (var i = 0; i < self.checkpoints.length; i++) {
self.checkpoints[i].passed = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x008080
});
/****
* Game Code
****/
// Music
// Sounds
// Game feedback
// Drift trail
// Track elements
// Car
// Game state
var gameState = 'ready'; // ready, playing, gameover
var currentLevel = 1;
var score = 0;
var highScore = storage.highScore || 0;
var driftScore = 0;
var driftMultiplier = 1;
var driftCombo = 0;
var lastDriftTime = 0;
var checkpointValue = 100;
var car;
var track;
var swipeStartX = 0;
var swipeStartY = 0;
var touchStart = false;
// UI Elements
var scoreText = new Text2("SCORE: 0", {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0, 0);
LK.gui.topRight.addChild(scoreText);
scoreText.x = -200;
scoreText.y = 20;
var highScoreText = new Text2("BEST: " + highScore, {
size: 30,
fill: 0xCCCCCC
});
highScoreText.anchor.set(0, 0);
LK.gui.topRight.addChild(highScoreText);
highScoreText.x = -200;
highScoreText.y = 80;
var multiplierText = new Text2("x1", {
size: 60,
fill: 0xFFCC00
});
multiplierText.anchor.set(0.5, 0.5);
multiplierText.alpha = 0;
LK.gui.center.addChild(multiplierText);
var instructionText = new Text2("TAP to accelerate\nSWIPE to drift", {
size: 50,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionText);
instructionText.y = 300;
// Initialize the game
function initGame() {
// Reset game state
gameState = 'ready';
score = 0;
driftScore = 0;
driftMultiplier = 1;
driftCombo = 0;
// Update UI
updateScoreText();
multiplierText.alpha = 0;
instructionText.alpha = 1;
// Create track
if (!track) {
track = new Track();
game.addChild(track);
}
track.createTrack(currentLevel);
// Create car
if (!car) {
car = new Car();
game.addChild(car);
}
// Reset car position
car.x = 0;
car.y = 0;
car.speed = 0;
car.direction = 0;
car.drifting = false;
car.driftDirection = 0;
car.driftFactor = 0;
// Clear all trail particles
for (var i = 0; i < car.trailParticles.length; i++) {
if (car.trailParticles[i].parent) {
car.trailParticles[i].parent.removeChild(car.trailParticles[i]);
}
}
car.trailParticles = [];
// Play music
LK.playMusic('bgmusic');
}
// Update the score display
function updateScoreText() {
scoreText.setText("SCORE: " + score);
highScoreText.setText("BEST: " + highScore);
}
// Create a score popup
function createScorePopup(value, x, y) {
var popup = new ScorePopup(value, x, y);
game.addChild(popup);
}
// Handle drift scoring
function handleDriftPoints() {
// Check if still drifting
if (car.drifting && car.speed > 5) {
// Check time since last drift point
var currentTime = Date.now();
var timeDiff = currentTime - lastDriftTime;
// Add drift points every 500ms while drifting
if (timeDiff >= 500) {
lastDriftTime = currentTime;
// Calculate points based on speed and drift factor
var points = Math.floor(car.speed * car.driftFactor * driftMultiplier);
// Bonus for drifting in a corner
var collision = track.checkCollisions(car);
if (collision && collision.type === 'corner') {
points *= 2;
}
// Add points to score
if (points > 0) {
score += points;
createScorePopup(points, car.x, car.y);
// Increase combo
driftCombo++;
// Update multiplier based on combo
driftMultiplier = Math.min(5, 1 + Math.floor(driftCombo / 3));
// Show multiplier
multiplierText.setText("x" + driftMultiplier);
multiplierText.alpha = 1;
tween.stop(multiplierText);
tween(multiplierText, {
scale: 1.3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(multiplierText, {
scale: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
}
} else if (!car.drifting && driftCombo > 0) {
// Reset combo when not drifting
driftCombo = 0;
driftMultiplier = 1;
// Hide multiplier
tween(multiplierText, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut
});
}
}
// Handle checkpoint scoring
function handleCheckpoint() {
var points = checkpointValue * driftMultiplier;
score += points;
createScorePopup(points, car.x, car.y);
LK.getSound('checkpoint').play();
// Flash the checkpoint text
var checkpointScoreText = new Text2("CHECKPOINT: +" + points, {
size: 60,
fill: 0xFFCC00
});
checkpointScoreText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(checkpointScoreText);
checkpointScoreText.y = -200;
tween(checkpointScoreText, {
y: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(checkpointScoreText, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
if (checkpointScoreText.parent) {
checkpointScoreText.parent.removeChild(checkpointScoreText);
}
}
});
}
});
// Check if all checkpoints are passed
if (track.allCheckpointsPassed()) {
// Level complete!
var levelCompleteText = new Text2("LEVEL COMPLETE!", {
size: 80,
fill: 0xFFCC00
});
levelCompleteText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(levelCompleteText);
// Animate the level complete text
tween(levelCompleteText, {
scale: 1.5
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(levelCompleteText, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
if (levelCompleteText.parent) {
levelCompleteText.parent.removeChild(levelCompleteText);
}
// Advance to next level
currentLevel++;
track.createTrack(currentLevel);
track.resetCheckpoints();
}
});
}
});
}
}
// Handle game over
function gameOver() {
gameState = 'gameover';
// Update high score if necessary
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
updateScoreText();
}
// Show game over
LK.showGameOver();
}
// Game initialization
initGame();
// Event handlers
game.down = function (x, y, obj) {
if (gameState === 'ready') {
gameState = 'playing';
instructionText.alpha = 0;
}
if (gameState === 'playing') {
// Start acceleration
car.accelerate();
// Store start position for swipe detection
swipeStartX = x;
swipeStartY = y;
touchStart = true;
// Play engine sound
LK.getSound('engine').play();
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing') {
// Stop drifting when releasing
car.stopDrift();
touchStart = false;
}
};
game.move = function (x, y, obj) {
if (gameState === 'playing' && touchStart) {
// Calculate swipe direction and magnitude
var deltaX = x - swipeStartX;
var deltaY = y - swipeStartY;
var swipeMagnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Only register as a swipe if the magnitude is significant
if (swipeMagnitude > 30) {
// Determine drift direction based on swipe direction
var swipeDirection = Math.atan2(deltaY, deltaX);
// Simplified direction determination (left or right)
var driftDir = 0;
// Compare swipe angle to car direction to determine if it's a left or right drift
var angleDiff = swipeDirection - car.direction;
// Normalize angle to -PI to PI
while (angleDiff > Math.PI) {
angleDiff -= Math.PI * 2;
}
while (angleDiff < -Math.PI) {
angleDiff += Math.PI * 2;
}
if (angleDiff > 0) {
driftDir = 1; // Right drift
} else {
driftDir = -1; // Left drift
}
// Start drifting in the determined direction
car.startDrift(driftDir);
// Reset drift time tracking
lastDriftTime = Date.now();
}
}
};
// Main game loop
game.update = function () {
if (gameState === 'playing') {
// Update car physics
car.update();
// Check collisions
var collision = track.checkCollisions(car);
if (collision) {
if (collision.type === 'border') {
// Hit a wall - game over
gameOver();
} else if (collision.type === 'checkpoint' && !collision.element.passed) {
// Passed checkpoint
handleCheckpoint();
}
// Corner collisions are handled in the drift scoring
}
// Handle drift scoring
handleDriftPoints();
// Update score display
updateScoreText();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,656 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0,
+ carsUnlocked: 1
+});
+
+/****
+* Classes
+****/
+var Car = Container.expand(function () {
+ var self = Container.call(this);
+ // Properties
+ self.velocity = {
+ x: 0,
+ y: 0
+ };
+ self.speed = 0;
+ self.maxSpeed = 15;
+ self.acceleration = 0.2;
+ self.deceleration = 0.1;
+ self.direction = 0; // Angle in radians
+ self.drifting = false;
+ self.driftDirection = 0;
+ self.driftPower = 0.5;
+ self.driftFactor = 0;
+ self.steeringPower = 0.05;
+ self.turningRadius = 0.04;
+ // Graphics
+ var carGraphics = self.attachAsset('car', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.5,
+ scaleY: 0.5
+ });
+ // Trail container to hold drift trails
+ self.trailContainer = new Container();
+ self.addChild(self.trailContainer);
+ // Drift trail particles
+ self.trailParticles = [];
+ // Methods
+ self.accelerate = function () {
+ if (self.speed < self.maxSpeed) {
+ self.speed += self.acceleration;
+ if (self.speed > self.maxSpeed) {
+ self.speed = self.maxSpeed;
+ }
+ }
+ };
+ self.decelerate = function () {
+ if (self.speed > 0) {
+ self.speed -= self.deceleration;
+ if (self.speed < 0) {
+ self.speed = 0;
+ }
+ }
+ };
+ self.startDrift = function (direction) {
+ self.drifting = true;
+ self.driftDirection = direction;
+ LK.getSound('drift').play();
+ };
+ self.stopDrift = function () {
+ self.drifting = false;
+ self.driftFactor = 0;
+ };
+ self.addTrailParticle = function () {
+ if (self.speed > 1 && self.drifting) {
+ var trail = LK.getAsset('driftTrail', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ alpha: 0.7
+ });
+ trail.x = 0;
+ trail.y = 0;
+ self.trailContainer.addChild(trail);
+ // Store the global position for this trail particle
+ var globalPos = self.trailContainer.toGlobal({
+ x: 0,
+ y: 0
+ });
+ trail.globalX = globalPos.x;
+ trail.globalY = globalPos.y;
+ self.trailParticles.push(trail);
+ // Fade out the trail particle
+ tween(trail, {
+ alpha: 0
+ }, {
+ duration: 1000,
+ onFinish: function onFinish() {
+ if (trail.parent) {
+ trail.parent.removeChild(trail);
+ }
+ var index = self.trailParticles.indexOf(trail);
+ if (index !== -1) {
+ self.trailParticles.splice(index, 1);
+ }
+ }
+ });
+ }
+ };
+ self.update = function () {
+ // Apply physics
+ if (self.drifting) {
+ self.driftFactor = Math.min(1, self.driftFactor + 0.05);
+ self.direction += self.driftDirection * self.driftPower * self.driftFactor;
+ // Add trail particles at a rate based on speed
+ if (LK.ticks % Math.max(1, Math.floor(10 / self.speed)) === 0) {
+ self.addTrailParticle();
+ }
+ } else {
+ // Normal steering
+ self.direction += self.driftDirection * self.steeringPower;
+ }
+ // Update velocity based on speed and direction
+ self.velocity.x = Math.sin(self.direction) * self.speed;
+ self.velocity.y = -Math.cos(self.direction) * self.speed;
+ // Apply velocity to position
+ self.x += self.velocity.x;
+ self.y += self.velocity.y;
+ // Set rotation to match direction
+ carGraphics.rotation = self.direction;
+ // Natural speed decay
+ self.decelerate();
+ // Update position of trail container
+ self.trailContainer.x = -self.x;
+ self.trailContainer.y = -self.y;
+ };
+ return self;
+});
+var ScorePopup = Container.expand(function (value, x, y) {
+ var self = Container.call(this);
+ // Create the popup
+ var popup = self.attachAsset('scorePopup', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Add score text
+ var scoreText = new Text2("+" + value, {
+ size: 40,
+ fill: 0x000000
+ });
+ scoreText.anchor.set(0.5, 0.5);
+ self.addChild(scoreText);
+ // Set initial position
+ self.x = x;
+ self.y = y;
+ // Animate the popup
+ tween(self, {
+ y: y - 100,
+ alpha: 0
+ }, {
+ duration: 1000,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ }
+ });
+ return self;
+});
+var Track = Container.expand(function () {
+ var self = Container.call(this);
+ // Track background
+ var trackBackground = self.attachAsset('track', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Track elements
+ self.borders = [];
+ self.checkpoints = [];
+ self.corners = [];
+ // Create track layout
+ self.createTrack = function (level) {
+ // Clear existing track elements
+ for (var i = 0; i < self.borders.length; i++) {
+ self.removeChild(self.borders[i]);
+ }
+ self.borders = [];
+ for (var i = 0; i < self.checkpoints.length; i++) {
+ self.removeChild(self.checkpoints[i]);
+ }
+ self.checkpoints = [];
+ for (var i = 0; i < self.corners.length; i++) {
+ self.removeChild(self.corners[i]);
+ }
+ self.corners = [];
+ // Track width and height
+ var trackWidth = trackBackground.width;
+ var trackHeight = trackBackground.height;
+ // Create border walls
+ // Top border
+ var topBorder = self.createBorder(0, -trackHeight / 2, trackWidth, 50);
+ // Bottom border
+ var bottomBorder = self.createBorder(0, trackHeight / 2, trackWidth, 50);
+ // Left border
+ var leftBorder = self.createBorder(-trackWidth / 2, 0, 50, trackHeight);
+ // Right border
+ var rightBorder = self.createBorder(trackWidth / 2, 0, 50, trackHeight);
+ // Add obstacles based on level
+ if (level >= 1) {
+ // Center obstacle
+ self.createBorder(0, 0, 500, 100);
+ // Create checkpoints
+ self.createCheckpoint(-trackWidth / 4, -trackHeight / 4, 0, 200, 50);
+ self.createCheckpoint(trackWidth / 4, trackHeight / 4, Math.PI / 2, 200, 50);
+ // Create corners for drift points
+ self.createCorner(-trackWidth / 4, trackHeight / 4, 300);
+ self.createCorner(trackWidth / 4, -trackHeight / 4, 300);
+ }
+ if (level >= 2) {
+ // Add more obstacles
+ self.createBorder(-trackWidth / 4, -trackHeight / 3, 100, 400);
+ self.createBorder(trackWidth / 4, trackHeight / 3, 100, 400);
+ // Additional checkpoints
+ self.createCheckpoint(0, trackHeight / 3, Math.PI, 200, 50);
+ self.createCheckpoint(0, -trackHeight / 3, 0, 200, 50);
+ // More corners
+ self.createCorner(-trackWidth / 3, 0, 250);
+ self.createCorner(trackWidth / 3, 0, 250);
+ }
+ };
+ self.createBorder = function (x, y, width, height) {
+ var border = LK.getAsset('trackBorder', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: width / 50,
+ scaleY: height / 50
+ });
+ border.x = x;
+ border.y = y;
+ border.width = width;
+ border.height = height;
+ self.addChild(border);
+ self.borders.push(border);
+ return border;
+ };
+ self.createCheckpoint = function (x, y, rotation, width, height) {
+ var checkpoint = LK.getAsset('checkpoint', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: width / 200,
+ scaleY: height / 50,
+ alpha: 0.7
+ });
+ checkpoint.x = x;
+ checkpoint.y = y;
+ checkpoint.rotation = rotation;
+ checkpoint.width = width;
+ checkpoint.height = height;
+ checkpoint.passed = false;
+ self.addChild(checkpoint);
+ self.checkpoints.push(checkpoint);
+ return checkpoint;
+ };
+ self.createCorner = function (x, y, size) {
+ var corner = LK.getAsset('corner', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: size / 300,
+ scaleY: size / 300,
+ alpha: 0.3
+ });
+ corner.x = x;
+ corner.y = y;
+ corner.size = size;
+ self.addChild(corner);
+ self.corners.push(corner);
+ return corner;
+ };
+ // Check collision between car and track elements
+ self.checkCollisions = function (car) {
+ // Check border collisions
+ for (var i = 0; i < self.borders.length; i++) {
+ if (car.intersects(self.borders[i])) {
+ return {
+ type: 'border',
+ element: self.borders[i]
+ };
+ }
+ }
+ // Check checkpoint collisions
+ for (var i = 0; i < self.checkpoints.length; i++) {
+ if (!self.checkpoints[i].passed && car.intersects(self.checkpoints[i])) {
+ self.checkpoints[i].passed = true;
+ return {
+ type: 'checkpoint',
+ element: self.checkpoints[i]
+ };
+ }
+ }
+ // Check if in corner for drift points
+ for (var i = 0; i < self.corners.length; i++) {
+ if (car.intersects(self.corners[i])) {
+ return {
+ type: 'corner',
+ element: self.corners[i]
+ };
+ }
+ }
+ return null;
+ };
+ // Check if all checkpoints have been passed
+ self.allCheckpointsPassed = function () {
+ for (var i = 0; i < self.checkpoints.length; i++) {
+ if (!self.checkpoints[i].passed) {
+ return false;
+ }
+ }
+ return self.checkpoints.length > 0;
+ };
+ // Reset checkpoints
+ self.resetCheckpoints = function () {
+ for (var i = 0; i < self.checkpoints.length; i++) {
+ self.checkpoints[i].passed = false;
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x008080
+});
+
+/****
+* Game Code
+****/
+// Music
+// Sounds
+// Game feedback
+// Drift trail
+// Track elements
+// Car
+// Game state
+var gameState = 'ready'; // ready, playing, gameover
+var currentLevel = 1;
+var score = 0;
+var highScore = storage.highScore || 0;
+var driftScore = 0;
+var driftMultiplier = 1;
+var driftCombo = 0;
+var lastDriftTime = 0;
+var checkpointValue = 100;
+var car;
+var track;
+var swipeStartX = 0;
+var swipeStartY = 0;
+var touchStart = false;
+// UI Elements
+var scoreText = new Text2("SCORE: 0", {
+ size: 50,
+ fill: 0xFFFFFF
+});
+scoreText.anchor.set(0, 0);
+LK.gui.topRight.addChild(scoreText);
+scoreText.x = -200;
+scoreText.y = 20;
+var highScoreText = new Text2("BEST: " + highScore, {
+ size: 30,
+ fill: 0xCCCCCC
+});
+highScoreText.anchor.set(0, 0);
+LK.gui.topRight.addChild(highScoreText);
+highScoreText.x = -200;
+highScoreText.y = 80;
+var multiplierText = new Text2("x1", {
+ size: 60,
+ fill: 0xFFCC00
+});
+multiplierText.anchor.set(0.5, 0.5);
+multiplierText.alpha = 0;
+LK.gui.center.addChild(multiplierText);
+var instructionText = new Text2("TAP to accelerate\nSWIPE to drift", {
+ size: 50,
+ fill: 0xFFFFFF
+});
+instructionText.anchor.set(0.5, 0.5);
+LK.gui.center.addChild(instructionText);
+instructionText.y = 300;
+// Initialize the game
+function initGame() {
+ // Reset game state
+ gameState = 'ready';
+ score = 0;
+ driftScore = 0;
+ driftMultiplier = 1;
+ driftCombo = 0;
+ // Update UI
+ updateScoreText();
+ multiplierText.alpha = 0;
+ instructionText.alpha = 1;
+ // Create track
+ if (!track) {
+ track = new Track();
+ game.addChild(track);
+ }
+ track.createTrack(currentLevel);
+ // Create car
+ if (!car) {
+ car = new Car();
+ game.addChild(car);
+ }
+ // Reset car position
+ car.x = 0;
+ car.y = 0;
+ car.speed = 0;
+ car.direction = 0;
+ car.drifting = false;
+ car.driftDirection = 0;
+ car.driftFactor = 0;
+ // Clear all trail particles
+ for (var i = 0; i < car.trailParticles.length; i++) {
+ if (car.trailParticles[i].parent) {
+ car.trailParticles[i].parent.removeChild(car.trailParticles[i]);
+ }
+ }
+ car.trailParticles = [];
+ // Play music
+ LK.playMusic('bgmusic');
+}
+// Update the score display
+function updateScoreText() {
+ scoreText.setText("SCORE: " + score);
+ highScoreText.setText("BEST: " + highScore);
+}
+// Create a score popup
+function createScorePopup(value, x, y) {
+ var popup = new ScorePopup(value, x, y);
+ game.addChild(popup);
+}
+// Handle drift scoring
+function handleDriftPoints() {
+ // Check if still drifting
+ if (car.drifting && car.speed > 5) {
+ // Check time since last drift point
+ var currentTime = Date.now();
+ var timeDiff = currentTime - lastDriftTime;
+ // Add drift points every 500ms while drifting
+ if (timeDiff >= 500) {
+ lastDriftTime = currentTime;
+ // Calculate points based on speed and drift factor
+ var points = Math.floor(car.speed * car.driftFactor * driftMultiplier);
+ // Bonus for drifting in a corner
+ var collision = track.checkCollisions(car);
+ if (collision && collision.type === 'corner') {
+ points *= 2;
+ }
+ // Add points to score
+ if (points > 0) {
+ score += points;
+ createScorePopup(points, car.x, car.y);
+ // Increase combo
+ driftCombo++;
+ // Update multiplier based on combo
+ driftMultiplier = Math.min(5, 1 + Math.floor(driftCombo / 3));
+ // Show multiplier
+ multiplierText.setText("x" + driftMultiplier);
+ multiplierText.alpha = 1;
+ tween.stop(multiplierText);
+ tween(multiplierText, {
+ scale: 1.3
+ }, {
+ duration: 200,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(multiplierText, {
+ scale: 1
+ }, {
+ duration: 200,
+ easing: tween.easeIn
+ });
+ }
+ });
+ }
+ }
+ } else if (!car.drifting && driftCombo > 0) {
+ // Reset combo when not drifting
+ driftCombo = 0;
+ driftMultiplier = 1;
+ // Hide multiplier
+ tween(multiplierText, {
+ alpha: 0
+ }, {
+ duration: 500,
+ easing: tween.easeOut
+ });
+ }
+}
+// Handle checkpoint scoring
+function handleCheckpoint() {
+ var points = checkpointValue * driftMultiplier;
+ score += points;
+ createScorePopup(points, car.x, car.y);
+ LK.getSound('checkpoint').play();
+ // Flash the checkpoint text
+ var checkpointScoreText = new Text2("CHECKPOINT: +" + points, {
+ size: 60,
+ fill: 0xFFCC00
+ });
+ checkpointScoreText.anchor.set(0.5, 0.5);
+ LK.gui.center.addChild(checkpointScoreText);
+ checkpointScoreText.y = -200;
+ tween(checkpointScoreText, {
+ y: 0
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(checkpointScoreText, {
+ alpha: 0
+ }, {
+ duration: 1000,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ if (checkpointScoreText.parent) {
+ checkpointScoreText.parent.removeChild(checkpointScoreText);
+ }
+ }
+ });
+ }
+ });
+ // Check if all checkpoints are passed
+ if (track.allCheckpointsPassed()) {
+ // Level complete!
+ var levelCompleteText = new Text2("LEVEL COMPLETE!", {
+ size: 80,
+ fill: 0xFFCC00
+ });
+ levelCompleteText.anchor.set(0.5, 0.5);
+ LK.gui.center.addChild(levelCompleteText);
+ // Animate the level complete text
+ tween(levelCompleteText, {
+ scale: 1.5
+ }, {
+ duration: 1000,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(levelCompleteText, {
+ alpha: 0
+ }, {
+ duration: 1000,
+ easing: tween.easeIn,
+ onFinish: function onFinish() {
+ if (levelCompleteText.parent) {
+ levelCompleteText.parent.removeChild(levelCompleteText);
+ }
+ // Advance to next level
+ currentLevel++;
+ track.createTrack(currentLevel);
+ track.resetCheckpoints();
+ }
+ });
+ }
+ });
+ }
+}
+// Handle game over
+function gameOver() {
+ gameState = 'gameover';
+ // Update high score if necessary
+ if (score > highScore) {
+ highScore = score;
+ storage.highScore = highScore;
+ updateScoreText();
+ }
+ // Show game over
+ LK.showGameOver();
+}
+// Game initialization
+initGame();
+// Event handlers
+game.down = function (x, y, obj) {
+ if (gameState === 'ready') {
+ gameState = 'playing';
+ instructionText.alpha = 0;
+ }
+ if (gameState === 'playing') {
+ // Start acceleration
+ car.accelerate();
+ // Store start position for swipe detection
+ swipeStartX = x;
+ swipeStartY = y;
+ touchStart = true;
+ // Play engine sound
+ LK.getSound('engine').play();
+ }
+};
+game.up = function (x, y, obj) {
+ if (gameState === 'playing') {
+ // Stop drifting when releasing
+ car.stopDrift();
+ touchStart = false;
+ }
+};
+game.move = function (x, y, obj) {
+ if (gameState === 'playing' && touchStart) {
+ // Calculate swipe direction and magnitude
+ var deltaX = x - swipeStartX;
+ var deltaY = y - swipeStartY;
+ var swipeMagnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
+ // Only register as a swipe if the magnitude is significant
+ if (swipeMagnitude > 30) {
+ // Determine drift direction based on swipe direction
+ var swipeDirection = Math.atan2(deltaY, deltaX);
+ // Simplified direction determination (left or right)
+ var driftDir = 0;
+ // Compare swipe angle to car direction to determine if it's a left or right drift
+ var angleDiff = swipeDirection - car.direction;
+ // Normalize angle to -PI to PI
+ while (angleDiff > Math.PI) {
+ angleDiff -= Math.PI * 2;
+ }
+ while (angleDiff < -Math.PI) {
+ angleDiff += Math.PI * 2;
+ }
+ if (angleDiff > 0) {
+ driftDir = 1; // Right drift
+ } else {
+ driftDir = -1; // Left drift
+ }
+ // Start drifting in the determined direction
+ car.startDrift(driftDir);
+ // Reset drift time tracking
+ lastDriftTime = Date.now();
+ }
+ }
+};
+// Main game loop
+game.update = function () {
+ if (gameState === 'playing') {
+ // Update car physics
+ car.update();
+ // Check collisions
+ var collision = track.checkCollisions(car);
+ if (collision) {
+ if (collision.type === 'border') {
+ // Hit a wall - game over
+ gameOver();
+ } else if (collision.type === 'checkpoint' && !collision.element.passed) {
+ // Passed checkpoint
+ handleCheckpoint();
+ }
+ // Corner collisions are handled in the drift scoring
+ }
+ // Handle drift scoring
+ handleDriftPoints();
+ // Update score display
+ updateScoreText();
+ }
+};
\ No newline at end of file