/**** * Classes ****/ var BoilingLava = Container.expand(function () { var self = Container.call(this); var lavaBubbles = []; self.x = 400; self.y = 400; // Function to create a new lava bubble function createLavaBubble() { var bubble = self.attachAsset('lavaBubble', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1, x: Math.random() * 200 - 100, // Random x position within a range y: Math.random() * 200 - 100 // Random y position within a range }); lavaBubbles.push(bubble); } // Update function to animate the lava bubbles self.update = function () { if (LK.ticks % 10 == 0) { // Emit a bubble every second createLavaBubble(); } for (var i = lavaBubbles.length - 1; i >= 0; i--) { var bubble = lavaBubbles[i]; bubble.y -= 2; // Move bubble upwards bubble.alpha -= 0.015; // Fade out bubble if (bubble.alpha <= 0) { bubble.destroy(); lavaBubbles.splice(i, 1); } } }; return self; }); /** * config { * x : Number || 0, * y : Number || 0, * rotation : Number || 0, * } **/ var ConfigContainer = Container.expand(function (config) { var self = Container.call(this); config = config || {}; ; self.x = config.x || 0; self.y = config.y || 0; self.rotation = config.rotation || 0; if (config.scale !== undefined || config.scaleX !== undefined || config.scaleY !== undefined) { var scaleX = config.scaleX !== undefined ? config.scaleX : config.scale !== undefined ? config.scale : 1; var scaleY = config.scaleY !== undefined ? config.scaleY : config.scale !== undefined ? config.scale : 1; self.scale.set(scaleX, scaleY); } ; return self; }); var Wall = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var wallIndex = Math.floor(Math.random() * ROAD_GEN_WALL_ASSETS); var scale = 1; //0.9 + 0.2 * Math.random(); self.attachAsset('wall' + wallIndex, { anchorX: 0.5, anchorY: 1, scaleX: scale, //Math.random() < 0.5 ? -scale : scale, scaleY: scale }); self.taken = false; self.update = function () { //log("player.sliding:", player.sliding); if (!player.sliding && player.body.torso.intersects(self)) { if (!isBonusActive) { player.hitWall = true; player.sliding = true; // Keep down player.isDead = true; tintPlayer(0x666666); log("Player hit a wall!"); // Flash screen red for 1 second (1000ms) to show we are dead. LK.effects.flashScreen(0xff0000, 1000); // Play lose sound LK.getSound('lose').play(); callGameOver(true); } else { // TODO : what id hit wall while bonus active ? } } }; return self; }); var Sun = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); for (var i = 0; i < 5; i++) { self.attachAsset('circle', { width: 200 + 50 * i, height: 200 + 50 * i, color: 0xFFFF00, alpha: 0.1, anchorX: 0.5, anchorY: 0.5 }); } var sunAsset = self.attachAsset('sun', { anchorX: 0.5075, anchorY: 0.5, alpha: 0.75 }); ; self.update = update; ; function update() { if (LK.ticks % 30 == 0) { for (var i = 0; i < self.children.length - 1; i++) { var circle = self.children[i]; if (i % 2 !== 0) { circle.alpha = 0.01 + 0.09 * Math.abs(Math.sin(LK.ticks / 90)); } else { circle.alpha = 0.01 + 0.09 * Math.abs(Math.cos(LK.ticks / 90)); } } } } }); var RoadSegment = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var background = self.addChild(new Container()); self.background = background; self.attachAsset('roadSegment', { anchorX: 1, anchorY: 1, tint: 0x62C344 }); self.segment = self.attachAsset('roadSegment', { anchorX: 1, anchorY: 1, scaleX: 0.95, scaleY: 0.95, tint: 0x62C344 // TEMP DEBUG0x555555 }); self.segmentRiver = self.attachAsset('lava', { anchorX: 1, anchorY: 1, scaleX: 0.95, scaleY: 0.95, visible: false }); ; self.update = update; self.regenerate = regenerate; self.fadeout = false; self.distance = config.distance; self.step = config.step; self.stepChance = config.stepChance; self.previous = config.previous; self.isRiver = false; self.isWall = false; ; function attachAssetRadial(parent, asset, obj) { var offsetTotal = ROAD_SEGMENT_HEIGHT - (obj.offset || 10); var rotation = -(1 - obj.anchorR) * ROAD_SEGMENT_ANGLE; parent.attachAsset(asset, { x: Math.sin(rotation) * offsetTotal, y: Math.cos(rotation) * -offsetTotal, width: obj.width, height: obj.height, anchorX: obj.anchorX, anchorY: obj.anchorY, scaleX: obj.scaleX || 1, scaleY: obj.scaleY || 1, rotation: (obj.rotation || 0) + 0 }); } function attachObjectRadial(parent, object, obj) { var offsetTotal = ROAD_SEGMENT_HEIGHT - (obj.offset || 10); var rotation = -(1 - obj.anchorR) * ROAD_SEGMENT_ANGLE; object.x = Math.sin(rotation) * offsetTotal - (obj.levitOffset && !obj.isOver || 0); //125* (obj.levitOffset || 0) - 400 * (obj.flying || 0); object.y = Math.cos(rotation) * -offsetTotal - (obj.levitOffset || 0); //object.width = obj.width; //object.height = obj.height; object.anchorX = obj.anchorX; object.anchorY = obj.anchorY; object.scaleX = obj.scaleX || 1; object.scaleY = obj.scaleY || 1; object.rotation = (obj.rotation || 0) + 0; parent.addChild(object); } function generateBackground() { //log(self.distance); background.removeChildren(); self.isRiver = false; self.isWall = false; self.segmentRiver.visible = false; var bonusTruce = false; var active = isActive(); if (isBonusActive && Date.now() - bonusLastStartTime > BONUS_DURATION_SEC * 1000 - 2000) { // just before bonus end bonusTruce = true; } var plantCount = Math.floor(Math.random() * (ROAD_GEN_PLANT_MAX + 1)); if (self.distance === SCORE_TOTAL_DISTANCE) { attachAssetRadial(background, 'flag', { anchorR: 0.5, anchorX: 0.1, anchorY: 1 }); } else { if (active && Math.random() < ROAD_GEN_DETRITUS_CHANCE) { var detritus = new Detritus(); var scale = 1; //0.9 + 0.2 * Math.random(); attachObjectRadial(background, detritus, { anchorR: 0.1 + 0.8 * Math.random(), anchorX: 0.5, anchorY: 0.1, scaleX: Math.random() < 0.5 ? -scale : scale, scaleY: scale, rotation: -Math.PI * 0.25 + Math.random() * Math.PI * 0.5, levitOffset: 190 }); } else if (active && Math.random() < ROAD_GEN_DETRITUS_FLYING_CHANCE) { var detritusFlying = new DetritusFlying(); var scale = 1; //0.9 + 0.2 * Math.random(); attachObjectRadial(background, detritusFlying, { anchorR: 0.1 + 0.8 * Math.random(), anchorX: 0.5, anchorY: 0.1, scaleX: Math.random() < 0.5 ? -scale : scale, scaleY: scale, rotation: -Math.PI * 0.25 + Math.random() * Math.PI * 0.5, flying: 1, levitOffset: 700 }); } else if (road && active && !bonusTruce && road.riverSegmentCount < ROAD_MAX_RIVER_SEGMENTS && !self.isRiver && !self.isWall && !self.previous.isWall && (!self.previous.previous || !self.previous.previous.isWall) && (!self.previous.previous.previous || !self.previous.previous.previous.isWall) && (!self.previous.previous.previous.previous || !self.previous.previous.previous.previous.isWall) && Math.random() < ROAD_GEN_FRAGILE_NATURE_CHANCE) { self.isRiver = true; self.segmentRiver.visible = true; road.riverSegmentCount++; attachObjectRadial(background, new BoilingLava(), { anchorR: 0.1 + 0.8 * Math.random() }); if (ROAD_GEN_LAVA_SIZE > 1) { self.previous.isRiver = true; self.previous.segmentRiver.visible = true; road.riverSegmentCount++; attachObjectRadial(self.previous.background, new BoilingLava(), { anchorR: 0.1 + 0.8 * Math.random() }); } } else if (road && active && !bonusTruce && road.wallSegmentCount < ROAD_MAX_WALL_SEGMENTS && !self.isWall && !self.isRiver && !self.previous.isRiver && (!self.previous.previous || !self.previous.previous.isRiver) && (!self.previous.previous.previous || !self.previous.previous.previous.isRiver) && (!self.previous.previous.previous.previous || !self.previous.previous.previous.previous.isRiver) && Math.random() < ROAD_GEN_WALL_CHANCE) { self.isWall = true; road.wallSegmentCount++; var wallIndex = Math.floor(Math.random() * ROAD_GEN_WALL_ASSETS); var scale = 1; //0.9 + 0.2 * Math.random(); var anchorR = 0.5; // 0.4 + 0.2 * Math.random(); attachObjectRadial(background, new Wall(), { anchorR: anchorR, anchorX: 0.5, anchorY: 1, scaleX: scale, scaleY: scale }); if (wallIndex == 0) { // for pipes : add 2 other above attachObjectRadial(background, new Wall(), { anchorR: anchorR, anchorX: 0.5, anchorY: 1, scaleX: scale, scaleY: scale, levitOffset: 250, isOver: true }); attachObjectRadial(background, new Wall(), { anchorR: anchorR, anchorX: 0.5, anchorY: 1, scaleX: scale, scaleY: scale, levitOffset: 500, isOver: true }); } } else { if (Math.random() < ROAD_GEN_TREE_CHANCE) { var treeIndex = Math.floor(Math.random() * ROAD_GEN_TREE_ASSETS); var scale = 0.9 + 0.2 * Math.random(); attachAssetRadial(background, 'tree' + treeIndex, { anchorR: 0.4 + 0.2 * Math.random(), anchorX: 0.5, anchorY: 1, scaleX: scale, scaleY: scale }); } for (var i = 0; i < plantCount; i++) { var plantIndex = Math.floor(Math.random() * ROAD_GEN_PLANT_ASSETS); var scale = 0.9 + 0.2 * Math.random(); attachAssetRadial(background, 'plant' + plantIndex, { anchorR: 0.1 + 0.8 * Math.random(), anchorX: 0.5, anchorY: 1, scaleX: Math.random() < 0.5 ? -scale : scale, scaleY: scale }); } } } if (active && Math.random() < ROAD_GEN_CLOUD_CHANCE) { var cloudIndex = Math.floor(Math.random() * ROAD_GEN_CLOUD_ASSETS); var scale = 1.0 + 1.5 * Math.random(); attachAssetRadial(background, 'cloud' + cloudIndex, { offset: -1000, anchorR: -1.0 + 2.0 * Math.random(), anchorX: 0.5, anchorY: 0.5, scaleX: scale, scaleY: scale, rotation: -0.2 }); } } function regenerate(incrementDistance) { if (incrementDistance) { self.distance += SCORE_SEGMENT_DISTANCE * ROAD_SEGMENT_COUNT; } var stepping = self.distance <= SCORE_TOTAL_DISTANCE; var stepChance = self.previous.stepChance; var stepUp = stepping && (self.previous.step < ROAD_STEP_COUNT ? Math.random() < self.stepChance : false); var stepDown = stepping && (self.previous.step > 0 ? Math.random() < self.stepChance : false); if (stepUp || stepDown) { if (stepUp && stepDown) { if (Math.random() < 0.5) { stepDown = false; } else { stepUp = false; } } self.step = self.previous.step + (stepUp ? 1 : -1); self.stepChance = ROAD_STEP_CHANCE_BASE; } else { self.step = self.previous.step; self.stepChance = self.previous.stepChance + ROAD_STEP_CHANCE_INCREMENT; } generateBackground(); self.fadeout = false; rescale(); } function update() { if (!isActive()) { return; } if (self.fadeout && self.alpha > 0) { if ((self.alpha -= ROAD_SEGMENT_FADEOUT) < 0) { self.alpha = 0; } } else if (!self.fadeout && self.alpha < 1) { if ((self.alpha += ROAD_SEGMENT_FADEOUT) > 1) { self.alpha = 1; } } } function rescale() { var newScale = (ROAD_STEP_HEIGHT_BASE + self.step * ROAD_STEP_HEIGHT_INCREMENT) / ROAD_SEGMENT_HEIGHT; // TEMP self.scale.set(newScale); } ; rescale(); }); var Road = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var segments = []; self.segments = segments; self.riverSegmentCount = 0; self.wallSegmentCount = 0; for (var i = 0; i < ROAD_SEGMENT_COUNT; i++) { var segment = segments[i] = self.addChild(new RoadSegment({ index: i, previous: i > 0 ? segments[i - 1] : undefined, rotation: i * ROAD_SEGMENT_ANGLE, distance: (i - 1) * SCORE_SEGMENT_DISTANCE, stepChance: ROAD_STEP_CHANCE_BASE, step: ROAD_STEP_DEFAULT })); if (i === ROAD_SEGMENT_COUNT - 1) { segments[0].previous = segment; } if (i >= ROAD_FREE_RUN_COUNT) { segment.regenerate(); } self.attachAsset('roadSegment', { anchorX: 1, anchorY: 1, scaleX: 0.30, scaleY: 0.27, rotation: i * ROAD_SEGMENT_ANGLE, tint: 0x8b4513 }); } self.earthCore = self.attachAsset('earthCore', { width: 470, height: 470, anchorX: 0.5, anchorY: 0.5, alpha: 0.75, //tint: 0x62C344 //tint: 0x87CEEB, tint: 0x888888 }); self.earthCore2 = self.attachAsset('earthCore', { width: 470, height: 470, anchorX: 0.5, anchorY: 0.5, scaleX: -1, scaleY: -1, alpha: 0.75, tint: 0x888888 }); self.attachAsset('ring', { width: 560, height: 560, anchorX: 0.5, anchorY: 0.5, tint: 0xff7518, blendMode: 3 }); var destroyIndex = -1; var regenerateIndex = -1; ; self.rotate = rotate; self.getIndex = getIndex; self.getNode = getNode; self.getNodeDist = getNodeDist; ; function rotate(speed) { if (!isActive()) { return; } self.rotation -= speed; var newDestroyIndex = getIndex(ROAD_SEGMENT_DESTROY); var newRegenerateIndex = getIndex(20); // TEMP if (newDestroyIndex >= 0 && newDestroyIndex !== destroyIndex && !segments[newDestroyIndex].fadeout) { destroyIndex = newDestroyIndex; if (segments[destroyIndex].isRiver) { self.riverSegmentCount--; self.riverSegmentCount = Math.max(0, self.riverSegmentCount); } if (segments[destroyIndex].isWall) { self.wallSegmentCount--; self.wallSegmentCount = Math.max(0, self.wallSegmentCount); } segments[destroyIndex].fadeout = true; } if (newRegenerateIndex >= 0 && newRegenerateIndex !== regenerateIndex && segments[newRegenerateIndex].fadeout) { regenerateIndex = newRegenerateIndex; segments[regenerateIndex].regenerate(true); } self.earthCore.rotation -= 0.001; self.earthCore2.rotation += 0.005; } function getIndex(shift) { return Math.floor(-self.rotation / MATH_2_PI * ROAD_SEGMENT_COUNT + (shift || 0) + 1) % ROAD_SEGMENT_COUNT; } function getNode(shift) { return segments[getIndex(shift)]; } function getNodeDist() { return ROAD_SEGMENT_ANGLE - -self.rotation % ROAD_SEGMENT_ANGLE; } }); var PlayerBody = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); // Animation settings var animation = animationStand; var alpha = 0; var blendAnimation = undefined; var blendDecrement = 0; var blendAlpha = 0; var afterTint = 0xAAAAAA; // Body settings var bodyOffsetY = config.y || 0; var pelvisOffsetX = -35; // old -10; var armUpperAngle = -3 * MATH_EIGHTH_PI; var armUpperOffsetX = 30; // old 15; var armUpperOffsetY = 10; // old 30 var armLowerAngle = -MATH_QUARTER_PI; var armLowerOffsetY = 90; var legUpperAngle = 3 * MATH_EIGHTH_PI; var legUpperOffsetX = -0; var legLowerOffsetY = 135; var footOffsetY = 100; // Create and attach body parts var armUpperRight = self.addChild(new ConfigContainer({ y: armUpperOffsetY })); var legUpperRight = self.addChild(new ConfigContainer({ x: pelvisOffsetX + legUpperOffsetX })); var torso = self.attachAsset('torso', { anchorX: 0.5 }); var head = self.attachAsset('head', { anchorX: 0.52, //0.15, anchorY: 0.8 //0.95 }); self.head = head; var pelvis = self.attachAsset('pelvis', { x: pelvisOffsetX, y: torso.height - 20, // old torso.height, anchorX: 0.5, anchorY: 0.2, tint: afterTint }); self.pelvis = pelvis; self.torso = torso; var legUpperLeft = self.addChild(new ConfigContainer({ x: pelvisOffsetX - legUpperOffsetX - 30 })); var armUpperLeft = self.addChild(new ConfigContainer({ y: armUpperOffsetY })); // Arm extensions armUpperRight.attachAsset('upperArm', { rotation: armUpperAngle, anchorX: 0.85, anchorY: 0.25, tint: afterTint }); self.armUpperRight = armUpperRight; armUpperLeft.attachAsset('upperArm', { rotation: armUpperAngle, anchorX: 0.85, anchorY: 0.25 }); self.armUpperLeft = armUpperLeft; var armLowerRight = armUpperRight.attachAsset('lowerArm', { y: armLowerOffsetY, rotation: armLowerAngle, anchorX: 0.95, anchorY: 0.05, tint: afterTint }); self.armLowerRight = armLowerRight; var armLowerLeft = armUpperLeft.attachAsset('lowerArm', { y: armLowerOffsetY, rotation: armLowerAngle, anchorX: 0.95, anchorY: 0.05 }); self.armLowerLeft = armLowerLeft; // Leg extensions legUpperRight.attachAsset('upperLeg', { rotation: legUpperAngle, anchorY: 0.1, tint: afterTint }); self.legUpperRight = legUpperRight; legUpperLeft.attachAsset('upperLeg', { rotation: legUpperAngle, anchorY: 0.1 }); self.legUpperLeft = legUpperLeft; var legLowerRight = legUpperRight.attachAsset('lowerLeg', { y: legLowerOffsetY, anchorX: 0.5, // old 0.65, tint: afterTint }); self.legLowerRight = legLowerRight; var legLowerLeft = legUpperLeft.attachAsset('lowerLeg', { y: legLowerOffsetY, anchorX: 0.5 // old 0.65 }); self.legLowerLeft = legLowerLeft; var footRight = legLowerRight.attachAsset('foot', { y: footOffsetY - 10, anchorX: -0.2, // old 0.2, anchorY: 0.2, // old 0.05, tint: afterTint }); self.footRight = footRight; var footLeft = legLowerLeft.attachAsset('foot', { y: footOffsetY, anchorX: -0.2, // old 0.2, anchorY: 0.2 // old 0.05, }); self.footLeft = footLeft; // Additional positioning armUpperLeft.x = -torso.width / 2 + armUpperOffsetX; armUpperRight.x = torso.width / 2 - armUpperOffsetX; legUpperLeft.y = torso.height + pelvis.height / 3 - 40; legUpperRight.y = torso.height + pelvis.height / 3 - 20; ; self.animate = animate; self.pushAnimation = pushAnimation; ; function animate(increment) { alpha = (alpha + increment) % 1; if (blendAlpha > 0) { if ((blendAlpha -= blendDecrement) <= 0) { blendAlpha = 0; blendAnimation = undefined; } } var pose = animation(alpha); var blendPose = blendAnimation && blendAnimation(alpha); self.y = animateProperty(pose, blendPose, blendAlpha, 'BODY_OFFSET', bodyOffsetY); head.rotation = animateProperty(pose, blendPose, blendAlpha, 'HEAD_ROTATION'); armUpperRight.rotation = animateProperty(pose, blendPose, blendAlpha, 'ARM_UPPER_RIGHT_ROTATION'); armUpperLeft.rotation = animateProperty(pose, blendPose, blendAlpha, 'ARM_UPPER_LEFT_ROTATION'); armLowerRight.rotation = animateProperty(pose, blendPose, blendAlpha, 'ARM_LOWER_RIGHT_ROTATION', armLowerAngle); armLowerLeft.rotation = animateProperty(pose, blendPose, blendAlpha, 'ARM_LOWER_LEFT_ROTATION', armLowerAngle); legUpperRight.rotation = animateProperty(pose, blendPose, blendAlpha, 'LEG_UPPER_RIGHT_ROTATION'); legUpperLeft.rotation = animateProperty(pose, blendPose, blendAlpha, 'LEG_UPPER_LEFT_ROTATION'); legLowerRight.rotation = animateProperty(pose, blendPose, blendAlpha, 'LEG_LOWER_RIGHT_ROTATION'); legLowerLeft.rotation = animateProperty(pose, blendPose, blendAlpha, 'LEG_LOWER_LEFT_ROTATION'); footRight.rotation = animateProperty(pose, blendPose, blendAlpha, 'FOOT_RIGHT_ROTATION'); footLeft.rotation = animateProperty(pose, blendPose, blendAlpha, 'FOOT_LEFT_ROTATION'); } function pushAnimation(newAnimation, newBlendDecrement) { blendDecrement = newBlendDecrement; if (newAnimation !== animation) { blendAnimation = animation; animation = newAnimation; blendAlpha = 1; } } ; animate(0); }); var Player = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var speedFactor = PLAYER_SPEED_FACTOR_BASE; var stopped = false; var falling = false; var jumping = false; // If the player is currently jumping (and immune to gravity) var jumpAction = false; // Tracks tap releases var jumpStep = 0; // Tracks min/max jump heights var aerialSpeed = 0; // Actual vertical/air speed var baseY = config.y; var step = ROAD_STEP_DEFAULT; var nodeDistance = 0; var nodeTicks = 0; var nodeMulti = 0; var slideTimer = 0; var SLIDE_DURATION = 100; // Duration of slide in frames var body = self.addChild(new PlayerBody({ y: -370 })); self.body = body; self.update = update; self.speedFactor = speedFactor; self.jumpStart = jumpStart; self.jumpEnd = jumpEnd; self.jumping = false; self.sliding = false; self.slideStart = slideStart; self.slideEnd = slideEnd; self.hitWall = false; self.isDead = false; self.intersects = function (obj) { var bounds1 = self.getBounds(); var bounds2 = obj.getBounds(); if (self.sliding) { // When sliding, reduce height for collision check return bounds1.x < bounds2.x + bounds2.width && bounds1.x + bounds1.width > bounds2.x && bounds1.y < bounds2.y + bounds2.height && bounds1.y + bounds1.height / 4 > bounds2.y; } else { return bounds1.x < bounds2.x + bounds2.width && bounds1.x + bounds1.width > bounds2.x && bounds1.y < bounds2.y + bounds2.height && bounds1.y + bounds1.height > bounds2.y; } }; ; self.update = update; self.jumpStart = jumpStart; self.jumpEnd = jumpEnd; self.slideStart = slideStart; self.slideEnd = slideEnd; self.enterBonusState = enterBonusState; self.exitBonusState = exitBonusState; ; function update() { if (!isActive()) { return; } var nextNode = road.getNode(1); var currentNode = nextNode.previous; // Update horizontal movement var outputSpeed = PLAYER_SPEED_BASE * speedFactor; var distance = road.getNodeDist(); // Check for collision with Detritus // Collision check removed from Player update method // Check for collision if (stopped && nextNode.step <= step) { stopped = false; } else if (nextNode.step > step && outputSpeed > distance) { road.rotate(distance - PLAYER_SPACING); speedFactor = PLAYER_SPEED_FACTOR_BASE; stopped = true; if (!isBonusActive && currentNode.step <= step) { body.pushAnimation(animationStand, PLAYER_POSE_TRANSITION); } } if (!stopped) { road.rotate(outputSpeed); if (!gameOver) { if (speedFactor < PLAYER_SPEED_FACTOR_MAX) { if ((speedFactor += PLAYER_SPEED_FACTOR_INCREMENT) >= PLAYER_SPEED_FACTOR_MAX) { speedFactor = PLAYER_SPEED_FACTOR_MAX; } } } else { if (speedFactor > 0) { if ((speedFactor -= PLAYER_SPEED_DECREMENT) <= 0) { speedFactor = 0; } } } } if (isBonusActive) { // Animate player tint using multiple flashy colors var colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff]; var colorIndex = Math.floor(LK.ticks / 5 % colors.length); var tintColor = colors[colorIndex]; tintPlayer(tintColor); if (nextNode && nextNode.background && nextNode.background.children.length > 0) { log(" nextNode.background.children:", nextNode.background.children); for (var i = 0; i < nextNode.background.children.length; i++) { var child = nextNode.background.children[i]; if (child.taken === false) { child.autoTake = true; break; } } } } else { // TOOD: Get new node if applicable // Update vertical movement if (jumping) { //log("speedFactor", speedFactor, "outputSpeed", outputSpeed); jumpStep += aerialSpeed * speedFactor; //log("jumpAction:", jumpAction, "jumpStep:", jumpStep, "PLAYER_JUMP_STEP_MIN:", PLAYER_JUMP_STEP_MIN, "PLAYER_JUMP_STEP_MAX:", PLAYER_JUMP_STEP_MAX); if (!jumpAction && jumpStep <= PLAYER_JUMP_STEP_MIN || jumpStep >= PLAYER_JUMP_STEP_MAX) { falling = true; jumping = false; jumpAction = false; jumpStep = 0; } } else if (falling) { aerialSpeed -= PLAYER_GRAVITY * speedFactor; } else if (step > currentNode.step) { falling = true; body.pushAnimation(animationJump, PLAYER_POSE_TRANSITION); } step += aerialSpeed; //log("falling", falling, "step:", step, "currentNode.step:", currentNode.step); if (falling && step <= currentNode.step) { step = currentNode.step; falling = false; aerialSpeed = 0; body.pushAnimation(stopped ? animationStand : animationRun, PLAYER_POSE_TRANSITION); } if (self.sliding) { slideTimer += 1 * speedFactor; if (slideTimer >= SLIDE_DURATION) { slideEnd(); } // Adjust player's vertical position when sliding self.y = baseY - 500; //- stepHeight / 4; // Adjust to quarter height when sliding } else { self.y = baseY - stepHeight; } } // Score calculations if (!gameOver && currentNode.distance > nodeDistance) { adjustScore(nodeMulti / nodeTicks); currentNode.distance = nodeDistance; nodeMulti = 0; nodeTicks = 0; } nodeMulti += stopped ? SCORE_STOPPED_FACTOR : speedFactor; nodeTicks++; // Adjustments var stepHeight = ROAD_STEP_HEIGHT_BASE + step * ROAD_STEP_HEIGHT_INCREMENT; // TODO: Better scaling if (!self.sliding) { self.y = baseY - stepHeight; // TODO: Better scaling } self.scale.set(PLAYER_SCALE_BASE * stepHeight / ROAD_SEGMENT_HEIGHT); // TODO: Better scaling body.animate(PLAYER_ANIMATION_SPEED_BASE * speedFactor); //multiplierText.setText((stopped ? SCORE_STOPPED_FACTOR : speedFactor).toFixed(1) + 'x'); // Get the current road segment var currentSegment = road.getNode(0); // Check if the current segment is a river segment if (!isBonusActive && currentSegment.isRiver && !jumping && !falling && !jumpAction) { self.isDead = true; tintPlayer(0xff0000); // Player is above a river segment log("Player fell in the river!"); // Flash screen red for 1 second (1000ms) to show we are dead. LK.effects.flashScreen(0xff0000, 1000); // Play lose sound LK.getSound('lose').play(); callGameOver(true); } } function jumpStart() { if (!gameOver && !jumping && !falling && !self.sliding) { LK.getSound('jump').play(); jumping = true; jumpAction = true; aerialSpeed = PLAYER_JUMP_STEP_INCREMENT; body.pushAnimation(animationJump, PLAYER_POSE_TRANSITION); } } function jumpEnd() { jumpAction = false; } function slideStart() { if (!gameOver && !jumping && !falling && !self.sliding) { self.sliding = true; slideTimer = 0; body.pushAnimation(animationSlide, PLAYER_POSE_TRANSITION); body.rotation = -Math.PI / 2; //body.scale.x *= -1; LK.getSound('slide').play(); /* Flies // Rotate the body, not the entire player container body.rotation = -Math.PI / 2; // Flip the body horizontally to ensure correct orientation body.scale.x *= -1; // Play slide sound (if available) // LK.getSound('slide').play(); */ } } function slideEnd() { if (self.sliding && !self.hitWall) { self.sliding = false; slideTimer = 0; body.pushAnimation(stopped ? animationStand : animationRun, PLAYER_POSE_TRANSITION); // Restore body's original rotation and scale body.rotation = 0; //body.scale.x *= -1; } } function enterBonusState() { // ... other bonus state logic ... if (self.sliding) { slideEnd(); } body.pushAnimation(animationBonus, PLAYER_POSE_TRANSITION); body.rotation = Math.PI / 6; speedFactor = PLAYER_SPEED_FACTOR_MAX * 2; } function exitBonusState() { // ... other exit bonus state logic ... body.pushAnimation(stopped ? animationStand : animationRun, PLAYER_POSE_TRANSITION); body.rotation = 0; tintPlayer(0xFFFFFF); speedFactor = PLAYER_SPEED_FACTOR_BASE; } function adjustScore(averageMulti) { var points = Math.floor(averageMulti * SCORE_SEGMENT_POINTS); score = Math.max(0, score + points); scoreText.setText(kgCollected.toFixed(2) + 'kg'); // Old score : scoreText.setText(String(score).padStart(6, '0')); distanceText.setText((distanceRun += SCORE_SEGMENT_DISTANCE) + 'm'); incrementText.setText((points === SCORE_MAX_POINTS ? '[MAX!] +' : '+') + points); } ; body.pushAnimation(animationRun, PLAYER_POSE_TRANSITION); }); var FragileNature = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var fragileNatureIndex = Math.floor(Math.random() * ROAD_GEN_FRAGILE_NATURE_ASSETS); var scale = 0.9 + 0.2 * Math.random(); self.attachAsset('fragileNature' + fragileNatureIndex, { anchorX: 0.5, anchorY: 1, scaleX: Math.random() < 0.5 ? -scale : scale, scaleY: scale }); self.taken = false; self.update = function () { if (self.taken) { // TODO : Do domthing when Fragile Nature is hit } else if (!self.taken && player.body.torso.intersects(self)) { self.taken = true; } }; return self; }); var DetritusFlying = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var detritusFlyingIndex = Math.floor(Math.random() * ROAD_GEN_DETRITUS_FLYING_ASSETS); var scale = 0.9 + 0.2 * Math.random(); self.attachAsset('detritusFlying' + detritusFlyingIndex, { anchorX: 0.5, anchorY: 0.5, scaleX: Math.random() < 0.5 ? -scale : scale, scaleY: scale }); self.update = function () { if (!isActive()) { return; } if (self.taken) { var targetX = recycleBin.x; var targetY = recycleBin.y; var startX = player.x; var startY = player.y; var speed = 15; var accelerationY = 1.0; // Adjust as needed var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var velocityX = dx / distance * speed; var velocityY = dy / distance * speed; if (distance > speed) { if (Math.abs(self.x - startX) < Math.abs(dx / 2)) { self.x += velocityX; self.y -= velocityY * 0.1 - accelerationY * 0.2; // Move up } else { self.x += velocityX; self.y += velocityY + accelerationY; // Move down with acceleration } self.scale.x *= 0.996; self.scale.y *= 0.996; self.rotation += 0.1; // Rotate detritusFlying on themselves when taken } else { self.x = targetX; self.y = targetY; self.destroy(); } } else if (!self.taken && (self.autoTake || player.body.torso.intersects(self))) { self.taken = true; // Flash Detritus in green for 500ms LK.effects.flashObject(self, 0x00ff00, 500); kgCollected += 0.01; // Add 0.01 to kgCollected var globalPosition = self.parent.toGlobal(self.position); self.parent.removeChild(self); game.addChildAt(self, game.getChildIndex(recycleBin)); self.position = game.toLocal(globalPosition); LK.getSound('collectDetritus').play(); if (!isBonusActive) { nbCollectedBeforeBonus++; } if (nbCollectedBeforeBonus >= BONUS_COLLECT_THRESHOLD) { log("Gained Bonus !!!"); startBonusAnimation(); } } else { self.rotation += 0.05 + (Math.random() - 0.25) * 0.1; } }; self.taken = false; return self; }); var Detritus = ConfigContainer.expand(function (config) { var self = ConfigContainer.call(this, config); var detritusIndex = Math.floor(Math.random() * ROAD_GEN_DETRITUS_ASSETS); var scale = 0.9 + 0.2 * Math.random(); self.attachAsset('detritus' + detritusIndex, { anchorX: 0.5, anchorY: 0.5, scaleX: Math.random() < 0.5 ? -scale : scale, scaleY: scale }); self.taken = false; self.update = function () { if (!isActive()) { return; } if (self.taken) { var targetX = recycleBin.x; var targetY = recycleBin.y; var startX = player.x; var startY = player.y; var speed = 15; var accelerationY = 1.0; // Adjust as needed var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); var velocityX = dx / distance * speed; var velocityY = dy / distance * speed; if (distance > speed) { if (Math.abs(self.x - startX) < Math.abs(dx / 2)) { self.x += velocityX; self.y -= velocityY * 0.5 - accelerationY * 0.2; // Move up } else { self.x += velocityX; self.y += velocityY + accelerationY; // Move down with acceleration } self.scale.x *= 0.996; self.scale.y *= 0.996; self.rotation += 0.1; // Rotate detritus on themselves when taken } else { self.x = targetX; self.y = targetY; self.destroy(); } } else if (!self.taken && (self.autoTake || player.body.torso.intersects(self))) { self.taken = true; // Flash DetritusFlying in green for 500ms LK.effects.flashObject(self, 0x00ff00, 500); kgCollected += 0.02; // Add 0.01 to kgCollected var globalPosition = self.parent.toGlobal(self.position); self.parent.removeChild(self); game.addChildAt(self, game.getChildIndex(recycleBin)); self.position = game.toLocal(globalPosition); LK.getSound('collectDetritus').play(); if (!isBonusActive) { nbCollectedBeforeBonus++; } if (nbCollectedBeforeBonus >= BONUS_COLLECT_THRESHOLD) { log("Gained Bonus !!!"); startBonusAnimation(); } } }; return self; }); /** * config { * x : Number || 0, // See: ConfigContainer * y : Number || 0, // See: ConfigContainer * rotation : Number || 0, // See: ConfigContainer * anchorX : Number || 0, * anchorY : Number || 1, * size : Number || TEXT_DEFAULT_SIZE, * weight : Number || TEXT_DEFAULT_WEIGHT, * font : String || TEXT_DEFAULT_FONT, * fill : String || TEXT_DEFAULT_FILL, * border : String || TEXT_DEFAULT_BORDER, * } **/ var BorderedText = ConfigContainer.expand(function (text, config) { var self = ConfigContainer.call(this, config); config = config || {}; ; var anchorX = config.anchorX !== undefined ? config.anchorX : 0; var anchorY = config.anchorY !== undefined ? config.anchorY : 1; var size = config.size !== undefined ? config.size : TEXT_DEFAULT_SIZE; var weight = config.weight !== undefined ? config.weight : TEXT_DEFAULT_WEIGHT; var font = config.font !== undefined ? config.font : TEXT_DEFAULT_FONT; var textFill = config.fill !== undefined ? config.fill : TEXT_DEFAULT_FILL; var borderFill = config.border !== undefined ? config.border : TEXT_DEFAULT_BORDER; var textAssets = []; var mainAsset; ; self.setText = setText; self.setFill = setFill; ; function setText(newText) { for (var i = 0; i < textAssets.length; i++) { textAssets[i].setText(newText); } } function setFill(newFill) { textFill = newFill; mainAsset.fill = newFill; } function buildTextAssets(newText) { for (var i = 0; i < TEXT_OFFSETS.length; i++) { var main = i === TEXT_OFFSETS.length - 1; var fill = main ? textFill : borderFill; var textAsset = textAssets[i]; if (textAsset) { textAsset.destroy(); } textAsset = self.addChild(new Text2(newText, { fill: fill, font: font, size: size })); textAsset.anchor = { x: anchorX, y: anchorY }; // NOTE: Cannot be set in config textAsset.x = TEXT_OFFSETS[i][0] * weight; // NOTE: Cannot be set in config textAsset.y = TEXT_OFFSETS[i][1] * weight; // NOTE: Cannot be set in config textAssets[i] = textAsset; } mainAsset = textAssets[TEXT_OFFSETS.length - 1]; } ; buildTextAssets(text); return self; }); var IntroPosterTrail = Container.expand(function () { var self = Container.call(this); var trailSquares = []; // Function to create a new trail square function createTrailSquare() { var square = self.attachAsset('square', { anchorX: 0.5, anchorY: 0.5, width: 5, height: 50, alpha: 0.8 }); var angle = Math.random() * Math.PI + Math.PI / 2; square.rotation = angle; trailSquares.push(square); } self.speed = 8; // Update function to animate the trail squares self.update = function () { if (LK.ticks % 2 == 0) { createTrailSquare(); } for (var i = trailSquares.length - 1; i >= 0; i--) { var square = trailSquares[i]; square.alpha -= 0.003; square.x += Math.cos(square.rotation + Math.PI / 2) * self.speed; square.y += Math.sin(square.rotation + Math.PI / 2) * self.speed; if (square.alpha <= 0) { square.destroy(); trailSquares.splice(i, 1); } } }; for (var i = 0; i < 50; i++) { createTrailSquare(); } return self; }); var Starfield = Container.expand(function (config) { var self = Container.call(this); config = config || {}; var starCount = config.starCount || 100; var starColor = config.starColor || 0xFFFFFF; var starSize = config.starSize || 2; for (var i = 0; i < starCount; i++) { var sizeVar = Math.random() * 3; var star = self.attachAsset('circle', { width: starSize + sizeVar, height: starSize + sizeVar, color: starColor, x: Math.random() * GAME_WIDTH, y: Math.random() * GAME_HEIGHT, anchorX: 0.5, anchorY: 0.5 }); star.direction = Math.random() < 0.5 ? 1 : -1; // Randomly set direction to 1 or -1 } // Add alpha animation to random stars self.update = function () { for (var i = 0; i < starsToAnimate.length; i++) { var star = starsToAnimate[i]; star.alpha += star.direction * 0.015; // Change alpha based on direction if (star.alpha <= 0.1 || star.alpha >= 1) { star.direction *= -1; // Reverse direction if alpha goes out of bounds } } if (help1 && help1 && help1.visible) { help1.alpha = 0.7 + 0.3 * Math.sin(LK.ticks / 30 + Math.PI / 2); help2.alpha = 0.7 + 0.3 * Math.sin(LK.ticks / 30); } }; function selectRandomStars() { starsToAnimate = []; for (var i = 0; i < 20; i++) { var randomIndex = Math.floor(Math.random() * self.children.length); starsToAnimate.push(self.children[randomIndex]); } } starAnimationInterval = LK.setInterval(selectRandomStars, 3000); // Select 10 stars every 3 seconds return self; }); var StartButton = Container.expand(function () { var self = Container.call(this); // Attach the start button asset var button = self.attachAsset('startButton', { anchorX: 0.5, anchorY: 0.5 }); // Attach the start recycle asset var recycle = self.attachAsset('startRecycle', { anchorX: 0.5, anchorY: 0.5 }); var startButtonText = self.attachAsset('startText', { anchorX: 0.5, anchorY: 0.5, rotation: -0.03, x: 7, y: 570 }); //startButtonText.x = GAME_WIDTH / 2; //startButtonText.y = road.y + 580; // Add update function to animate recycle rotation self.update = function () { recycle.rotation += 0.005; // Adjust rotation speed as needed button.rotation -= 0.005; // Adjust rotation speed as needed //introPoster.alpha = 0.8 + 0.2 * Math.sin(LK.ticks / 100); // Animate alpha from 0.5 to 1 and vice versa introPosterTrail.alpha = 0.8 + 0.2 * Math.sin(LK.ticks / 100); //recycle.alpha = 0.5 + 0.5 * Math.sin(LK.ticks / 30); // Animate alpha from 1 to 0 and vice versa }; // Event handler for button press self.down = function (x, y, obj) { isStarted = true; LK.getSound('startButton').play(); // Play startButton audio LK.setTimeout(function () { LK.playMusic('bgMusic', { loop: true }); }, 100); recycleBin.visible = true; recycleBinBack.visible = true; recycleBin.alpha = 0; recycleBinBack.alpha = 0; var binFadeInInterval = LK.setInterval(function () { if (recycleBin.alpha < 1) { recycleBin.alpha += 0.05; recycleBinBack.alpha += 0.05; } else { LK.clearInterval(binFadeInInterval); } }, 100); introPoster.destroy(); // Remove the intro poster introPosterTrail.destroy(); // Remove the intro poster trail sun.visible = true; help1.visible = true; help2.visible = true; LK.setTimeout(function () { help1.destroy(); help2.destroy(); }, 5000); self.destroy(); // Remove the start button after it's pressed }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x121B20 // Sky blue color }); /**** * Game Code ****/ /*if (isBonusStartAnim && bonus.update) { bonus.update(); } */ // Always call move and tick methods from the main tick method in the 'Game' class. var isDebug = false; var _console = console; var isStarted = false; var isBonusStartAnim = false; var isBonusActive = false; //============================================================================== ; // Math Constants / Pre-calculations var MATH_4_PI = Math.PI * 4; var MATH_2_PI = Math.PI * 2; var MATH_HALF_PI = Math.PI / 2; var MATH_THIRD_PI = Math.PI / 3; var MATH_QUARTER_PI = Math.PI / 4; var MATH_FIFTH_PI = Math.PI / 5; var MATH_SIXTH_PI = Math.PI / 5; var MATH_EIGHTH_PI = Math.PI / 8; var MATH_HALF_ROOT_3 = Math.sqrt(3) / 2; // Required by: TEXT_OFFSETS, BorderedText, BorderedSymbol, BorderedShape, SymbolText ; // Text Settings var TEXT_OFFSETS = [[0, 1], [MATH_HALF_ROOT_3, 0.5], [MATH_HALF_ROOT_3, -0.5], [0, -1], [-MATH_HALF_ROOT_3, -0.5], [-MATH_HALF_ROOT_3, 0.5], [0, 0]]; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText var TEXT_DEFAULT_WEIGHT = 4; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText var TEXT_DEFAULT_BORDER = '#000000'; // Required by: BorderedText, BorderedSymbol, BorderedShape, SymbolText var TEXT_DEFAULT_FILL = '#FFFFFF'; // Required by: BorderedText, SymbolText var TEXT_DEFAULT_FONT = 'Courier'; // Required by: BorderedText, SymbolText var TEXT_DEFAULT_SIZE = 80; // Required by: BorderedText, SymbolText ; // Game Constants var GAME_TICKS = 60; var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; ; // Road Constants var ROAD_SEGMENT_DISTANCE = 1.0; var ROAD_SEGMENT_POINTS = 100; var ROAD_SEGMENT_COUNT = 30; var ROAD_SEGMENT_ANGLE = MATH_2_PI / ROAD_SEGMENT_COUNT; var ROAD_SEGMENT_HEIGHT = 1000; var ROAD_SEGMENT_DESTROY = -2; var ROAD_SEGMENT_FADEOUT = 0.015; var ROAD_MAX_RIVER_SEGMENTS = 1; var ROAD_MAX_WALL_SEGMENTS = 1; var ROAD_FREE_RUN_COUNT = 5; var ROAD_STEP_COUNT = 5; var ROAD_STEP_DEFAULT = 10; var ROAD_STEP_HEIGHT_BASE = 512; var ROAD_STEP_HEIGHT_INCREMENT = 20; var ROAD_STEP_CHANCE_BASE = 0; //0.1; var ROAD_STEP_CHANCE_INCREMENT = 0; //0.05; var ROAD_GEN_PLANT_ASSETS = 3; var ROAD_GEN_PLANT_MAX = 3; var ROAD_GEN_TREE_ASSETS = 4; var ROAD_GEN_TREE_CHANCE = 0; //0.1; var ROAD_GEN_CLOUD_ASSETS = 4; var ROAD_GEN_CLOUD_CHANCE = 0.2; var ROAD_GEN_DETRITUS_ASSETS = 2; var ROAD_GEN_DETRITUS_CHANCE = 0.2; var ROAD_GEN_DETRITUS_FLYING_ASSETS = 2; var ROAD_GEN_DETRITUS_FLYING_CHANCE = 0.2; var ROAD_GEN_FRAGILE_NATURE_ASSETS = 2; var ROAD_GEN_FRAGILE_NATURE_CHANCE = 0.1; var ROAD_GEN_LAVA_SIZE = 1; var ROAD_GEN_WALL_ASSETS = 1; var ROAD_GEN_WALL_CHANCE = 0.1; ; // Player Constants var PLAYER_SPACING = ROAD_SEGMENT_ANGLE / 8; // 1/8 of a segment var PLAYER_POSE_TRANSITION = 0.1; var PLAYER_GRAVITY = 0.02; var PLAYER_JUMP_STEP_MIN = 1.5; // 720; // 1.0; var PLAYER_JUMP_STEP_MAX = 2.0; //1500; //2.0; var PLAYER_JUMP_STEP_INCREMENT = 0.75; //; 0.15; var PLAYER_ANIMATION_SPEED_BASE = 0.02; var PLAYER_SCALE_BASE = 1; //0.5; var PLAYER_SPEED_BASE = MATH_2_PI / (GAME_TICKS * 10); // 10s to complete a revolution var PLAYER_SPEED_FACTOR_BASE = 1.0; var PLAYER_SPEED_FACTOR_MAX = 2.0; //1.5; var PLAYER_SPEED_FACTOR_INCREMENT = 0.0015; //0.001; var PLAYER_SPEED_DECREMENT = 0.005; ; // Scoring Constants var SCORE_TOTAL_DISTANCE = 500; var SCORE_SEGMENT_DISTANCE = 1; var SCORE_SEGMENT_POINTS = 100; var SCORE_STOPPED_FACTOR = -0.2; var SCORE_MAX_POINTS = SCORE_SEGMENT_POINTS * PLAYER_SPEED_FACTOR_MAX; // Bonus Constants var BONUS_COLLECT_THRESHOLD = 50; var BONUS_DURATION_SEC = 10; //============================================================================== // Game Instances & Variables //============================================================================== ; // Variables var level = 0; var score = 0; var winningTime = 0; var gameOver = false; var distanceRemaining = SCORE_TOTAL_DISTANCE; var distanceRun = 0; var kgCollected = 0; var nbCollectedBeforeBonus = 0; // Number of detritus collected since last bonus var bonusLastStartTime = 0; ; var startY = 0; // Variable to store the initial Y position for swipe detection var swipeStarted = false; // Flag to start detecting swipe only after tap // Instances var background = game.addChild(LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2 })); var starfield = game.addChild(new Starfield({ starCount: 200, starColor: 0xFFFFFF, starSize: 2 })); var sun = game.addChild(new Sun({ x: GAME_WIDTH / 2, y: 50 })); sun.visible = false; var introPosterTrail = game.addChild(new IntroPosterTrail()); var introPoster = game.addChild(LK.getAsset('introPoster', { anchorX: 0.5, anchorY: 0.5, x: 870, y: 600, alpha: 1 })); introPosterTrail.x = introPoster.x; introPosterTrail.y = introPoster.y + 400; var playerContainer = game.addChild(new Container()); var roadContainer = game.addChild(new Container()); var road = roadContainer.addChild(new Road({ x: GAME_WIDTH / 2, y: GAME_HEIGHT - GAME_WIDTH / 2 })); var player = playerContainer.addChild(new Player({ x: road.x, y: road.y, scale: 0.5 })); var distanceText = game.addChild(new BorderedText(distanceRun + 'm', { x: road.x, y: road.y - TEXT_DEFAULT_SIZE, anchorX: 0.5, anchorY: 1 })); var scoreText = game.addChild(new BorderedText('0.00kg', { x: road.x, y: road.y, size: TEXT_DEFAULT_SIZE * 1.2, anchorX: 0.5, anchorY: 0.5 })); var multiplierText = game.addChild(new BorderedText('collected', { x: road.x, y: road.y + TEXT_DEFAULT_SIZE * 0.8, size: TEXT_DEFAULT_SIZE * 0.8, anchorX: 0.5, anchorY: 0 })); multiplierText.visible = true; var incrementText = game.addChild(new BorderedText('', { x: road.x - 300, y: road.y, anchorX: 1, anchorY: 0.5 })); incrementText.visible = false; var winningText = game.addChild(new BorderedText('', { x: GAME_WIDTH / 2, y: 400, anchorX: 0.5, anchorY: 0.5, size: 2 * TEXT_DEFAULT_SIZE })); ; var recycleBinBack = game.addChild(LK.getAsset('recycleBinBack', { anchorX: 0.5, anchorY: 0.5, x: 250, //450, y: 1750, visible: false })); ; var recycleBin = game.addChild(LK.getAsset('recycleBin', { anchorX: 0.5, anchorY: 0.5, x: 250, //450, y: 1750, visible: false })); ; var startButton = game.addChild(new StartButton()); startButton.x = GAME_WIDTH / 2; startButton.y = road.y; ; var help1 = game.addChild(LK.getAsset('help1', { anchorX: 0.5, anchorY: 0.5, x: 220, y: 2732 - 220, blendMode: 1, visible: false })); ; var help2 = game.addChild(LK.getAsset('help2', { anchorX: 0.5, anchorY: 0.5, x: 2048 - 220, y: 2732 - 220, blendMode: 1, visible: false })); ; //============================================================================== // Global events //============================================================================== ; var startY = 0; game.down = function (x, y, obj) { startY = y; swipeStarted = true; }; game.move = function (x, y, obj) { if (isBonusActive || !swipeStarted) { return; } if (startY - y > 50) { // Detect swipe up player.jumpStart(); } if (startY - y < -50) { // Detect swipe down player.slideStart(); } }; game.up = function (x, y, obj) { if (isBonusActive) { return; } player.jumpEnd(); startY = 0; swipeStarted = false; }; ; //============================================================================== // Global functions //============================================================================== ; // Helpers function log() { if (isDebug) { _console.log.apply(_console, arguments); } } ; function isActive() { return isStarted && !isBonusStartAnim && !player.isDead; } ; function callGameOver(lost) { gameOver = true; winningTime = LK.ticks; LK.setScore(score + kgCollected * 100); LK.stopMusic(); winningText.setText('The end'); distanceText.y += 500; scoreText.y += 500; multiplierText.y += 500; // Check if winningTime is set and show game over screen after 60 ticks game.update = function () { if (lost || winningTime && LK.ticks >= winningTime + 120) { LK.setTimeout(function () { LK.showGameOver(); }, 1000); LK.clearInterval(starAnimationInterval); } }; } ; function startBonusAnimation() { log('startBonusAnimation...'); nbCollectedBeforeBonus = 0; isBonusStartAnim = true; // Set alpha of all taken detritus to 0 for (var i = 0; i < game.children.length; i++) { var child = game.children[i]; if (child.taken) { log("IS TAKEN : ", child); child.alpha = 0; } } // Play bonus start sound LK.getSound('bonusStart').play(); // Flash screen green for 500ms to indicate bonus start LK.effects.flashScreen(0x00ff00, 500); // Create a bonus asset at the recycleBin position var bonus = game.addChild(LK.getAsset('bonus', { anchorX: 0.5, anchorY: 0.5, width: 10, height: 10, x: recycleBin.x, y: recycleBin.y })); // Animate bonus: move to road x,y while increasing width and height to 1024 var targetX = road.x; var targetY = road.y; var targetWidth = 1024; var targetHeight = 1024; var duration = 40; // Duration of the animation in milliseconds var duration2 = 30; // Duration of the animation in milliseconds var startTime = LK.ticks; var startTime2 = LK.ticks; bonus.update = function () { var elapsed = LK.ticks - startTime; var progress = Math.min(elapsed / duration, 1); if (progress < 1) { bonus.x = recycleBin.x + (targetX - recycleBin.x) * progress; bonus.y = recycleBin.y + (targetY - recycleBin.y) * progress; bonus.width = 100 + (targetWidth - 100) * progress; bonus.height = 100 + (targetHeight - 100) * progress; } if (progress > 0.5) { LK.getSound('bonusMove').play(); } if (progress === 1 && elapsed > duration * 2) { // Set new target to player position targetX = player.x; targetY = player.y - player.height / 2; targetWidth = 10; targetHeight = 10; startTime2 = LK.ticks; // Reset start time for the new animation phase bonus.update = function () { var elapsed2 = LK.ticks - startTime2; var progress2 = Math.min(elapsed2 / duration2, 1); if (progress2 > 0.5) { LK.getSound('bonusMove').play(); } if (progress2 < 1) { bonus.x = road.x + (targetX - road.x) * progress2; bonus.y = road.y + (targetY - road.y) * progress2; bonus.width = 1024 + (targetWidth - 1024) * progress2; bonus.height = 1024 + (targetHeight - 1024) * progress2; } if (progress2 === 1) { bonus.destroy(); isBonusActive = true; isBonusStartAnim = false; LK.stopMusic(); LK.playMusic('bonusMusic'); player.enterBonusState(); // Schedule stopBonus to be called after BONUS_DURATION_SEC seconds LK.setTimeout(stopBonus, BONUS_DURATION_SEC * 1000); bonusLastStartTime = Date.now(); } }; } }; } ; function stopBonus() { log('stopBonus...'); player.exitBonusState(); LK.stopMusic(); LK.playMusic('bgMusic', { loop: true }); nbCollectedBeforeBonus = 0; isBonusActive = false; increaseLevel(); } ; function increaseLevel() { log('increaseLevel...'); level++; PLAYER_SPEED_FACTOR_MAX += level / 10; ROAD_GEN_DETRITUS_CHANCE = 0.1; ROAD_GEN_DETRITUS_FLYING_CHANCE = 0.1; ROAD_GEN_FRAGILE_NATURE_CHANCE = 0.2; // Rivers of lava ROAD_GEN_LAVA_SIZE = 2; ROAD_GEN_WALL_CHANCE = 0.2; ROAD_GEN_DETRITUS_ASSETS = 4; ROAD_GEN_DETRITUS_FLYING_ASSETS = 4; } ; // Animations & handlers function animateProperty(animationPose, blendPose, blendAlpha, key, baseValue) { var animationPoseValue = (animationPose || {})[key] || 0; var blendPoseValue = (blendPose || {})[key] || 0; return (baseValue || 0) + animationPoseValue * (1 - blendAlpha) + blendPoseValue * blendAlpha; } function animationRun(alpha) { // Animation constants var armUpperAngle = MATH_FIFTH_PI; var armLowerAngle = -5 * MATH_EIGHTH_PI; var legLowerAngle = MATH_EIGHTH_PI; // Sinusoidals var rightSinusoidal = Math.cos(MATH_2_PI * (alpha + 0.5)); var leftSinusoidal = Math.cos(MATH_2_PI * alpha); var doubleSinusoidal = Math.cos(MATH_4_PI * alpha); // Animation calculations var armUpperRightSwing = -rightSinusoidal * MATH_QUARTER_PI; var armUpperLeftSwing = -leftSinusoidal * MATH_QUARTER_PI; var legUpperRightSwing = rightSinusoidal * MATH_THIRD_PI; var legUpperLeftSwing = leftSinusoidal * MATH_THIRD_PI; return { BODY_OFFSET: doubleSinusoidal * 10, HEAD_ROTATION: (1 + doubleSinusoidal) * Math.PI / 32, ARM_UPPER_RIGHT_ROTATION: armUpperAngle + armUpperRightSwing, ARM_UPPER_LEFT_ROTATION: armUpperAngle + armUpperLeftSwing, ARM_LOWER_RIGHT_ROTATION: armLowerAngle + armUpperRightSwing / 2, ARM_LOWER_LEFT_ROTATION: armLowerAngle + armUpperLeftSwing / 2, LEG_UPPER_RIGHT_ROTATION: legUpperRightSwing, LEG_UPPER_LEFT_ROTATION: legUpperLeftSwing, LEG_LOWER_RIGHT_ROTATION: legLowerAngle + (alpha > 0.5 ? MATH_THIRD_PI + (1 - Math.abs(rightSinusoidal)) * MATH_SIXTH_PI : Math.abs(-legUpperRightSwing)), LEG_LOWER_LEFT_ROTATION: legLowerAngle + (alpha <= 0.5 ? MATH_THIRD_PI + (1 - Math.abs(leftSinusoidal)) * MATH_SIXTH_PI : Math.abs(-legUpperLeftSwing)), FOOT_RIGHT_ROTATION: Math.max(0, legUpperRightSwing * 2 / 3) - legLowerAngle, FOOT_LEFT_ROTATION: Math.max(0, legUpperLeftSwing * 2 / 3) - legLowerAngle }; } function animationJump(alpha) { var sinusoidal = Math.cos(MATH_2_PI * alpha); return animationRun(0.35 + sinusoidal * 0.02); } function animationStand(alpha) { var sinusoidal = Math.cos(MATH_2_PI * alpha); var offsetAngle = Math.PI / 16; var sharedAngle = (2 + sinusoidal) * Math.PI / 64; return { BODY_OFFSET: sinusoidal * 5, ARM_UPPER_RIGHT_ROTATION: 0.5 * offsetAngle, ARM_UPPER_LEFT_ROTATION: 3 * offsetAngle, ARM_LOWER_RIGHT_ROTATION: -4 * offsetAngle, ARM_LOWER_LEFT_ROTATION: -4 * offsetAngle, LEG_UPPER_RIGHT_ROTATION: 1.5 * offsetAngle - sharedAngle, LEG_UPPER_LEFT_ROTATION: -1.5 * offsetAngle - sharedAngle, LEG_LOWER_RIGHT_ROTATION: 2 * sharedAngle, LEG_LOWER_LEFT_ROTATION: 2 * sharedAngle, FOOT_RIGHT_ROTATION: -sharedAngle - 1.5 * offsetAngle, FOOT_LEFT_ROTATION: -sharedAngle + 1.5 * offsetAngle }; } // On belly head front function animationSlide(alpha) { return { BODY_ROTATION: Math.PI / 2, // Rotate body 90 degrees BODY_OFFSET: -30, // Adjust body position to align with ground HEAD_ROTATION: Math.PI / 4, // Arm Right ARM_UPPER_RIGHT_ROTATION: Math.PI / 4, ARM_LOWER_RIGHT_ROTATION: -Math.PI / 4, // Arm Left ARM_UPPER_LEFT_ROTATION: -Math.PI, ARM_LOWER_LEFT_ROTATION: -Math.PI / 2, // Upper Legs LEG_UPPER_RIGHT_ROTATION: Math.PI / 10, LEG_UPPER_LEFT_ROTATION: Math.PI / 10, // Lower legs LEG_LOWER_RIGHT_ROTATION: Math.PI / 6, LEG_LOWER_LEFT_ROTATION: Math.PI / 6, FOOT_RIGHT_ROTATION: 0, FOOT_LEFT_ROTATION: 0 }; } function animationBonus(alpha) { // Use a sinusoidal movement for a slight floating effect var floatOffset = Math.sin(MATH_2_PI * alpha) * 10; return { BODY_ROTATION: Math.PI / 4, // 45° angle BODY_OFFSET: -50 + floatOffset, // Raised in the air with a slight float // Head tilted slightly back for a heroic look HEAD_ROTATION: -Math.PI / 8, // Right arm outstretched in front ARM_UPPER_RIGHT_ROTATION: -Math.PI / 1.5, // Shoulder at 90° ARM_LOWER_RIGHT_ROTATION: -Math.PI / 8, // Slight bend at elbow // Left arm slightly bent and back ARM_UPPER_LEFT_ROTATION: Math.PI / 4, ARM_LOWER_LEFT_ROTATION: -Math.PI / 3, // Legs in a dynamic pose LEG_UPPER_RIGHT_ROTATION: Math.PI / 6, LEG_LOWER_RIGHT_ROTATION: Math.PI / 3, LEG_UPPER_LEFT_ROTATION: Math.PI / 6, LEG_LOWER_LEFT_ROTATION: Math.PI / 3, /* LEG_UPPER_LEFT_ROTATION: Math.PI / 8, LEG_LOWER_LEFT_ROTATION: Math.PI / 2, */ // Feet angled for a more dynamic pose FOOT_RIGHT_ROTATION: -Math.PI / 6, FOOT_LEFT_ROTATION: -Math.PI / 4 }; } function tintPlayer(color) { player.body.torso.tint = color; // Tint the player's torso player.body.legUpperLeft.children[0].tint = color; // Tint the player's upper left leg player.body.legUpperRight.children[0].tint = color; // Tint the player's upper right leg player.body.armUpperLeft.children[0].tint = color; // Tint the player's upper left arm player.body.armUpperRight.children[0].tint = color; // Tint the player's upper right arm player.body.armLowerLeft.tint = color; player.body.armLowerRight.tint = color; player.body.legLowerLeft.tint = color; player.body.legLowerRight.tint = color; player.body.pelvis.tint = color; // Tint the player's pelvis player.body.head.tint = color; // Tint the player's head player.body.footRight.tint = color; player.body.footLeft.tint = color; } var starAnimationInterval; var starsToAnimate = [];
===================================================================
--- original.js
+++ change.js
@@ -1107,18 +1107,19 @@
var angle = Math.random() * Math.PI + Math.PI / 2;
square.rotation = angle;
trailSquares.push(square);
}
+ self.speed = 8;
// Update function to animate the trail squares
self.update = function () {
if (LK.ticks % 2 == 0) {
createTrailSquare();
}
for (var i = trailSquares.length - 1; i >= 0; i--) {
var square = trailSquares[i];
square.alpha -= 0.003;
- square.x += Math.cos(square.rotation + Math.PI / 2) * 5;
- square.y += Math.sin(square.rotation + Math.PI / 2) * 5;
+ square.x += Math.cos(square.rotation + Math.PI / 2) * self.speed;
+ square.y += Math.sin(square.rotation + Math.PI / 2) * self.speed;
if (square.alpha <= 0) {
square.destroy();
trailSquares.splice(i, 1);
}
@@ -1156,8 +1157,12 @@
if (star.alpha <= 0.1 || star.alpha >= 1) {
star.direction *= -1; // Reverse direction if alpha goes out of bounds
}
}
+ if (help1 && help1 && help1.visible) {
+ help1.alpha = 0.7 + 0.3 * Math.sin(LK.ticks / 30 + Math.PI / 2);
+ help2.alpha = 0.7 + 0.3 * Math.sin(LK.ticks / 30);
+ }
};
function selectRandomStars() {
starsToAnimate = [];
for (var i = 0; i < 20; i++) {
@@ -1179,16 +1184,23 @@
var recycle = self.attachAsset('startRecycle', {
anchorX: 0.5,
anchorY: 0.5
});
+ var startButtonText = self.attachAsset('startText', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ rotation: -0.03,
+ x: 7,
+ y: 570
+ });
+ //startButtonText.x = GAME_WIDTH / 2;
+ //startButtonText.y = road.y + 580;
// Add update function to animate recycle rotation
self.update = function () {
recycle.rotation += 0.005; // Adjust rotation speed as needed
button.rotation -= 0.005; // Adjust rotation speed as needed
//introPoster.alpha = 0.8 + 0.2 * Math.sin(LK.ticks / 100); // Animate alpha from 0.5 to 1 and vice versa
introPosterTrail.alpha = 0.8 + 0.2 * Math.sin(LK.ticks / 100);
- help1.alpha = 0.7 + 0.3 * Math.sin(LK.ticks / 30 + Math.PI / 2);
- help2.alpha = 0.7 + 0.3 * Math.sin(LK.ticks / 30);
//recycle.alpha = 0.5 + 0.5 * Math.sin(LK.ticks / 30); // Animate alpha from 1 to 0 and vice versa
};
// Event handler for button press
self.down = function (x, y, obj) {
@@ -1218,9 +1230,9 @@
help2.visible = true;
LK.setTimeout(function () {
help1.destroy();
help2.destroy();
- }, 3000);
+ }, 5000);
self.destroy(); // Remove the start button after it's pressed
};
return self;
});
@@ -1234,13 +1246,13 @@
/****
* Game Code
****/
-// Always call move and tick methods from the main tick method in the 'Game' class.
/*if (isBonusStartAnim && bonus.update) {
bonus.update();
}
*/
+// Always call move and tick methods from the main tick method in the 'Game' class.
var isDebug = false;
var _console = console;
var isStarted = false;
var isBonusStartAnim = false;
@@ -1439,8 +1451,9 @@
;
var startButton = game.addChild(new StartButton());
startButton.x = GAME_WIDTH / 2;
startButton.y = road.y;
+;
var help1 = game.addChild(LK.getAsset('help1', {
anchorX: 0.5,
anchorY: 0.5,
x: 220,
@@ -1625,8 +1638,10 @@
ROAD_GEN_DETRITUS_FLYING_CHANCE = 0.1;
ROAD_GEN_FRAGILE_NATURE_CHANCE = 0.2; // Rivers of lava
ROAD_GEN_LAVA_SIZE = 2;
ROAD_GEN_WALL_CHANCE = 0.2;
+ ROAD_GEN_DETRITUS_ASSETS = 4;
+ ROAD_GEN_DETRITUS_FLYING_ASSETS = 4;
}
;
// Animations & handlers
function animateProperty(animationPose, blendPose, blendAlpha, key, baseValue) {
white
circle sliced into many pieces, flat image. 2d, white background, shadowless.
pixel art of a tall, tree. game asset, 2d, white background, shadowless.
pixel art cloud. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
dark space.
flying lava bubble. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
a bonus crystal ball with the recycle symbol. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
top view A green round start button empty in the center like a ring.