User prompt
Agrégale IA al auto enemigo
User prompt
Haz que aparezcan entre 3 a 6 autos
User prompt
Haz que aparezcan entre 3 a 7 autos
User prompt
Mejora más la lógica de choque, algunas veces el auto sale disparado en la dirección equivocada
User prompt
Agrega un frenado más suave al auto chocado
User prompt
Agrega un frenado por fricción l auto chocado alargando su frenado y haciéndolo más suave
User prompt
Al cochar con poca velocidad un auto haz que aparezca como si se empujar y al chocar muy rápido exagera más el empuje
User prompt
Haz que al chocar yendo muy rápido la perdida el reinicio de aceleración sea mayor
User prompt
Haz que el auto chocado salga disparado en la dirección contraria al choque equivalente a la velocidad con la que se haya chocado
User prompt
Arregla el error que hace que al chocar no se reinicia el momento de acelerar como al iniciar la conducción
User prompt
Haz que al chocar la perdida de velocidad y aceleración sea equivalente a la velocidad actual haciendo más natural y realista el choque
User prompt
Haz que al chocar la perdida de velocidad y aceleración sea equivalente a la velocidad actual haciendo más natural y realista el choque
User prompt
Agrega la lógica de coque por epso con la pared
User prompt
Mejora la lógica de empuje haciéndolo más natural
User prompt
Haz que se puedan empujar los autos
User prompt
Haz que al chocar muy rápido contra un auto el auto pierda aceleración
User prompt
El auto jugador rebota mucho al chocar, hazlo más narural
User prompt
El auto rebota mucho al chocar, hazlo más narural
User prompt
Arregla la colisión entre los costados, el área de choque es muy grande
User prompt
Agrega entre 4 a 7 autos
User prompt
Haz que los autos aparezcan en posiciones random mirando al centro
User prompt
Haz un poco más exagerado los choques
User prompt
Agrega peso a los autos para mejorarla lógica de choques
User prompt
Haz que al chocar un auto enemigo este será empujado en la dirección contraria donde se chocó. Mientras rápido se va más lejos irá. Agrega desaseleracion al choque (no tweet plugin)
User prompt
Haz que al chocar un auto enemigo este será empujado en la dirección contraria donde se chocó. Mientras más rápido se va más lejos irá. Agrega desaceleración al choque ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var EnemyCar = Container.expand(function () { var self = Container.call(this); var enemyCarGraphics = self.attachAsset('Cars', { anchorX: 0.5, anchorY: 0.5 }); // Assign random color (excluding red) var enemyColors = [0x0066ff, // Blue 0x00ff66, // Green 0xffff00, // Yellow 0xff8800, // Orange 0x8800ff, // Purple 0x00ffff, // Cyan 0xff00ff, // Magenta 0x888888, // Gray 0xffffff // White ]; var randomColorIndex = Math.floor(Math.random() * enemyColors.length); enemyCarGraphics.tint = enemyColors[randomColorIndex]; // Basic properties for enemy car with weight self.velocityX = 0; self.velocityY = 0; self.rotation = 0; self.weight = 1.0 + Math.random() * 1.5; // Random weight between 1.0 and 2.5 return self; }); var Particle = Container.expand(function () { var self = Container.call(this); // Random particle size between 10.8-25.2 pixels (20% smaller than original) var particleSize = 10.8 + Math.random() * 14.4; var particleGraphics = self.attachAsset('ParticulasVel', { anchorX: 0.5, anchorY: 0.5, scaleX: particleSize / 30, scaleY: particleSize / 30 }); // Random initial properties (20% smaller velocities) self.velocityX = (Math.random() - 0.5) * 3.2; self.velocityY = Math.random() * 2.4 + 0.8; self.lifespan = 20 + Math.random() * 20; // Reduced lifespan: 0.33-0.67 seconds at 60fps self.age = 0; self.update = function () { // Update position self.x += self.velocityX; self.y += self.velocityY; // Age particle self.age++; // Fade out over time var fadeProgress = self.age / self.lifespan; particleGraphics.alpha = 1 - fadeProgress; // Scale down over time var scaleProgress = 1 - fadeProgress * 0.5; particleGraphics.scaleX = particleSize / 30 * scaleProgress; particleGraphics.scaleY = particleSize / 30 * scaleProgress; // Apply gravity and air resistance (20% reduced for smaller scale) self.velocityY += 0.08; // Reduced gravity self.velocityX *= 0.984; // Slightly less air resistance self.velocityY *= 0.984; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Create gameplay background - 4/5 of screen height (top portion) 6; var gameplayBackground = game.attachAsset('gameplayBg', { x: 0, y: 0, anchorX: 0, anchorY: 0 }); // Create carPlayer character on top of gameplayBackground var carPlayer = gameplayBackground.attachAsset('CarPlayer', { x: 1024, // Center horizontally y: 1800, // Position in lower portion of gameplay area anchorX: 0.5, anchorY: 0.5 }); // Create enemy car in gameplay area at random position var enemyCar = new EnemyCar(); // Generate random position around the edges or inside the gameplay area var spawnSide = Math.floor(Math.random() * 4); // 0=top, 1=right, 2=bottom, 3=left var centerX = 1024; // Center of gameplay area var centerY = 1093; // Center of gameplay area (2186/2) switch (spawnSide) { case 0: // Top edge enemyCar.x = Math.random() * 1800 + 124; // Random X between 124-1924 enemyCar.y = Math.random() * 300 + 50; // Random Y between 50-350 break; case 1: // Right edge enemyCar.x = Math.random() * 300 + 1700; // Random X between 1700-2000 enemyCar.y = Math.random() * 1800 + 193; // Random Y between 193-1993 break; case 2: // Bottom edge enemyCar.x = Math.random() * 1800 + 124; // Random X between 124-1924 enemyCar.y = Math.random() * 300 + 1836; // Random Y between 1836-2136 break; case 3: // Left edge enemyCar.x = Math.random() * 300 + 50; // Random X between 50-350 enemyCar.y = Math.random() * 1800 + 193; // Random Y between 193-1993 break; } // Calculate rotation to face the center var deltaX = centerX - enemyCar.x; var deltaY = centerY - enemyCar.y; enemyCar.rotation = Math.atan2(deltaX, -deltaY); // Rotation to face center gameplayBackground.addChild(enemyCar); // Create UI background - 1/5 of screen height (bottom portion) var uiBackground = game.attachAsset('uiBg', { x: 0, y: 2186, anchorX: 0, anchorY: 0 }); // Create speed display text var speedText = new Text2('Speed: 0', { size: 60, fill: 0x000000 }); speedText.anchor.set(0, 0.5); speedText.x = 50; speedText.y = 2459; // Center vertically in UI area game.addChild(speedText); // Create joystickBG centered in UI background var joystickBG = uiBackground.attachAsset('JoystickBG', { x: 1024, // Center horizontally in UI y: 273, // Center vertically in UI (546/2 = 273) anchorX: 0.5, anchorY: 0.5 }); // Create point object that will follow touch position var point = null; // Create JoystickPoinr that will follow point position smoothly var joystickPoinr = game.attachAsset('JoystickPoinr', { x: 1024, y: 2459, anchorX: 0.5, anchorY: 0.5 }); // Variables for smooth movement var targetX = 1024; var targetY = 2459; var smoothSpeed = 0.2; // Variables for smooth rotation var targetRotation = 0; var baseRotationSpeed = 0.052; // Variables for realistic car physics var currentVelocity = 0; var acceleration = 0.16; var deceleration = 0.44; var maxSpeed = 15.36; // Variables for drift physics var velocityX = 0; var velocityY = 0; var driftFactor = 0.85; // How much momentum is retained (lower = more drift) var gripFactor = 0.3; // How quickly car aligns with direction (lower = more drift) // Player car weight var playerCarWeight = 1.2; // Player car is moderately heavy // Handle touch down - create and show point game.down = function (x, y, obj) { // Create point at touch position point = game.attachAsset('Puntero', { x: x, y: y, anchorX: 0.5, anchorY: 0.5 }); }; // Handle touch move - update point position game.move = function (x, y, obj) { if (point) { point.x = x; point.y = y; // Calculate joystickBG world position var joystickWorldX = joystickBG.x + uiBackground.x; var joystickWorldY = joystickBG.y + uiBackground.y; // Calculate distance from joystick center var deltaX = x - joystickWorldX; var deltaY = y - joystickWorldY; var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); var maxRadius = joystickBG.width / 2; // Limit movement to joystick radius if (distance > maxRadius) { var angle = Math.atan2(deltaY, deltaX); deltaX = Math.cos(angle) * maxRadius; deltaY = Math.sin(angle) * maxRadius; } // Update target position for smooth movement (constrained) targetX = joystickWorldX + deltaX; targetY = joystickWorldY + deltaY; } }; // Handle touch up - remove point game.up = function (x, y, obj) { if (point) { point.destroy(); point = null; // Reset target position to joystick center var joystickWorldX = joystickBG.x + uiBackground.x; var joystickWorldY = joystickBG.y + uiBackground.y; targetX = joystickWorldX; targetY = joystickWorldY; } }; // Update function for smooth movement game.update = function () { // Smoothly move JoystickPoinr towards target position var deltaX = targetX - joystickPoinr.x; var deltaY = targetY - joystickPoinr.y; joystickPoinr.x += deltaX * smoothSpeed; joystickPoinr.y += deltaY * smoothSpeed; // Double-check that joystickPoinr stays within bounds var joystickWorldX = joystickBG.x + uiBackground.x; var joystickWorldY = joystickBG.y + uiBackground.y; var currentDeltaX = joystickPoinr.x - joystickWorldX; var currentDeltaY = joystickPoinr.y - joystickWorldY; var currentDistance = Math.sqrt(currentDeltaX * currentDeltaX + currentDeltaY * currentDeltaY); var maxRadius = joystickBG.width / 2; if (currentDistance > maxRadius) { var angle = Math.atan2(currentDeltaY, currentDeltaX); joystickPoinr.x = joystickWorldX + Math.cos(angle) * maxRadius; joystickPoinr.y = joystickWorldY + Math.sin(angle) * maxRadius; } // Update car rotation based on joystick position var joystickOffsetX = joystickPoinr.x - joystickWorldX; var joystickOffsetY = joystickPoinr.y - joystickWorldY; var joystickDistance = Math.sqrt(joystickOffsetX * joystickOffsetX + joystickOffsetY * joystickOffsetY); // Calculate power based on distance from center (0 to 1) var power = Math.min(joystickDistance / maxRadius, 1); // Only rotate if joystick is moved significantly from center if (joystickDistance > 10) { var joystickAngle = Math.atan2(joystickOffsetX, -joystickOffsetY); targetRotation = joystickAngle; } // Smoothly interpolate car rotation towards target var rotationDelta = targetRotation - carPlayer.rotation; // Handle angle wrapping for shortest rotation path while (rotationDelta > Math.PI) { rotationDelta -= 2 * Math.PI; } while (rotationDelta < -Math.PI) { rotationDelta += 2 * Math.PI; } // Calculate rotation speed based on current velocity (slower speed = much slower turning) var speedRatio = Math.sqrt(velocityX * velocityX + velocityY * velocityY) / maxSpeed; var dynamicRotationSpeed = baseRotationSpeed * Math.max(0.1, speedRatio); // Minimum 10% rotation speed carPlayer.rotation += rotationDelta * dynamicRotationSpeed; // Calculate target velocity based on joystick power var targetVelocity = maxSpeed * power; // Apply smooth velocity transitions with exponential interpolation if (power > 0.1) { // Accelerating - smooth exponential approach to target velocity var velocityDiff = targetVelocity - currentVelocity; var accelerationRate = 0.004; // Smooth acceleration rate (20% slower for smaller car) currentVelocity += velocityDiff * accelerationRate; } else { // Decelerating when joystick is near center - smooth exponential decay var decelerationRate = 0.048; // Smooth deceleration rate (20% slower for smaller car) currentVelocity *= 1 - decelerationRate; if (Math.abs(currentVelocity) < 0.1) { currentVelocity = 0; } } // Limit velocity to max speed currentVelocity = Math.min(currentVelocity, maxSpeed); // Calculate intended movement direction based on car rotation and current velocity var intendedMoveX = Math.sin(carPlayer.rotation) * currentVelocity; var intendedMoveY = -Math.cos(carPlayer.rotation) * currentVelocity; // Calculate turning friction based on dynamic rotation speed var rotationFriction = Math.abs(rotationDelta * dynamicRotationSpeed) * 0.8; // Reduced friction intensity for smoother feel var frictionMultiplier = Math.max(0.85, 1 - rotationFriction); // Less velocity reduction when turning (min 0.85 for more natural feel) // Apply drift physics - blend current momentum with intended direction velocityX = velocityX * driftFactor + intendedMoveX * gripFactor; velocityY = velocityY * driftFactor + intendedMoveY * gripFactor; // Apply turning friction to reduce velocity when steering velocityX *= frictionMultiplier; velocityY *= frictionMultiplier; // Apply some base deceleration to drift momentum velocityX *= 0.98; velocityY *= 0.98; // Update car position using drift momentum carPlayer.x += velocityX; carPlayer.y += velocityY; // Keep car within gameplay area bounds with realistic collision physics var halfCarWidth = 16; // CarPlayer width is 32, so half is 16 var halfCarHeight = 24; // CarPlayer height is 47.36, so half is ~24 // Calculate current speed for impact calculations var currentSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY); var impactThreshold = 2; // Minimum speed to trigger impact effects // Realistic collision physics with energy loss and proper angles if (carPlayer.x < halfCarWidth) { carPlayer.x = halfCarWidth; // Calculate impact intensity based on perpendicular velocity component var impactVelocity = Math.abs(velocityX); var energyLoss = 0.4 + impactVelocity / maxSpeed * 0.3; // More energy loss at higher speeds // Realistic bounce with energy conservation velocityX = -velocityX * (1 - energyLoss); velocityY *= 0.8; // Friction reduces parallel velocity component // Visual feedback for significant impacts if (impactVelocity > impactThreshold) { LK.effects.flashObject(carPlayer, 0xff4444, 200); } } if (carPlayer.x > 2048 - halfCarWidth) { carPlayer.x = 2048 - halfCarWidth; // Calculate impact intensity based on perpendicular velocity component var impactVelocity = Math.abs(velocityX); var energyLoss = 0.4 + impactVelocity / maxSpeed * 0.3; // More energy loss at higher speeds // Realistic bounce with energy conservation velocityX = -velocityX * (1 - energyLoss); velocityY *= 0.8; // Friction reduces parallel velocity component // Visual feedback for significant impacts if (impactVelocity > impactThreshold) { LK.effects.flashObject(carPlayer, 0xff4444, 200); } } if (carPlayer.y < halfCarHeight) { carPlayer.y = halfCarHeight; // Calculate impact intensity based on perpendicular velocity component var impactVelocity = Math.abs(velocityY); var energyLoss = 0.4 + impactVelocity / maxSpeed * 0.3; // More energy loss at higher speeds // Realistic bounce with energy conservation velocityY = -velocityY * (1 - energyLoss); velocityX *= 0.8; // Friction reduces parallel velocity component // Visual feedback for significant impacts if (impactVelocity > impactThreshold) { LK.effects.flashObject(carPlayer, 0xff4444, 200); } } if (carPlayer.y > 2186 - halfCarHeight) { carPlayer.y = 2186 - halfCarHeight; // Calculate impact intensity based on perpendicular velocity component var impactVelocity = Math.abs(velocityY); var energyLoss = 0.4 + impactVelocity / maxSpeed * 0.3; // More energy loss at higher speeds // Realistic bounce with energy conservation velocityY = -velocityY * (1 - energyLoss); velocityX *= 0.8; // Friction reduces parallel velocity component // Visual feedback for significant impacts if (impactVelocity > impactThreshold) { LK.effects.flashObject(carPlayer, 0xff4444, 200); } } // Particle system for car exhaust if (!game.particles) { game.particles = []; } // Generate particles proportional to current velocity (from very little to much) var totalSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY); var speedRatio = totalSpeed / maxSpeed; // 0 to 1 ratio of current speed to max speed // Calculate particle generation frequency based on speed (more speed = more frequent particles) var particleFrequency = Math.max(1, Math.floor(8 - speedRatio * 6)); // From every 8 ticks (slow) to every 2 ticks (fast) if (speedRatio > 0.05 && LK.ticks % particleFrequency === 0) { // Only generate particles when moving at least 5% of max speed // Calculate particle spawn position further behind the car (20% closer for smaller car) var particleSpawnX = carPlayer.x - Math.sin(carPlayer.rotation) * 55; var particleSpawnY = carPlayer.y + Math.cos(carPlayer.rotation) * 55; // Create particles based on speed - more speed = more particles var particleCount = Math.max(1, Math.floor(speedRatio * 3)); // 1-3 particles based on speed ratio for (var p = 0; p < particleCount; p++) { // Create new particle var newParticle = new Particle(); newParticle.x = particleSpawnX + (Math.random() - 0.5) * 19.2; // 20% smaller spawn area newParticle.y = particleSpawnY + (Math.random() - 0.5) * 19.2; // Add velocity variation based on car movement (20% reduced for smaller scale) newParticle.velocityX += -velocityX * 0.12 + (Math.random() - 0.5) * 2.4; newParticle.velocityY += -velocityY * 0.12 + (Math.random() - 0.5) * 2.4; game.particles.push(newParticle); gameplayBackground.addChild(newParticle); // Tween particle color for variety var colors = [0xffffff, 0xcccccc, 0x999999, 0x666666]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; tween(newParticle.children[0], { tint: randomColor }, { duration: 100 }); } } // Update and clean up particles for (var i = game.particles.length - 1; i >= 0; i--) { var particle = game.particles[i]; if (particle.age >= particle.lifespan) { particle.destroy(); game.particles.splice(i, 1); } } // Check collision between player car and enemy car using smaller collision boxes if (!carPlayer.lastColliding) carPlayer.lastColliding = false; // Define smaller collision boxes (approximately 60% of actual asset size for more precise collision) var playerCollisionWidth = 38; // Reduced from 64px width var playerCollisionHeight = 57; // Reduced from ~95px height var enemyCollisionWidth = 38; // Reduced from 64px width var enemyCollisionHeight = 57; // Reduced from ~94px height // Calculate collision boxes centers var playerLeft = carPlayer.x - playerCollisionWidth / 2; var playerRight = carPlayer.x + playerCollisionWidth / 2; var playerTop = carPlayer.y - playerCollisionHeight / 2; var playerBottom = carPlayer.y + playerCollisionHeight / 2; var enemyLeft = enemyCar.x - enemyCollisionWidth / 2; var enemyRight = enemyCar.x + enemyCollisionWidth / 2; var enemyTop = enemyCar.y - enemyCollisionHeight / 2; var enemyBottom = enemyCar.y + enemyCollisionHeight / 2; // More precise collision detection using smaller bounding boxes var currentColliding = !(playerRight < enemyLeft || playerLeft > enemyRight || playerBottom < enemyTop || playerTop > enemyBottom); if (!carPlayer.lastColliding && currentColliding) { // Collision just started - calculate collision physics with mass var playerSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY); var enemySpeed = Math.sqrt(enemyCar.velocityX * enemyCar.velocityX + enemyCar.velocityY * enemyCar.velocityY); // Calculate collision direction (from player car to enemy car) var collisionDeltaX = enemyCar.x - carPlayer.x; var collisionDeltaY = enemyCar.y - carPlayer.y; var collisionDistance = Math.sqrt(collisionDeltaX * collisionDeltaX + collisionDeltaY * collisionDeltaY); // Normalize collision direction if (collisionDistance > 0) { collisionDeltaX /= collisionDistance; collisionDeltaY /= collisionDistance; } // Calculate momentum transfer using conservation of momentum // m1*v1 + m2*v2 = m1*v1' + m2*v2' (simplified elastic collision) var totalMass = playerCarWeight + enemyCar.weight; var massRatio1 = (playerCarWeight - enemyCar.weight) / totalMass; var massRatio2 = 2 * enemyCar.weight / totalMass; var massRatio3 = 2 * playerCarWeight / totalMass; var massRatio4 = (enemyCar.weight - playerCarWeight) / totalMass; // Make energy loss proportional to current speed for more natural and realistic crash // At low speed, little loss; at high speed, much more loss var relativeSpeed = Math.max(playerSpeed, enemySpeed); var minLoss = 0.18; // minimum energy loss at very low speed var maxLoss = 0.65; // maximum energy loss at very high speed var speedNorm = Math.min(1, relativeSpeed / maxSpeed); // 0 to 1 var energyLoss = minLoss + (maxLoss - minLoss) * speedNorm; var restitution = 1 - energyLoss; // Separate cars to prevent overlap (less exaggerated separation) var separationDistance = 70; // Reduced from 110 for more natural push carPlayer.x = enemyCar.x - collisionDeltaX * separationDistance; carPlayer.y = enemyCar.y - collisionDeltaY * separationDistance; // Calculate new velocities based on mass and current motion // Player car velocity change (heavier cars are less affected) var playerImpactX = velocityX * massRatio1 + enemyCar.velocityX * massRatio2; var playerImpactY = velocityY * massRatio1 + enemyCar.velocityY * massRatio2; velocityX = playerImpactX * restitution; velocityY = playerImpactY * restitution; // Enemy car velocity change (lighter cars get pushed more) var enemyImpactX = velocityX * massRatio3 + enemyCar.velocityX * massRatio4; var enemyImpactY = velocityY * massRatio3 + enemyCar.velocityY * massRatio4; enemyCar.velocityX = enemyImpactX * restitution; enemyCar.velocityY = enemyImpactY * restitution; // --- NEW: Launch enemy car away from collision, push effect depends on collision speed --- var launchSpeed = Math.max(playerSpeed, enemySpeed); // Calculate push multiplier: gentle at low speed, exaggerated at high speed // At 0 speed: 0.4x, at maxSpeed: 1.5x (tunable) var minPush = 0.4; var maxPush = 1.5; var pushMultiplier = minPush + (maxPush - minPush) * speedNorm; // Direction from player to enemy (so enemy is launched away from player) var launchDirX = enemyCar.x - carPlayer.x; var launchDirY = enemyCar.y - carPlayer.y; var launchDist = Math.sqrt(launchDirX * launchDirX + launchDirY * launchDirY); // If the direction is too small (almost zero), use the player's movement direction if (launchDist < 0.01) { // Use the normalized velocity of the player (if moving) var playerMoveNorm = Math.sqrt(velocityX * velocityX + velocityY * velocityY); if (playerMoveNorm > 0.01) { launchDirX = velocityX / playerMoveNorm; launchDirY = velocityY / playerMoveNorm; } else { // Default to up if both are zero launchDirX = 0; launchDirY = -1; } } else { launchDirX /= launchDist; launchDirY /= launchDist; } // Add launch velocity proportional to collision speed and pushMultiplier enemyCar.velocityX += launchDirX * launchSpeed * pushMultiplier; enemyCar.velocityY += launchDirY * launchSpeed * pushMultiplier; // --- END NEW --- // Add directional push based on collision angle and relative mass var pushIntensity = (playerSpeed + enemySpeed) * (0.5 + 0.5 * speedNorm); // More push at higher speed, less at low var playerPushRatio = enemyCar.weight / totalMass; // Heavier enemy = more push on player var enemyPushRatio = playerCarWeight / totalMass; // Heavier player = more push on enemy // Apply directional collision forces (less exaggerated, but still speed-dependent) velocityX += -collisionDeltaX * pushIntensity * playerPushRatio * 0.7; velocityY += -collisionDeltaY * pushIntensity * playerPushRatio * 0.7; enemyCar.velocityX += collisionDeltaX * pushIntensity * enemyPushRatio * 0.7; enemyCar.velocityY += collisionDeltaY * pushIntensity * enemyPushRatio * 0.7; // Reset acceleration interpolation so acceleration after crash feels like at driving start, but more severe at high speed var postCrashSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY); // If the crash was at high speed, reduce the post-collision velocity more (stronger reset) if (relativeSpeed > maxSpeed * 0.7) { // At very high speed, reduce velocity to 40% of post-collision value currentVelocity = postCrashSpeed * 0.4; } else if (relativeSpeed > maxSpeed * 0.4) { // At medium speed, reduce velocity to 70% of post-collision value currentVelocity = postCrashSpeed * 0.7; } else { // At low speed, keep as before currentVelocity = postCrashSpeed; } // Visual feedback for collision LK.effects.flashObject(carPlayer, 0xff0000, 500); } // Update last collision state carPlayer.lastColliding = currentColliding; // --- ENEMY CAR AI LOGIC --- // Simple AI: enemy car will try to follow the player car if not recently hit if (!enemyCar.aiCooldown) enemyCar.aiCooldown = 0; if (!enemyCar.lastAIUpdate) enemyCar.lastAIUpdate = 0; if (!enemyCar.lastWasHit) enemyCar.lastWasHit = false; // AI cooldown after being hit (so it doesn't immediately chase again) if (enemyCar.aiCooldown > 0) { enemyCar.aiCooldown--; } else { // Only update AI every 6 frames for stability if (LK.ticks - enemyCar.lastAIUpdate > 6) { enemyCar.lastAIUpdate = LK.ticks; // Calculate vector from enemy to player var dx = carPlayer.x - enemyCar.x; var dy = carPlayer.y - enemyCar.y; var dist = Math.sqrt(dx * dx + dy * dy); // If close, try to avoid; if far, chase var aiTargetVX = 0; var aiTargetVY = 0; if (dist > 220) { // Far: chase player var aiSpeed = 2.2 + Math.random() * 0.7; // Randomize a bit for less robotic movement aiTargetVX = dx / dist * aiSpeed; aiTargetVY = dy / dist * aiSpeed; } else if (dist < 120) { // Too close: move away from player var aiSpeed = 2.5 + Math.random() * 0.7; aiTargetVX = -(dx / dist) * aiSpeed; aiTargetVY = -(dy / dist) * aiSpeed; } else { // Maintain current velocity (cruise) aiTargetVX = enemyCar.velocityX * 0.98; aiTargetVY = enemyCar.velocityY * 0.98; } // Smoothly blend current velocity towards AI target var aiBlend = 0.12 + Math.random() * 0.08; enemyCar.velocityX = enemyCar.velocityX * (1 - aiBlend) + aiTargetVX * aiBlend; enemyCar.velocityY = enemyCar.velocityY * (1 - aiBlend) + aiTargetVY * aiBlend; } } // Update enemy car physics (simple momentum with friction) enemyCar.x += enemyCar.velocityX; enemyCar.y += enemyCar.velocityY; // Apply smooth braking to enemy car after collision for more natural deceleration if (!enemyCar.smoothBraking) enemyCar.smoothBraking = false; if (!enemyCar.brakeFrames) enemyCar.brakeFrames = 0; var currentEnemySpeed = Math.sqrt(enemyCar.velocityX * enemyCar.velocityX + enemyCar.velocityY * enemyCar.velocityY); // If enemy car was just launched (high velocity), enable smooth braking if (currentEnemySpeed > maxSpeed * 0.6 && !enemyCar.smoothBraking) { enemyCar.smoothBraking = true; enemyCar.brakeFrames = 0; } // Smooth braking logic: apply a gentle, progressive friction for a short period after being launched if (enemyCar.smoothBraking) { // Braking lasts for 18 frames (~0.3s at 60fps) var brakeDuration = 18; var brakeProgress = Math.min(1, enemyCar.brakeFrames / brakeDuration); // Start with gentle friction, increase to normal friction var minFriction = 0.96; var maxFriction = 0.92 - currentEnemySpeed / maxSpeed * 0.05; var frictionRate = minFriction + (maxFriction - minFriction) * brakeProgress; enemyCar.velocityX *= frictionRate; enemyCar.velocityY *= frictionRate; enemyCar.brakeFrames++; if (enemyCar.brakeFrames >= brakeDuration) { enemyCar.smoothBraking = false; } } else if (currentEnemySpeed > 0.1) { // Normal progressive friction var frictionRate = 0.92 - currentEnemySpeed / maxSpeed * 0.05; // More friction at higher speeds enemyCar.velocityX *= frictionRate; enemyCar.velocityY *= frictionRate; } else { // Stop very slow movement to prevent endless drift enemyCar.velocityX = 0; enemyCar.velocityY = 0; } // Keep enemy car within bounds var enemyHalfWidth = 32; var enemyHalfHeight = 47; if (enemyCar.x < enemyHalfWidth) { enemyCar.x = enemyHalfWidth; enemyCar.velocityX = -enemyCar.velocityX * 0.6; } if (enemyCar.x > 2048 - enemyHalfWidth) { enemyCar.x = 2048 - enemyHalfWidth; enemyCar.velocityX = -enemyCar.velocityX * 0.6; } if (enemyCar.y < enemyHalfHeight) { enemyCar.y = enemyHalfHeight; enemyCar.velocityY = -enemyCar.velocityY * 0.6; } if (enemyCar.y > 2186 - enemyHalfHeight) { enemyCar.y = 2186 - enemyHalfHeight; enemyCar.velocityY = -enemyCar.velocityY * 0.6; } // Update speed display speedText.setText('Speed: ' + Math.round(totalSpeed)); };
===================================================================
--- original.js
+++ change.js
@@ -102,46 +102,41 @@
// Position in lower portion of gameplay area
anchorX: 0.5,
anchorY: 0.5
});
-// Create between 3 and 6 enemy cars at random positions
-var enemyCars = [];
-var numEnemies = 3 + Math.floor(Math.random() * 4); // 3 to 6
+// Create enemy car in gameplay area at random position
+var enemyCar = new EnemyCar();
+// Generate random position around the edges or inside the gameplay area
+var spawnSide = Math.floor(Math.random() * 4); // 0=top, 1=right, 2=bottom, 3=left
var centerX = 1024; // Center of gameplay area
var centerY = 1093; // Center of gameplay area (2186/2)
-for (var i = 0; i < numEnemies; i++) {
- var enemyCar = new EnemyCar();
- // Generate random position around the edges or inside the gameplay area
- var spawnSide = Math.floor(Math.random() * 4); // 0=top, 1=right, 2=bottom, 3=left
- switch (spawnSide) {
- case 0:
- // Top edge
- enemyCar.x = Math.random() * 1800 + 124;
- enemyCar.y = Math.random() * 300 + 50;
- break;
- case 1:
- // Right edge
- enemyCar.x = Math.random() * 300 + 1700;
- enemyCar.y = Math.random() * 1800 + 193;
- break;
- case 2:
- // Bottom edge
- enemyCar.x = Math.random() * 1800 + 124;
- enemyCar.y = Math.random() * 300 + 1836;
- break;
- case 3:
- // Left edge
- enemyCar.x = Math.random() * 300 + 50;
- enemyCar.y = Math.random() * 1800 + 193;
- break;
- }
- // Calculate rotation to face the center
- var deltaX = centerX - enemyCar.x;
- var deltaY = centerY - enemyCar.y;
- enemyCar.rotation = Math.atan2(deltaX, -deltaY);
- gameplayBackground.addChild(enemyCar);
- enemyCars.push(enemyCar);
+switch (spawnSide) {
+ case 0:
+ // Top edge
+ enemyCar.x = Math.random() * 1800 + 124; // Random X between 124-1924
+ enemyCar.y = Math.random() * 300 + 50; // Random Y between 50-350
+ break;
+ case 1:
+ // Right edge
+ enemyCar.x = Math.random() * 300 + 1700; // Random X between 1700-2000
+ enemyCar.y = Math.random() * 1800 + 193; // Random Y between 193-1993
+ break;
+ case 2:
+ // Bottom edge
+ enemyCar.x = Math.random() * 1800 + 124; // Random X between 124-1924
+ enemyCar.y = Math.random() * 300 + 1836; // Random Y between 1836-2136
+ break;
+ case 3:
+ // Left edge
+ enemyCar.x = Math.random() * 300 + 50; // Random X between 50-350
+ enemyCar.y = Math.random() * 1800 + 193; // Random Y between 193-1993
+ break;
}
+// Calculate rotation to face the center
+var deltaX = centerX - enemyCar.x;
+var deltaY = centerY - enemyCar.y;
+enemyCar.rotation = Math.atan2(deltaX, -deltaY); // Rotation to face center
+gameplayBackground.addChild(enemyCar);
// Create UI background - 1/5 of screen height (bottom portion)
var uiBackground = game.attachAsset('uiBg', {
x: 0,
y: 2186,
@@ -421,186 +416,222 @@
particle.destroy();
game.particles.splice(i, 1);
}
}
- // Check collision between player car and all enemy cars using smaller collision boxes
- if (!carPlayer.lastCollidingArr) carPlayer.lastCollidingArr = [];
+ // Check collision between player car and enemy car using smaller collision boxes
+ if (!carPlayer.lastColliding) carPlayer.lastColliding = false;
// Define smaller collision boxes (approximately 60% of actual asset size for more precise collision)
var playerCollisionWidth = 38; // Reduced from 64px width
var playerCollisionHeight = 57; // Reduced from ~95px height
- var enemyCollisionWidth = 38; // Reduced from 64px width
+ var enemyCollisionWidth = 38; // Reduced from 64px width
var enemyCollisionHeight = 57; // Reduced from ~94px height
- for (var e = 0; e < enemyCars.length; e++) {
- var enemyCar = enemyCars[e];
- if (typeof carPlayer.lastCollidingArr[e] === "undefined") carPlayer.lastCollidingArr[e] = false;
- // Calculate collision boxes centers
- var playerLeft = carPlayer.x - playerCollisionWidth / 2;
- var playerRight = carPlayer.x + playerCollisionWidth / 2;
- var playerTop = carPlayer.y - playerCollisionHeight / 2;
- var playerBottom = carPlayer.y + playerCollisionHeight / 2;
- var enemyLeft = enemyCar.x - enemyCollisionWidth / 2;
- var enemyRight = enemyCar.x + enemyCollisionWidth / 2;
- var enemyTop = enemyCar.y - enemyCollisionHeight / 2;
- var enemyBottom = enemyCar.y + enemyCollisionHeight / 2;
- // More precise collision detection using smaller bounding boxes
- var currentColliding = !(playerRight < enemyLeft || playerLeft > enemyRight || playerBottom < enemyTop || playerTop > enemyBottom);
- if (!carPlayer.lastCollidingArr[e] && currentColliding) {
- // Collision just started - calculate collision physics with mass
- var playerSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
- var enemySpeed = Math.sqrt(enemyCar.velocityX * enemyCar.velocityX + enemyCar.velocityY * enemyCar.velocityY);
- // Calculate collision direction (from player car to enemy car)
- var collisionDeltaX = enemyCar.x - carPlayer.x;
- var collisionDeltaY = enemyCar.y - carPlayer.y;
- var collisionDistance = Math.sqrt(collisionDeltaX * collisionDeltaX + collisionDeltaY * collisionDeltaY);
- // Normalize collision direction
- if (collisionDistance > 0) {
- collisionDeltaX /= collisionDistance;
- collisionDeltaY /= collisionDistance;
- }
- // Calculate momentum transfer using conservation of momentum
- // m1*v1 + m2*v2 = m1*v1' + m2*v2' (simplified elastic collision)
- var totalMass = playerCarWeight + enemyCar.weight;
- var massRatio1 = (playerCarWeight - enemyCar.weight) / totalMass;
- var massRatio2 = 2 * enemyCar.weight / totalMass;
- var massRatio3 = 2 * playerCarWeight / totalMass;
- var massRatio4 = (enemyCar.weight - playerCarWeight) / totalMass;
- // Make energy loss proportional to current speed for more natural and realistic crash
- // At low speed, little loss; at high speed, much more loss
- var relativeSpeed = Math.max(playerSpeed, enemySpeed);
- var minLoss = 0.18; // minimum energy loss at very low speed
- var maxLoss = 0.65; // maximum energy loss at very high speed
- var speedNorm = Math.min(1, relativeSpeed / maxSpeed); // 0 to 1
- var energyLoss = minLoss + (maxLoss - minLoss) * speedNorm;
- var restitution = 1 - energyLoss;
- // Separate cars to prevent overlap (less exaggerated separation)
- var separationDistance = 70; // Reduced from 110 for more natural push
- carPlayer.x = enemyCar.x - collisionDeltaX * separationDistance;
- carPlayer.y = enemyCar.y - collisionDeltaY * separationDistance;
- // Calculate new velocities based on mass and current motion
- // Player car velocity change (heavier cars are less affected)
- var playerImpactX = velocityX * massRatio1 + enemyCar.velocityX * massRatio2;
- var playerImpactY = velocityY * massRatio1 + enemyCar.velocityY * massRatio2;
- velocityX = playerImpactX * restitution;
- velocityY = playerImpactY * restitution;
- // Enemy car velocity change (lighter cars get pushed more)
- var enemyImpactX = velocityX * massRatio3 + enemyCar.velocityX * massRatio4;
- var enemyImpactY = velocityY * massRatio3 + enemyCar.velocityY * massRatio4;
- enemyCar.velocityX = enemyImpactX * restitution;
- enemyCar.velocityY = enemyImpactY * restitution;
- // --- NEW: Launch enemy car away from collision, push effect depends on collision speed ---
- var launchSpeed = Math.max(playerSpeed, enemySpeed);
- // Calculate push multiplier: gentle at low speed, exaggerated at high speed
- // At 0 speed: 0.4x, at maxSpeed: 1.5x (tunable)
- var minPush = 0.4;
- var maxPush = 1.5;
- var pushMultiplier = minPush + (maxPush - minPush) * speedNorm;
- // Direction from player to enemy (so enemy is launched away from player)
- var launchDirX = enemyCar.x - carPlayer.x;
- var launchDirY = enemyCar.y - carPlayer.y;
- var launchDist = Math.sqrt(launchDirX * launchDirX + launchDirY * launchDirY);
- // If the direction is too small (almost zero), use the player's movement direction
- if (launchDist < 0.01) {
- // Use the normalized velocity of the player (if moving)
- var playerMoveNorm = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
- if (playerMoveNorm > 0.01) {
- launchDirX = velocityX / playerMoveNorm;
- launchDirY = velocityY / playerMoveNorm;
- } else {
- // Default to up if both are zero
- launchDirX = 0;
- launchDirY = -1;
- }
+ // Calculate collision boxes centers
+ var playerLeft = carPlayer.x - playerCollisionWidth / 2;
+ var playerRight = carPlayer.x + playerCollisionWidth / 2;
+ var playerTop = carPlayer.y - playerCollisionHeight / 2;
+ var playerBottom = carPlayer.y + playerCollisionHeight / 2;
+ var enemyLeft = enemyCar.x - enemyCollisionWidth / 2;
+ var enemyRight = enemyCar.x + enemyCollisionWidth / 2;
+ var enemyTop = enemyCar.y - enemyCollisionHeight / 2;
+ var enemyBottom = enemyCar.y + enemyCollisionHeight / 2;
+ // More precise collision detection using smaller bounding boxes
+ var currentColliding = !(playerRight < enemyLeft || playerLeft > enemyRight || playerBottom < enemyTop || playerTop > enemyBottom);
+ if (!carPlayer.lastColliding && currentColliding) {
+ // Collision just started - calculate collision physics with mass
+ var playerSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
+ var enemySpeed = Math.sqrt(enemyCar.velocityX * enemyCar.velocityX + enemyCar.velocityY * enemyCar.velocityY);
+ // Calculate collision direction (from player car to enemy car)
+ var collisionDeltaX = enemyCar.x - carPlayer.x;
+ var collisionDeltaY = enemyCar.y - carPlayer.y;
+ var collisionDistance = Math.sqrt(collisionDeltaX * collisionDeltaX + collisionDeltaY * collisionDeltaY);
+ // Normalize collision direction
+ if (collisionDistance > 0) {
+ collisionDeltaX /= collisionDistance;
+ collisionDeltaY /= collisionDistance;
+ }
+ // Calculate momentum transfer using conservation of momentum
+ // m1*v1 + m2*v2 = m1*v1' + m2*v2' (simplified elastic collision)
+ var totalMass = playerCarWeight + enemyCar.weight;
+ var massRatio1 = (playerCarWeight - enemyCar.weight) / totalMass;
+ var massRatio2 = 2 * enemyCar.weight / totalMass;
+ var massRatio3 = 2 * playerCarWeight / totalMass;
+ var massRatio4 = (enemyCar.weight - playerCarWeight) / totalMass;
+ // Make energy loss proportional to current speed for more natural and realistic crash
+ // At low speed, little loss; at high speed, much more loss
+ var relativeSpeed = Math.max(playerSpeed, enemySpeed);
+ var minLoss = 0.18; // minimum energy loss at very low speed
+ var maxLoss = 0.65; // maximum energy loss at very high speed
+ var speedNorm = Math.min(1, relativeSpeed / maxSpeed); // 0 to 1
+ var energyLoss = minLoss + (maxLoss - minLoss) * speedNorm;
+ var restitution = 1 - energyLoss;
+ // Separate cars to prevent overlap (less exaggerated separation)
+ var separationDistance = 70; // Reduced from 110 for more natural push
+ carPlayer.x = enemyCar.x - collisionDeltaX * separationDistance;
+ carPlayer.y = enemyCar.y - collisionDeltaY * separationDistance;
+ // Calculate new velocities based on mass and current motion
+ // Player car velocity change (heavier cars are less affected)
+ var playerImpactX = velocityX * massRatio1 + enemyCar.velocityX * massRatio2;
+ var playerImpactY = velocityY * massRatio1 + enemyCar.velocityY * massRatio2;
+ velocityX = playerImpactX * restitution;
+ velocityY = playerImpactY * restitution;
+ // Enemy car velocity change (lighter cars get pushed more)
+ var enemyImpactX = velocityX * massRatio3 + enemyCar.velocityX * massRatio4;
+ var enemyImpactY = velocityY * massRatio3 + enemyCar.velocityY * massRatio4;
+ enemyCar.velocityX = enemyImpactX * restitution;
+ enemyCar.velocityY = enemyImpactY * restitution;
+ // --- NEW: Launch enemy car away from collision, push effect depends on collision speed ---
+ var launchSpeed = Math.max(playerSpeed, enemySpeed);
+ // Calculate push multiplier: gentle at low speed, exaggerated at high speed
+ // At 0 speed: 0.4x, at maxSpeed: 1.5x (tunable)
+ var minPush = 0.4;
+ var maxPush = 1.5;
+ var pushMultiplier = minPush + (maxPush - minPush) * speedNorm;
+ // Direction from player to enemy (so enemy is launched away from player)
+ var launchDirX = enemyCar.x - carPlayer.x;
+ var launchDirY = enemyCar.y - carPlayer.y;
+ var launchDist = Math.sqrt(launchDirX * launchDirX + launchDirY * launchDirY);
+ // If the direction is too small (almost zero), use the player's movement direction
+ if (launchDist < 0.01) {
+ // Use the normalized velocity of the player (if moving)
+ var playerMoveNorm = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
+ if (playerMoveNorm > 0.01) {
+ launchDirX = velocityX / playerMoveNorm;
+ launchDirY = velocityY / playerMoveNorm;
} else {
- launchDirX /= launchDist;
- launchDirY /= launchDist;
+ // Default to up if both are zero
+ launchDirX = 0;
+ launchDirY = -1;
}
- // Add launch velocity proportional to collision speed and pushMultiplier
- enemyCar.velocityX += launchDirX * launchSpeed * pushMultiplier;
- enemyCar.velocityY += launchDirY * launchSpeed * pushMultiplier;
- // --- END NEW ---
- // Add directional push based on collision angle and relative mass
- var pushIntensity = (playerSpeed + enemySpeed) * (0.5 + 0.5 * speedNorm); // More push at higher speed, less at low
- var playerPushRatio = enemyCar.weight / totalMass; // Heavier enemy = more push on player
- var enemyPushRatio = playerCarWeight / totalMass; // Heavier player = more push on enemy
- // Apply directional collision forces (less exaggerated, but still speed-dependent)
- velocityX += -collisionDeltaX * pushIntensity * playerPushRatio * 0.7;
- velocityY += -collisionDeltaY * pushIntensity * playerPushRatio * 0.7;
- enemyCar.velocityX += collisionDeltaX * pushIntensity * enemyPushRatio * 0.7;
- enemyCar.velocityY += collisionDeltaY * pushIntensity * enemyPushRatio * 0.7;
- // Reset acceleration interpolation so acceleration after crash feels like at driving start, but more severe at high speed
- var postCrashSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
- // If the crash was at high speed, reduce the post-collision velocity more (stronger reset)
- if (relativeSpeed > maxSpeed * 0.7) {
- // At very high speed, reduce velocity to 40% of post-collision value
- currentVelocity = postCrashSpeed * 0.4;
- } else if (relativeSpeed > maxSpeed * 0.4) {
- // At medium speed, reduce velocity to 70% of post-collision value
- currentVelocity = postCrashSpeed * 0.7;
- } else {
- // At low speed, keep as before
- currentVelocity = postCrashSpeed;
- }
- // Visual feedback for collision
- LK.effects.flashObject(carPlayer, 0xff0000, 500);
+ } else {
+ launchDirX /= launchDist;
+ launchDirY /= launchDist;
}
- // Update last collision state for this enemy
- carPlayer.lastCollidingArr[e] = currentColliding;
- // Update enemy car physics (simple momentum with friction)
- enemyCar.x += enemyCar.velocityX;
- enemyCar.y += enemyCar.velocityY;
- // Apply smooth braking to enemy car after collision for more natural deceleration
- if (!enemyCar.smoothBraking) enemyCar.smoothBraking = false;
- if (!enemyCar.brakeFrames) enemyCar.brakeFrames = 0;
- var currentEnemySpeed = Math.sqrt(enemyCar.velocityX * enemyCar.velocityX + enemyCar.velocityY * enemyCar.velocityY);
- // If enemy car was just launched (high velocity), enable smooth braking
- if (currentEnemySpeed > maxSpeed * 0.6 && !enemyCar.smoothBraking) {
- enemyCar.smoothBraking = true;
- enemyCar.brakeFrames = 0;
+ // Add launch velocity proportional to collision speed and pushMultiplier
+ enemyCar.velocityX += launchDirX * launchSpeed * pushMultiplier;
+ enemyCar.velocityY += launchDirY * launchSpeed * pushMultiplier;
+ // --- END NEW ---
+ // Add directional push based on collision angle and relative mass
+ var pushIntensity = (playerSpeed + enemySpeed) * (0.5 + 0.5 * speedNorm); // More push at higher speed, less at low
+ var playerPushRatio = enemyCar.weight / totalMass; // Heavier enemy = more push on player
+ var enemyPushRatio = playerCarWeight / totalMass; // Heavier player = more push on enemy
+ // Apply directional collision forces (less exaggerated, but still speed-dependent)
+ velocityX += -collisionDeltaX * pushIntensity * playerPushRatio * 0.7;
+ velocityY += -collisionDeltaY * pushIntensity * playerPushRatio * 0.7;
+ enemyCar.velocityX += collisionDeltaX * pushIntensity * enemyPushRatio * 0.7;
+ enemyCar.velocityY += collisionDeltaY * pushIntensity * enemyPushRatio * 0.7;
+ // Reset acceleration interpolation so acceleration after crash feels like at driving start, but more severe at high speed
+ var postCrashSpeed = Math.sqrt(velocityX * velocityX + velocityY * velocityY);
+ // If the crash was at high speed, reduce the post-collision velocity more (stronger reset)
+ if (relativeSpeed > maxSpeed * 0.7) {
+ // At very high speed, reduce velocity to 40% of post-collision value
+ currentVelocity = postCrashSpeed * 0.4;
+ } else if (relativeSpeed > maxSpeed * 0.4) {
+ // At medium speed, reduce velocity to 70% of post-collision value
+ currentVelocity = postCrashSpeed * 0.7;
+ } else {
+ // At low speed, keep as before
+ currentVelocity = postCrashSpeed;
}
- // Smooth braking logic: apply a gentle, progressive friction for a short period after being launched
- if (enemyCar.smoothBraking) {
- // Braking lasts for 18 frames (~0.3s at 60fps)
- var brakeDuration = 18;
- var brakeProgress = Math.min(1, enemyCar.brakeFrames / brakeDuration);
- // Start with gentle friction, increase to normal friction
- var minFriction = 0.96;
- var maxFriction = 0.92 - currentEnemySpeed / maxSpeed * 0.05;
- var frictionRate = minFriction + (maxFriction - minFriction) * brakeProgress;
- enemyCar.velocityX *= frictionRate;
- enemyCar.velocityY *= frictionRate;
- enemyCar.brakeFrames++;
- if (enemyCar.brakeFrames >= brakeDuration) {
- enemyCar.smoothBraking = false;
+ // Visual feedback for collision
+ LK.effects.flashObject(carPlayer, 0xff0000, 500);
+ }
+ // Update last collision state
+ carPlayer.lastColliding = currentColliding;
+ // --- ENEMY CAR AI LOGIC ---
+ // Simple AI: enemy car will try to follow the player car if not recently hit
+ if (!enemyCar.aiCooldown) enemyCar.aiCooldown = 0;
+ if (!enemyCar.lastAIUpdate) enemyCar.lastAIUpdate = 0;
+ if (!enemyCar.lastWasHit) enemyCar.lastWasHit = false;
+ // AI cooldown after being hit (so it doesn't immediately chase again)
+ if (enemyCar.aiCooldown > 0) {
+ enemyCar.aiCooldown--;
+ } else {
+ // Only update AI every 6 frames for stability
+ if (LK.ticks - enemyCar.lastAIUpdate > 6) {
+ enemyCar.lastAIUpdate = LK.ticks;
+ // Calculate vector from enemy to player
+ var dx = carPlayer.x - enemyCar.x;
+ var dy = carPlayer.y - enemyCar.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ // If close, try to avoid; if far, chase
+ var aiTargetVX = 0;
+ var aiTargetVY = 0;
+ if (dist > 220) {
+ // Far: chase player
+ var aiSpeed = 2.2 + Math.random() * 0.7; // Randomize a bit for less robotic movement
+ aiTargetVX = dx / dist * aiSpeed;
+ aiTargetVY = dy / dist * aiSpeed;
+ } else if (dist < 120) {
+ // Too close: move away from player
+ var aiSpeed = 2.5 + Math.random() * 0.7;
+ aiTargetVX = -(dx / dist) * aiSpeed;
+ aiTargetVY = -(dy / dist) * aiSpeed;
+ } else {
+ // Maintain current velocity (cruise)
+ aiTargetVX = enemyCar.velocityX * 0.98;
+ aiTargetVY = enemyCar.velocityY * 0.98;
}
- } else if (currentEnemySpeed > 0.1) {
- // Normal progressive friction
- var frictionRate = 0.92 - currentEnemySpeed / maxSpeed * 0.05; // More friction at higher speeds
- enemyCar.velocityX *= frictionRate;
- enemyCar.velocityY *= frictionRate;
- } else {
- // Stop very slow movement to prevent endless drift
- enemyCar.velocityX = 0;
- enemyCar.velocityY = 0;
+ // Smoothly blend current velocity towards AI target
+ var aiBlend = 0.12 + Math.random() * 0.08;
+ enemyCar.velocityX = enemyCar.velocityX * (1 - aiBlend) + aiTargetVX * aiBlend;
+ enemyCar.velocityY = enemyCar.velocityY * (1 - aiBlend) + aiTargetVY * aiBlend;
}
- // Keep enemy car within bounds
- var enemyHalfWidth = 32;
- var enemyHalfHeight = 47;
- if (enemyCar.x < enemyHalfWidth) {
- enemyCar.x = enemyHalfWidth;
- enemyCar.velocityX = -enemyCar.velocityX * 0.6;
+ }
+ // Update enemy car physics (simple momentum with friction)
+ enemyCar.x += enemyCar.velocityX;
+ enemyCar.y += enemyCar.velocityY;
+ // Apply smooth braking to enemy car after collision for more natural deceleration
+ if (!enemyCar.smoothBraking) enemyCar.smoothBraking = false;
+ if (!enemyCar.brakeFrames) enemyCar.brakeFrames = 0;
+ var currentEnemySpeed = Math.sqrt(enemyCar.velocityX * enemyCar.velocityX + enemyCar.velocityY * enemyCar.velocityY);
+ // If enemy car was just launched (high velocity), enable smooth braking
+ if (currentEnemySpeed > maxSpeed * 0.6 && !enemyCar.smoothBraking) {
+ enemyCar.smoothBraking = true;
+ enemyCar.brakeFrames = 0;
+ }
+ // Smooth braking logic: apply a gentle, progressive friction for a short period after being launched
+ if (enemyCar.smoothBraking) {
+ // Braking lasts for 18 frames (~0.3s at 60fps)
+ var brakeDuration = 18;
+ var brakeProgress = Math.min(1, enemyCar.brakeFrames / brakeDuration);
+ // Start with gentle friction, increase to normal friction
+ var minFriction = 0.96;
+ var maxFriction = 0.92 - currentEnemySpeed / maxSpeed * 0.05;
+ var frictionRate = minFriction + (maxFriction - minFriction) * brakeProgress;
+ enemyCar.velocityX *= frictionRate;
+ enemyCar.velocityY *= frictionRate;
+ enemyCar.brakeFrames++;
+ if (enemyCar.brakeFrames >= brakeDuration) {
+ enemyCar.smoothBraking = false;
}
- if (enemyCar.x > 2048 - enemyHalfWidth) {
- enemyCar.x = 2048 - enemyHalfWidth;
- enemyCar.velocityX = -enemyCar.velocityX * 0.6;
- }
- if (enemyCar.y < enemyHalfHeight) {
- enemyCar.y = enemyHalfHeight;
- enemyCar.velocityY = -enemyCar.velocityY * 0.6;
- }
- if (enemyCar.y > 2186 - enemyHalfHeight) {
- enemyCar.y = 2186 - enemyHalfHeight;
- enemyCar.velocityY = -enemyCar.velocityY * 0.6;
- }
+ } else if (currentEnemySpeed > 0.1) {
+ // Normal progressive friction
+ var frictionRate = 0.92 - currentEnemySpeed / maxSpeed * 0.05; // More friction at higher speeds
+ enemyCar.velocityX *= frictionRate;
+ enemyCar.velocityY *= frictionRate;
+ } else {
+ // Stop very slow movement to prevent endless drift
+ enemyCar.velocityX = 0;
+ enemyCar.velocityY = 0;
}
+ // Keep enemy car within bounds
+ var enemyHalfWidth = 32;
+ var enemyHalfHeight = 47;
+ if (enemyCar.x < enemyHalfWidth) {
+ enemyCar.x = enemyHalfWidth;
+ enemyCar.velocityX = -enemyCar.velocityX * 0.6;
+ }
+ if (enemyCar.x > 2048 - enemyHalfWidth) {
+ enemyCar.x = 2048 - enemyHalfWidth;
+ enemyCar.velocityX = -enemyCar.velocityX * 0.6;
+ }
+ if (enemyCar.y < enemyHalfHeight) {
+ enemyCar.y = enemyHalfHeight;
+ enemyCar.velocityY = -enemyCar.velocityY * 0.6;
+ }
+ if (enemyCar.y > 2186 - enemyHalfHeight) {
+ enemyCar.y = 2186 - enemyHalfHeight;
+ enemyCar.velocityY = -enemyCar.velocityY * 0.6;
+ }
// Update speed display
speedText.setText('Speed: ' + Math.round(totalSpeed));
};
\ No newline at end of file