/**** * 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