/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bird (obstacle, cartoon) var Bird = Container.expand(function () { var self = Container.call(this); // Use custom bird asset var bird = self.attachAsset('bird_asset', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); self.bird = bird; self.moveDir = Math.random() < 0.5 ? -1 : 1; self.moveSpeed = 6 + Math.random() * 3; self.range = 400 + Math.random() * 800; self.baseX = 0; self.baseY = 0; self.t = Math.random() * 1000; self.setStart = function (x, y) { self.baseX = x; self.baseY = y; self.x = x; self.y = y; }; self.update = function () { self.t += 1; // Move left-right in a sine wave self.x = self.baseX + Math.sin(self.t / 60) * self.range * self.moveDir; // Optionally, add some up-down movement self.y = self.baseY + Math.sin(self.t / 30) * 40; }; return self; }); // Enemy Child (cartoon) var Child = Container.expand(function () { var self = Container.call(this); var body = self.attachAsset('child_cartoon', { anchorX: 0.5, anchorY: 1.0 }); self.body = body; return self; }); // Dog (chaser, cartoon) var Dog = Container.expand(function () { var self = Container.call(this); // Use custom dog asset var dog = self.attachAsset('dog_asset', { anchorX: 0.5, anchorY: 1.0, scaleX: 1.0, scaleY: 1.0 }); self.dog = dog; self.speed = 6 + Math.random() * 2; self.update = function () { // Chase the playerObj if (typeof playerObj !== "undefined" && playerObj) { var dx = playerObj.x - self.x; var dy = playerObj.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { var step = Math.min(self.speed, dist); self.x += dx / dist * step; self.y += dy / dist * step; } } }; return self; }); // Fountain (Goal, cartoon) var Fountain = Container.expand(function () { var self = Container.call(this); var f = self.attachAsset('fountain_cartoon', { anchorX: 0.5, anchorY: 0.5 }); self.f = f; return self; }); // Fridge (Bonus, cartoon) var Fridge = Container.expand(function () { var self = Container.call(this); var fridge = self.attachAsset('fridge_cartoon', { anchorX: 0.5, anchorY: 1.0 }); self.fridge = fridge; return self; }); // Player Ice Cream (cartoon) var IceCream = Container.expand(function () { var self = Container.call(this); // State: 'normal', 'old', 'melt', 'baby' self.state = 'normal'; self.age = 0; // 0: baby, 1: normal, 2: old, 3: melt // Attach cone (cartoon) var cone = self.attachAsset('cone_cartoon', { anchorX: 0.5, anchorY: 0.0, y: 120 }); // Attach scoop (ice cream, cartoon) var scoop = self.attachAsset('icecream_cartoon', { anchorX: 0.5, anchorY: 1.0, y: 120 }); self.scoop = scoop; self.cone = cone; // For visual aging self.setState = function (state) { if (state === self.state) return; self.state = state; if (state === 'normal') { scoop.texture = LK.getAsset('icecream_cartoon', {}).texture; } else if (state === 'old') { scoop.texture = LK.getAsset('icecream_old_cartoon', {}).texture; } else if (state === 'melt') { scoop.texture = LK.getAsset('icecream_melt_cartoon', {}).texture; } else if (state === 'baby') { scoop.texture = LK.getAsset('icecream_baby_cartoon', {}).texture; } }; // For bonus self.resetAge = function () { self.age = 0; self.setState('normal'); }; return self; }); // Shadow (Safe zone, cartoon) var Shadow = Container.expand(function () { var self = Container.call(this); var shadow = self.attachAsset('shadow_cartoon', { anchorX: 0.5, anchorY: 0.5 }); self.shadow = shadow; return self; }); // Sunbeam (Danger zone, for visual only, cartoon) var Sunbeam = Container.expand(function () { var self = Container.call(this); var sunbeam = self.attachAsset('sunbeam_cartoon', { anchorX: 0.5, anchorY: 0.5 }); self.sunbeam = sunbeam; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // Sky blue }); /**** * Game Code ****/ // Fallback for any missing asset // Cartoon-style image assets (replace simple shapes) // --- Game Variables --- var level = 1; var maxLevel = 30; var playerSpeed = 18; var childBaseSpeed = 4.5; // easier: slower child var childSpeed = childBaseSpeed; var shadowSpeed = 2.5; var shadowCount = 5; // easier: more shadows var shadowMinWidth = 400; // easier: wider shadows var shadowMaxWidth = 700; var sunbeamCount = 1; // easier: less sunbeams var sunbeamSpeed = 1.2; var fridgeChance = 0.35; // more chance for fridge var fridgeActive = false; var fridgeTimer = 0; var fridgeDuration = 120; // frames var playerAgingRate = 0.7; // easier: slower aging var playerMeltRate = 1.1; // easier: slower melt var playerAge = 0; // 0: baby, 1: normal, 2: old, 3: melt var playerMaxAge = 3; var playerInShadow = false; var playerInFridge = false; var playerMelt = 0; var playerMaxMelt = 120; // easier: more margin before melting var playerMeltWarning = false; var playerMeltSoundPlayed = false; var playerOldWarning = false; var playerOldSoundPlayed = false; var playerGoalReached = false; var playerDead = false; var playerWin = false; var distanceToGoal = 1500 + (level - 1) * 250; // easier: shorter distance var distanceTraveled = 0; var moveDir = { up: false, down: false, left: false, right: false }; var lastMoveTick = 0; var lastShadowTick = 0; var lastChildTick = 0; var lastFridgeTick = 0; var lastStepSound = 0; var childChaseDelay = 80; // child starts a bit later var childChaseStarted = false; var childChaseTick = 0; var childCatchDist = 120; // easier: more margin before caught var shadowList = []; var sunbeamList = []; var sunBeamObstacles = []; var birdList = []; var dogList = []; var fridgeObj = null; var fridgeUsed = false; var fountainObj = null; var childObj = null; var playerObj = null; var scoreTxt = null; var levelTxt = null; var meltBar = null; // --- Child funny behavior state --- var childBehavior = { mode: "chase", // chase, stumble, butterfly, idle timer: 0 }; // --- GUI --- // Score/Level text scoreTxt = new Text2('0', { size: 110, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); levelTxt = new Text2('Niveau 1', { size: 70, fill: 0xFFFFFF }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 120; // Melt bar (shows how close to melting) meltBar = new Text2('', { size: 60, fill: 0xF7E6B2 }); meltBar.anchor.set(0.5, 0); LK.gui.top.addChild(meltBar); meltBar.y = 210; // --- Game Setup --- function setupLevel() { // Reset distanceToGoal = 1500 + (level - 1) * 250; distanceTraveled = 0; playerAgingRate = 0.7 + (level - 1) * 0.13; playerMeltRate = 1.1 + (level - 1) * 0.18; childSpeed = childBaseSpeed + (level - 1) * 1.2; shadowCount = 5 + Math.floor((level - 1) * 1.2); sunbeamCount = 1 + Math.floor((level - 1) / 4); fridgeActive = false; fridgeUsed = false; playerGoalReached = false; playerDead = false; playerWin = false; playerMelt = 0; playerMaxMelt = 120; playerMeltWarning = false; playerMeltSoundPlayed = false; playerOldWarning = false; playerOldSoundPlayed = false; playerInShadow = false; playerInFridge = false; childChaseStarted = false; childChaseTick = 0; childCatchDist = 120; playerAge = 1; playerObj.resetAge(); childBehavior.mode = "chase"; childBehavior.timer = 0; // Remove old objects for (var i = 0; i < shadowList.length; i++) { shadowList[i].destroy(); } shadowList = []; for (var i = 0; i < sunbeamList.length; i++) { sunbeamList[i].destroy(); } sunbeamList = []; if (fridgeObj) { fridgeObj.destroy(); fridgeObj = null; } if (fountainObj) { fountainObj.destroy(); fountainObj = null; } if (childObj) { childObj.destroy(); childObj = null; } // Place player at bottom center playerObj.x = 2048 / 2; playerObj.y = 2732 - 300; // Place child at bottom, offset childObj = new Child(); childObj.x = 2048 / 2 + 200; childObj.y = 2732 - 300; game.addChild(childObj); // Place fountain at top center fountainObj = new Fountain(); fountainObj.x = 2048 / 2; fountainObj.y = 300; game.addChild(fountainObj); // Place shadows (random X, Y spaced along path) for (var i = 0; i < shadowCount; i++) { var s = new Shadow(); var sx = 300 + Math.random() * (2048 - 600); var sy = 2732 - 600 - (i + 1) * (distanceToGoal / (shadowCount + 1)); s.x = sx; s.y = sy; // Make trees (shadows) larger as level increases var levelShadowScale = 1 + (level - 1) * 0.18; var w = (shadowMinWidth + Math.random() * (shadowMaxWidth - shadowMinWidth)) * levelShadowScale; s.shadow.width = w; s.shadow.height = s.shadow.height * (0.95 + Math.random() * 0.15) * levelShadowScale; shadowList.push(s); game.addChild(s); } // Place sunbeams (now moving obstacles) for (var i = 0; i < sunbeamCount; i++) { var sb = new Sunbeam(); var sbx = 300 + Math.random() * (2048 - 600); var sby = 2732 - 600 - (i + 1) * (distanceToGoal / (sunbeamCount + 1)); sb.x = sbx; sb.y = sby; // Give each sunbeam a random horizontal speed and direction sb.moveDir = Math.random() < 0.5 ? -1 : 1; sb.moveSpeed = 2 + Math.random() * 2; sunbeamList.push(sb); game.addChild(sb); } // Add SunBeam obstacle from level 10+ if (typeof sunBeamObstacles !== "undefined") { for (var i = 0; i < sunBeamObstacles.length; i++) { sunBeamObstacles[i].destroy(); } } sunBeamObstacles = []; if (level >= 10) { // Add a SunBeam obstacle that moves left-right across the screen var sunBeam = new Sunbeam(); sunBeam.x = 2048 / 2; sunBeam.y = 2732 / 2 - 200; sunBeam.moveDir = 1; sunBeam.moveSpeed = 8 + (level - 10) * 0.7; sunBeamObstacles.push(sunBeam); game.addChild(sunBeam); } // Add birds from level 15+ if (typeof birdList !== "undefined") { for (var i = 0; i < birdList.length; i++) { birdList[i].destroy(); } } birdList = []; if (level >= 15) { // Add birds, more at level 20+ var birdCount = 1; if (level >= 20) birdCount = 2 + Math.floor((level - 20) * 0.7); for (var i = 0; i < birdCount; i++) { var bird = new Bird(); var bx = 400 + Math.random() * (2048 - 800); var by = 800 + Math.random() * (2732 - 1600); bird.setStart(bx, by); birdList.push(bird); game.addChild(bird); } } // Add dogs from level 25+ if (typeof dogList !== "undefined") { for (var i = 0; i < dogList.length; i++) { dogList[i].destroy(); } } dogList = []; if (level >= 25) { // Add dogs, more at higher levels var dogCount = 1 + Math.floor((level - 25) * 0.5); for (var i = 0; i < dogCount; i++) { var dog = new Dog(); dog.x = 2048 / 2 + (Math.random() < 0.5 ? -1 : 1) * (300 + Math.random() * 400); dog.y = 2732 - 600 - Math.random() * 400; dogList.push(dog); game.addChild(dog); } } // End game at level 30 if (level >= 30) { LK.setTimeout(function () { LK.showYouWin(); }, 1200); } // Place fridge (bonus) randomly, only if not already used if (Math.random() < fridgeChance) { fridgeObj = new Fridge(); fridgeObj.x = 400 + Math.random() * (2048 - 800); fridgeObj.y = 2732 - 600 - Math.random() * (distanceToGoal - 800); game.addChild(fridgeObj); fridgeActive = true; } // Place random ice puddles (obstacles that slow player) if (typeof puddleList !== "undefined") { for (var i = 0; i < puddleList.length; i++) { puddleList[i].destroy(); } } puddleList = []; var puddleCount = 2 + Math.floor(level / 2); for (var i = 0; i < puddleCount; i++) { var puddle = new Container(); var puddleAsset = puddle.attachAsset('icecream_melt_cartoon', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7 + Math.random() * 0.5, scaleY: 0.5 + Math.random() * 0.3 }); puddle.x = 200 + Math.random() * (2048 - 400); puddle.y = 2732 - 600 - Math.random() * (distanceToGoal - 800); puddle.slow = 0.5 + Math.random() * 0.3; puddleList.push(puddle); game.addChild(puddle); } // Update GUI scoreTxt.setText("Distance: " + Math.max(0, Math.floor(distanceToGoal - distanceTraveled)) + "m"); levelTxt.setText("Niveau " + level); meltBar.setText("Fraîcheur: " + Math.max(0, Math.floor(playerMaxMelt - playerMelt)) + "%"); } // --- Custom Background --- var backgroundObj = LK.getAsset('custom_background', { anchorX: 0, anchorY: 0, x: 0, y: 0 }); game.addChild(backgroundObj); // --- Player --- playerObj = new IceCream(); game.addChild(playerObj); // --- Tap-to-move: move player a short distance towards tap/click position --- // Remove GUI buttons, use tap anywhere to move player a short distance in that direction // Maximum distance the player can move per tap var tapMoveDistance = 180; // Handle tap/click on the game area game.down = function (x, y, obj) { if (playerDead || playerWin) return; // Clamp tap to game area var targetX = Math.max(100, Math.min(2048 - 100, x)); var targetY = Math.max(200, Math.min(2732 - 100, y)); // Compute direction vector from player to tap var dx = targetX - playerObj.x; var dy = targetY - playerObj.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist === 0) return; // Move only up to tapMoveDistance per tap var moveDist = Math.min(tapMoveDistance, dist); var moveX = dx / dist * moveDist; var moveY = dy / dist * moveDist; // Check for puddle slow var onPuddle = false; if (typeof puddleList !== "undefined") { for (var i = 0; i < puddleList.length; i++) { if (playerObj.intersects(puddleList[i])) { onPuddle = true; break; } } } var speedFactor = onPuddle ? 0.4 : 1; moveX *= speedFactor; moveY *= speedFactor; // New position var newX = playerObj.x + moveX; var newY = playerObj.y + moveY; // Clamp to game area newX = Math.max(100, Math.min(2048 - 100, newX)); newY = Math.max(200, Math.min(2732 - 100, newY)); // Only count distance if moving up (towards goal) if (distanceTraveled < distanceToGoal && newY < playerObj.y) { distanceTraveled += playerObj.y - newY; } playerObj.x = newX; playerObj.y = newY; // Play step sound LK.getSound('step').play(); }; // --- Main Game Update --- game.update = function () { if (playerDead || playerWin) return; // --- Player Movement --- // (Handled by tap-to-move in game.down) // Just update lastX/lastY for consistency playerObj.lastX = playerObj.x; playerObj.lastY = playerObj.y; // --- Shadows --- playerInShadow = false; for (var i = 0; i < shadowList.length; i++) { var s = shadowList[i]; if (playerObj.intersects(s)) { playerInShadow = true; break; } } // --- Sunbeams (moving obstacles, dangerous) --- for (var i = 0; i < sunbeamList.length; i++) { var sb = sunbeamList[i]; // Move sunbeam horizontally, bounce at screen edges sb.x += sb.moveDir * sb.moveSpeed; if (sb.x < 200) { sb.x = 200; sb.moveDir = 1; } if (sb.x > 2048 - 200) { sb.x = 2048 - 200; sb.moveDir = -1; } // If player touches a sunbeam, instant melt! if (!playerDead && playerObj.intersects(sb)) { playerObj.setState('melt'); playerDead = true; LK.effects.flashScreen(0xffe066, 1200); LK.getSound('melt').play(); LK.showGameOver(); return; } } // --- SunBeam obstacle (from level 10) --- if (typeof sunBeamObstacles !== "undefined") { for (var i = 0; i < sunBeamObstacles.length; i++) { var sb = sunBeamObstacles[i]; sb.x += sb.moveDir * sb.moveSpeed; if (sb.x < 200) { sb.x = 200; sb.moveDir = 1; } if (sb.x > 2048 - 200) { sb.x = 2048 - 200; sb.moveDir = -1; } if (!playerDead && playerObj.intersects(sb)) { playerObj.setState('melt'); playerDead = true; LK.effects.flashScreen(0xffe066, 1200); LK.getSound('melt').play(); LK.showGameOver(); return; } } } // --- Birds (from level 15) --- if (typeof birdList !== "undefined") { for (var i = 0; i < birdList.length; i++) { var bird = birdList[i]; if (bird.update) bird.update(); if (!playerDead && playerObj.intersects(bird)) { playerDead = true; LK.effects.flashScreen(0x222222, 1200); LK.getSound('danger').play(); LK.showGameOver(); return; } } } // --- Dogs (from level 25) --- if (typeof dogList !== "undefined") { for (var i = 0; i < dogList.length; i++) { var dog = dogList[i]; if (dog.update) dog.update(); // If dog catches player var dx = playerObj.x - dog.x; var dy = playerObj.y - dog.y; var dist = Math.sqrt(dx * dx + dy * dy); if (!playerDead && dist < 100) { playerDead = true; LK.effects.flashScreen(0xc68642, 1200); LK.getSound('danger').play(); LK.showGameOver(); return; } } } // --- Fridge (bonus) --- if (fridgeObj && !fridgeUsed && playerObj.intersects(fridgeObj)) { playerInFridge = true; fridgeUsed = true; playerObj.resetAge(); playerMelt = 0; LK.getSound('bonus').play(); // Animate fridge tween(fridgeObj, { alpha: 0 }, { duration: 600, onFinish: function onFinish() { fridgeObj.destroy(); fridgeObj = null; } }); } else { playerInFridge = false; } // --- Melting / Aging --- if (playerInFridge) { // No aging/melting } else if (playerInShadow) { // Age slowly (recover a little freshness in shadow) playerMelt -= 0.5; if (playerMelt < 0) playerMelt = 0; } else { // In sun: melt at exactly -1% per second (1% of playerMaxMelt per 60 ticks) playerMelt += playerMaxMelt / 100 / 60; if (!playerMeltWarning && playerMelt > playerMaxMelt * 0.7) { playerMeltWarning = true; LK.effects.flashObject(playerObj, 0xffe066, 400); LK.getSound('melt').play(); } if (playerMelt > playerMaxMelt) { // Melted! playerObj.setState('melt'); playerDead = true; LK.effects.flashScreen(0xffe066, 1200); LK.showGameOver(); return; } } // Age visually if in sun for long if (playerMelt > playerMaxMelt * 0.4 && playerMelt < playerMaxMelt * 0.7) { playerObj.setState('old'); } else if (playerMelt <= playerMaxMelt * 0.4) { playerObj.setState('normal'); } // --- Child (enemy) --- if (!childChaseStarted) { childChaseTick++; if (childChaseTick > childChaseDelay) { childChaseStarted = true; childBehavior.mode = "chase"; childBehavior.timer = 0; } } else { // --- Child funny behaviors --- childBehavior.timer--; if (childBehavior.timer <= 0) { // Randomly pick a new behavior var r = Math.random(); if (r < 0.15) { childBehavior.mode = "stumble"; childBehavior.timer = 40 + Math.floor(Math.random() * 30); } else if (r < 0.30) { childBehavior.mode = "butterfly"; childBehavior.timer = 50 + Math.floor(Math.random() * 40); } else if (r < 0.40) { childBehavior.mode = "idle"; childBehavior.timer = 30 + Math.floor(Math.random() * 20); } else { childBehavior.mode = "chase"; childBehavior.timer = 60 + Math.floor(Math.random() * 60); } } var cx = childObj.x, cy = childObj.y; var px = playerObj.x, py = playerObj.y; var dx = px - cx, dy = py - cy; var dist = Math.sqrt(dx * dx + dy * dy); if (childBehavior.mode === "chase") { if (dist > 1) { var step = Math.min(childSpeed, dist); childObj.x += dx / dist * step; childObj.y += dy / dist * step; } } else if (childBehavior.mode === "stumble") { // Stumble: move erratically, slower var angle = Math.random() * Math.PI * 2; childObj.x += Math.cos(angle) * 2.5; childObj.y += Math.sin(angle) * 2.5; } else if (childBehavior.mode === "butterfly") { // Butterfly: move in a small circle var t = LK.ticks % 360; childObj.x += Math.cos(t / 20) * 2.2; childObj.y += Math.sin(t / 20) * 2.2; } else if (childBehavior.mode === "idle") { // Idle: stand still, maybe wiggle a bit childObj.x += Math.sin(LK.ticks / 10) * 0.5; } // If child catches player (only if chasing) if (childBehavior.mode === "chase" && dist < childCatchDist) { playerDead = true; LK.effects.flashScreen(0xff0000, 1200); LK.getSound('danger').play(); LK.showGameOver(); return; } } // --- Goal (Fountain) --- if (!playerGoalReached && playerObj.intersects(fountainObj)) { playerGoalReached = true; playerWin = true; playerObj.setState('baby'); LK.getSound('goal').play(); LK.effects.flashScreen(0x4ecdc4, 1200); LK.setScore(level); if (level >= maxLevel) { LK.showYouWin(); } else { // Next level after short delay LK.setTimeout(function () { level++; setupLevel(); }, 1200); } return; } // --- Update GUI --- scoreTxt.setText("Distance: " + Math.max(0, Math.floor(distanceToGoal - distanceTraveled)) + "m"); levelTxt.setText("Niveau " + level); meltBar.setText("Fraîcheur: " + Math.max(0, Math.floor(playerMaxMelt - playerMelt)) + "%"); }; // --- Start Game --- setupLevel(); // --- Music --- LK.playMusic('summer', { loop: true, fade: { start: 0, end: 1, duration: 1200 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird (obstacle, cartoon)
var Bird = Container.expand(function () {
var self = Container.call(this);
// Use custom bird asset
var bird = self.attachAsset('bird_asset', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
self.bird = bird;
self.moveDir = Math.random() < 0.5 ? -1 : 1;
self.moveSpeed = 6 + Math.random() * 3;
self.range = 400 + Math.random() * 800;
self.baseX = 0;
self.baseY = 0;
self.t = Math.random() * 1000;
self.setStart = function (x, y) {
self.baseX = x;
self.baseY = y;
self.x = x;
self.y = y;
};
self.update = function () {
self.t += 1;
// Move left-right in a sine wave
self.x = self.baseX + Math.sin(self.t / 60) * self.range * self.moveDir;
// Optionally, add some up-down movement
self.y = self.baseY + Math.sin(self.t / 30) * 40;
};
return self;
});
// Enemy Child (cartoon)
var Child = Container.expand(function () {
var self = Container.call(this);
var body = self.attachAsset('child_cartoon', {
anchorX: 0.5,
anchorY: 1.0
});
self.body = body;
return self;
});
// Dog (chaser, cartoon)
var Dog = Container.expand(function () {
var self = Container.call(this);
// Use custom dog asset
var dog = self.attachAsset('dog_asset', {
anchorX: 0.5,
anchorY: 1.0,
scaleX: 1.0,
scaleY: 1.0
});
self.dog = dog;
self.speed = 6 + Math.random() * 2;
self.update = function () {
// Chase the playerObj
if (typeof playerObj !== "undefined" && playerObj) {
var dx = playerObj.x - self.x;
var dy = playerObj.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 1) {
var step = Math.min(self.speed, dist);
self.x += dx / dist * step;
self.y += dy / dist * step;
}
}
};
return self;
});
// Fountain (Goal, cartoon)
var Fountain = Container.expand(function () {
var self = Container.call(this);
var f = self.attachAsset('fountain_cartoon', {
anchorX: 0.5,
anchorY: 0.5
});
self.f = f;
return self;
});
// Fridge (Bonus, cartoon)
var Fridge = Container.expand(function () {
var self = Container.call(this);
var fridge = self.attachAsset('fridge_cartoon', {
anchorX: 0.5,
anchorY: 1.0
});
self.fridge = fridge;
return self;
});
// Player Ice Cream (cartoon)
var IceCream = Container.expand(function () {
var self = Container.call(this);
// State: 'normal', 'old', 'melt', 'baby'
self.state = 'normal';
self.age = 0; // 0: baby, 1: normal, 2: old, 3: melt
// Attach cone (cartoon)
var cone = self.attachAsset('cone_cartoon', {
anchorX: 0.5,
anchorY: 0.0,
y: 120
});
// Attach scoop (ice cream, cartoon)
var scoop = self.attachAsset('icecream_cartoon', {
anchorX: 0.5,
anchorY: 1.0,
y: 120
});
self.scoop = scoop;
self.cone = cone;
// For visual aging
self.setState = function (state) {
if (state === self.state) return;
self.state = state;
if (state === 'normal') {
scoop.texture = LK.getAsset('icecream_cartoon', {}).texture;
} else if (state === 'old') {
scoop.texture = LK.getAsset('icecream_old_cartoon', {}).texture;
} else if (state === 'melt') {
scoop.texture = LK.getAsset('icecream_melt_cartoon', {}).texture;
} else if (state === 'baby') {
scoop.texture = LK.getAsset('icecream_baby_cartoon', {}).texture;
}
};
// For bonus
self.resetAge = function () {
self.age = 0;
self.setState('normal');
};
return self;
});
// Shadow (Safe zone, cartoon)
var Shadow = Container.expand(function () {
var self = Container.call(this);
var shadow = self.attachAsset('shadow_cartoon', {
anchorX: 0.5,
anchorY: 0.5
});
self.shadow = shadow;
return self;
});
// Sunbeam (Danger zone, for visual only, cartoon)
var Sunbeam = Container.expand(function () {
var self = Container.call(this);
var sunbeam = self.attachAsset('sunbeam_cartoon', {
anchorX: 0.5,
anchorY: 0.5
});
self.sunbeam = sunbeam;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Fallback for any missing asset
// Cartoon-style image assets (replace simple shapes)
// --- Game Variables ---
var level = 1;
var maxLevel = 30;
var playerSpeed = 18;
var childBaseSpeed = 4.5; // easier: slower child
var childSpeed = childBaseSpeed;
var shadowSpeed = 2.5;
var shadowCount = 5; // easier: more shadows
var shadowMinWidth = 400; // easier: wider shadows
var shadowMaxWidth = 700;
var sunbeamCount = 1; // easier: less sunbeams
var sunbeamSpeed = 1.2;
var fridgeChance = 0.35; // more chance for fridge
var fridgeActive = false;
var fridgeTimer = 0;
var fridgeDuration = 120; // frames
var playerAgingRate = 0.7; // easier: slower aging
var playerMeltRate = 1.1; // easier: slower melt
var playerAge = 0; // 0: baby, 1: normal, 2: old, 3: melt
var playerMaxAge = 3;
var playerInShadow = false;
var playerInFridge = false;
var playerMelt = 0;
var playerMaxMelt = 120; // easier: more margin before melting
var playerMeltWarning = false;
var playerMeltSoundPlayed = false;
var playerOldWarning = false;
var playerOldSoundPlayed = false;
var playerGoalReached = false;
var playerDead = false;
var playerWin = false;
var distanceToGoal = 1500 + (level - 1) * 250; // easier: shorter distance
var distanceTraveled = 0;
var moveDir = {
up: false,
down: false,
left: false,
right: false
};
var lastMoveTick = 0;
var lastShadowTick = 0;
var lastChildTick = 0;
var lastFridgeTick = 0;
var lastStepSound = 0;
var childChaseDelay = 80; // child starts a bit later
var childChaseStarted = false;
var childChaseTick = 0;
var childCatchDist = 120; // easier: more margin before caught
var shadowList = [];
var sunbeamList = [];
var sunBeamObstacles = [];
var birdList = [];
var dogList = [];
var fridgeObj = null;
var fridgeUsed = false;
var fountainObj = null;
var childObj = null;
var playerObj = null;
var scoreTxt = null;
var levelTxt = null;
var meltBar = null;
// --- Child funny behavior state ---
var childBehavior = {
mode: "chase",
// chase, stumble, butterfly, idle
timer: 0
};
// --- GUI ---
// Score/Level text
scoreTxt = new Text2('0', {
size: 110,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
levelTxt = new Text2('Niveau 1', {
size: 70,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 120;
// Melt bar (shows how close to melting)
meltBar = new Text2('', {
size: 60,
fill: 0xF7E6B2
});
meltBar.anchor.set(0.5, 0);
LK.gui.top.addChild(meltBar);
meltBar.y = 210;
// --- Game Setup ---
function setupLevel() {
// Reset
distanceToGoal = 1500 + (level - 1) * 250;
distanceTraveled = 0;
playerAgingRate = 0.7 + (level - 1) * 0.13;
playerMeltRate = 1.1 + (level - 1) * 0.18;
childSpeed = childBaseSpeed + (level - 1) * 1.2;
shadowCount = 5 + Math.floor((level - 1) * 1.2);
sunbeamCount = 1 + Math.floor((level - 1) / 4);
fridgeActive = false;
fridgeUsed = false;
playerGoalReached = false;
playerDead = false;
playerWin = false;
playerMelt = 0;
playerMaxMelt = 120;
playerMeltWarning = false;
playerMeltSoundPlayed = false;
playerOldWarning = false;
playerOldSoundPlayed = false;
playerInShadow = false;
playerInFridge = false;
childChaseStarted = false;
childChaseTick = 0;
childCatchDist = 120;
playerAge = 1;
playerObj.resetAge();
childBehavior.mode = "chase";
childBehavior.timer = 0;
// Remove old objects
for (var i = 0; i < shadowList.length; i++) {
shadowList[i].destroy();
}
shadowList = [];
for (var i = 0; i < sunbeamList.length; i++) {
sunbeamList[i].destroy();
}
sunbeamList = [];
if (fridgeObj) {
fridgeObj.destroy();
fridgeObj = null;
}
if (fountainObj) {
fountainObj.destroy();
fountainObj = null;
}
if (childObj) {
childObj.destroy();
childObj = null;
}
// Place player at bottom center
playerObj.x = 2048 / 2;
playerObj.y = 2732 - 300;
// Place child at bottom, offset
childObj = new Child();
childObj.x = 2048 / 2 + 200;
childObj.y = 2732 - 300;
game.addChild(childObj);
// Place fountain at top center
fountainObj = new Fountain();
fountainObj.x = 2048 / 2;
fountainObj.y = 300;
game.addChild(fountainObj);
// Place shadows (random X, Y spaced along path)
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
var sx = 300 + Math.random() * (2048 - 600);
var sy = 2732 - 600 - (i + 1) * (distanceToGoal / (shadowCount + 1));
s.x = sx;
s.y = sy;
// Make trees (shadows) larger as level increases
var levelShadowScale = 1 + (level - 1) * 0.18;
var w = (shadowMinWidth + Math.random() * (shadowMaxWidth - shadowMinWidth)) * levelShadowScale;
s.shadow.width = w;
s.shadow.height = s.shadow.height * (0.95 + Math.random() * 0.15) * levelShadowScale;
shadowList.push(s);
game.addChild(s);
}
// Place sunbeams (now moving obstacles)
for (var i = 0; i < sunbeamCount; i++) {
var sb = new Sunbeam();
var sbx = 300 + Math.random() * (2048 - 600);
var sby = 2732 - 600 - (i + 1) * (distanceToGoal / (sunbeamCount + 1));
sb.x = sbx;
sb.y = sby;
// Give each sunbeam a random horizontal speed and direction
sb.moveDir = Math.random() < 0.5 ? -1 : 1;
sb.moveSpeed = 2 + Math.random() * 2;
sunbeamList.push(sb);
game.addChild(sb);
}
// Add SunBeam obstacle from level 10+
if (typeof sunBeamObstacles !== "undefined") {
for (var i = 0; i < sunBeamObstacles.length; i++) {
sunBeamObstacles[i].destroy();
}
}
sunBeamObstacles = [];
if (level >= 10) {
// Add a SunBeam obstacle that moves left-right across the screen
var sunBeam = new Sunbeam();
sunBeam.x = 2048 / 2;
sunBeam.y = 2732 / 2 - 200;
sunBeam.moveDir = 1;
sunBeam.moveSpeed = 8 + (level - 10) * 0.7;
sunBeamObstacles.push(sunBeam);
game.addChild(sunBeam);
}
// Add birds from level 15+
if (typeof birdList !== "undefined") {
for (var i = 0; i < birdList.length; i++) {
birdList[i].destroy();
}
}
birdList = [];
if (level >= 15) {
// Add birds, more at level 20+
var birdCount = 1;
if (level >= 20) birdCount = 2 + Math.floor((level - 20) * 0.7);
for (var i = 0; i < birdCount; i++) {
var bird = new Bird();
var bx = 400 + Math.random() * (2048 - 800);
var by = 800 + Math.random() * (2732 - 1600);
bird.setStart(bx, by);
birdList.push(bird);
game.addChild(bird);
}
}
// Add dogs from level 25+
if (typeof dogList !== "undefined") {
for (var i = 0; i < dogList.length; i++) {
dogList[i].destroy();
}
}
dogList = [];
if (level >= 25) {
// Add dogs, more at higher levels
var dogCount = 1 + Math.floor((level - 25) * 0.5);
for (var i = 0; i < dogCount; i++) {
var dog = new Dog();
dog.x = 2048 / 2 + (Math.random() < 0.5 ? -1 : 1) * (300 + Math.random() * 400);
dog.y = 2732 - 600 - Math.random() * 400;
dogList.push(dog);
game.addChild(dog);
}
}
// End game at level 30
if (level >= 30) {
LK.setTimeout(function () {
LK.showYouWin();
}, 1200);
}
// Place fridge (bonus) randomly, only if not already used
if (Math.random() < fridgeChance) {
fridgeObj = new Fridge();
fridgeObj.x = 400 + Math.random() * (2048 - 800);
fridgeObj.y = 2732 - 600 - Math.random() * (distanceToGoal - 800);
game.addChild(fridgeObj);
fridgeActive = true;
}
// Place random ice puddles (obstacles that slow player)
if (typeof puddleList !== "undefined") {
for (var i = 0; i < puddleList.length; i++) {
puddleList[i].destroy();
}
}
puddleList = [];
var puddleCount = 2 + Math.floor(level / 2);
for (var i = 0; i < puddleCount; i++) {
var puddle = new Container();
var puddleAsset = puddle.attachAsset('icecream_melt_cartoon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7 + Math.random() * 0.5,
scaleY: 0.5 + Math.random() * 0.3
});
puddle.x = 200 + Math.random() * (2048 - 400);
puddle.y = 2732 - 600 - Math.random() * (distanceToGoal - 800);
puddle.slow = 0.5 + Math.random() * 0.3;
puddleList.push(puddle);
game.addChild(puddle);
}
// Update GUI
scoreTxt.setText("Distance: " + Math.max(0, Math.floor(distanceToGoal - distanceTraveled)) + "m");
levelTxt.setText("Niveau " + level);
meltBar.setText("Fraîcheur: " + Math.max(0, Math.floor(playerMaxMelt - playerMelt)) + "%");
}
// --- Custom Background ---
var backgroundObj = LK.getAsset('custom_background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(backgroundObj);
// --- Player ---
playerObj = new IceCream();
game.addChild(playerObj);
// --- Tap-to-move: move player a short distance towards tap/click position ---
// Remove GUI buttons, use tap anywhere to move player a short distance in that direction
// Maximum distance the player can move per tap
var tapMoveDistance = 180;
// Handle tap/click on the game area
game.down = function (x, y, obj) {
if (playerDead || playerWin) return;
// Clamp tap to game area
var targetX = Math.max(100, Math.min(2048 - 100, x));
var targetY = Math.max(200, Math.min(2732 - 100, y));
// Compute direction vector from player to tap
var dx = targetX - playerObj.x;
var dy = targetY - playerObj.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist === 0) return;
// Move only up to tapMoveDistance per tap
var moveDist = Math.min(tapMoveDistance, dist);
var moveX = dx / dist * moveDist;
var moveY = dy / dist * moveDist;
// Check for puddle slow
var onPuddle = false;
if (typeof puddleList !== "undefined") {
for (var i = 0; i < puddleList.length; i++) {
if (playerObj.intersects(puddleList[i])) {
onPuddle = true;
break;
}
}
}
var speedFactor = onPuddle ? 0.4 : 1;
moveX *= speedFactor;
moveY *= speedFactor;
// New position
var newX = playerObj.x + moveX;
var newY = playerObj.y + moveY;
// Clamp to game area
newX = Math.max(100, Math.min(2048 - 100, newX));
newY = Math.max(200, Math.min(2732 - 100, newY));
// Only count distance if moving up (towards goal)
if (distanceTraveled < distanceToGoal && newY < playerObj.y) {
distanceTraveled += playerObj.y - newY;
}
playerObj.x = newX;
playerObj.y = newY;
// Play step sound
LK.getSound('step').play();
};
// --- Main Game Update ---
game.update = function () {
if (playerDead || playerWin) return;
// --- Player Movement ---
// (Handled by tap-to-move in game.down)
// Just update lastX/lastY for consistency
playerObj.lastX = playerObj.x;
playerObj.lastY = playerObj.y;
// --- Shadows ---
playerInShadow = false;
for (var i = 0; i < shadowList.length; i++) {
var s = shadowList[i];
if (playerObj.intersects(s)) {
playerInShadow = true;
break;
}
}
// --- Sunbeams (moving obstacles, dangerous) ---
for (var i = 0; i < sunbeamList.length; i++) {
var sb = sunbeamList[i];
// Move sunbeam horizontally, bounce at screen edges
sb.x += sb.moveDir * sb.moveSpeed;
if (sb.x < 200) {
sb.x = 200;
sb.moveDir = 1;
}
if (sb.x > 2048 - 200) {
sb.x = 2048 - 200;
sb.moveDir = -1;
}
// If player touches a sunbeam, instant melt!
if (!playerDead && playerObj.intersects(sb)) {
playerObj.setState('melt');
playerDead = true;
LK.effects.flashScreen(0xffe066, 1200);
LK.getSound('melt').play();
LK.showGameOver();
return;
}
}
// --- SunBeam obstacle (from level 10) ---
if (typeof sunBeamObstacles !== "undefined") {
for (var i = 0; i < sunBeamObstacles.length; i++) {
var sb = sunBeamObstacles[i];
sb.x += sb.moveDir * sb.moveSpeed;
if (sb.x < 200) {
sb.x = 200;
sb.moveDir = 1;
}
if (sb.x > 2048 - 200) {
sb.x = 2048 - 200;
sb.moveDir = -1;
}
if (!playerDead && playerObj.intersects(sb)) {
playerObj.setState('melt');
playerDead = true;
LK.effects.flashScreen(0xffe066, 1200);
LK.getSound('melt').play();
LK.showGameOver();
return;
}
}
}
// --- Birds (from level 15) ---
if (typeof birdList !== "undefined") {
for (var i = 0; i < birdList.length; i++) {
var bird = birdList[i];
if (bird.update) bird.update();
if (!playerDead && playerObj.intersects(bird)) {
playerDead = true;
LK.effects.flashScreen(0x222222, 1200);
LK.getSound('danger').play();
LK.showGameOver();
return;
}
}
}
// --- Dogs (from level 25) ---
if (typeof dogList !== "undefined") {
for (var i = 0; i < dogList.length; i++) {
var dog = dogList[i];
if (dog.update) dog.update();
// If dog catches player
var dx = playerObj.x - dog.x;
var dy = playerObj.y - dog.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (!playerDead && dist < 100) {
playerDead = true;
LK.effects.flashScreen(0xc68642, 1200);
LK.getSound('danger').play();
LK.showGameOver();
return;
}
}
}
// --- Fridge (bonus) ---
if (fridgeObj && !fridgeUsed && playerObj.intersects(fridgeObj)) {
playerInFridge = true;
fridgeUsed = true;
playerObj.resetAge();
playerMelt = 0;
LK.getSound('bonus').play();
// Animate fridge
tween(fridgeObj, {
alpha: 0
}, {
duration: 600,
onFinish: function onFinish() {
fridgeObj.destroy();
fridgeObj = null;
}
});
} else {
playerInFridge = false;
}
// --- Melting / Aging ---
if (playerInFridge) {
// No aging/melting
} else if (playerInShadow) {
// Age slowly (recover a little freshness in shadow)
playerMelt -= 0.5;
if (playerMelt < 0) playerMelt = 0;
} else {
// In sun: melt at exactly -1% per second (1% of playerMaxMelt per 60 ticks)
playerMelt += playerMaxMelt / 100 / 60;
if (!playerMeltWarning && playerMelt > playerMaxMelt * 0.7) {
playerMeltWarning = true;
LK.effects.flashObject(playerObj, 0xffe066, 400);
LK.getSound('melt').play();
}
if (playerMelt > playerMaxMelt) {
// Melted!
playerObj.setState('melt');
playerDead = true;
LK.effects.flashScreen(0xffe066, 1200);
LK.showGameOver();
return;
}
}
// Age visually if in sun for long
if (playerMelt > playerMaxMelt * 0.4 && playerMelt < playerMaxMelt * 0.7) {
playerObj.setState('old');
} else if (playerMelt <= playerMaxMelt * 0.4) {
playerObj.setState('normal');
}
// --- Child (enemy) ---
if (!childChaseStarted) {
childChaseTick++;
if (childChaseTick > childChaseDelay) {
childChaseStarted = true;
childBehavior.mode = "chase";
childBehavior.timer = 0;
}
} else {
// --- Child funny behaviors ---
childBehavior.timer--;
if (childBehavior.timer <= 0) {
// Randomly pick a new behavior
var r = Math.random();
if (r < 0.15) {
childBehavior.mode = "stumble";
childBehavior.timer = 40 + Math.floor(Math.random() * 30);
} else if (r < 0.30) {
childBehavior.mode = "butterfly";
childBehavior.timer = 50 + Math.floor(Math.random() * 40);
} else if (r < 0.40) {
childBehavior.mode = "idle";
childBehavior.timer = 30 + Math.floor(Math.random() * 20);
} else {
childBehavior.mode = "chase";
childBehavior.timer = 60 + Math.floor(Math.random() * 60);
}
}
var cx = childObj.x,
cy = childObj.y;
var px = playerObj.x,
py = playerObj.y;
var dx = px - cx,
dy = py - cy;
var dist = Math.sqrt(dx * dx + dy * dy);
if (childBehavior.mode === "chase") {
if (dist > 1) {
var step = Math.min(childSpeed, dist);
childObj.x += dx / dist * step;
childObj.y += dy / dist * step;
}
} else if (childBehavior.mode === "stumble") {
// Stumble: move erratically, slower
var angle = Math.random() * Math.PI * 2;
childObj.x += Math.cos(angle) * 2.5;
childObj.y += Math.sin(angle) * 2.5;
} else if (childBehavior.mode === "butterfly") {
// Butterfly: move in a small circle
var t = LK.ticks % 360;
childObj.x += Math.cos(t / 20) * 2.2;
childObj.y += Math.sin(t / 20) * 2.2;
} else if (childBehavior.mode === "idle") {
// Idle: stand still, maybe wiggle a bit
childObj.x += Math.sin(LK.ticks / 10) * 0.5;
}
// If child catches player (only if chasing)
if (childBehavior.mode === "chase" && dist < childCatchDist) {
playerDead = true;
LK.effects.flashScreen(0xff0000, 1200);
LK.getSound('danger').play();
LK.showGameOver();
return;
}
}
// --- Goal (Fountain) ---
if (!playerGoalReached && playerObj.intersects(fountainObj)) {
playerGoalReached = true;
playerWin = true;
playerObj.setState('baby');
LK.getSound('goal').play();
LK.effects.flashScreen(0x4ecdc4, 1200);
LK.setScore(level);
if (level >= maxLevel) {
LK.showYouWin();
} else {
// Next level after short delay
LK.setTimeout(function () {
level++;
setupLevel();
}, 1200);
}
return;
}
// --- Update GUI ---
scoreTxt.setText("Distance: " + Math.max(0, Math.floor(distanceToGoal - distanceTraveled)) + "m");
levelTxt.setText("Niveau " + level);
meltBar.setText("Fraîcheur: " + Math.max(0, Math.floor(playerMaxMelt - playerMelt)) + "%");
};
// --- Start Game ---
setupLevel();
// --- Music ---
LK.playMusic('summer', {
loop: true,
fade: {
start: 0,
end: 1,
duration: 1200
}
});
Cone de glace a la vanille. In-Game asset. 2d. High contrast. No shadows
un arbre avec un visage . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Une fontaine de jouvence. In-Game asset. 2d. High contrast. No shadows
Oiseau qui vole. In-Game asset. 2d. High contrast. No shadows
Chien. In-Game asset. 2d. High contrast. No shadows
icecream_melt_cartoon. In-Game asset. 2d. High contrast. No shadows
bébé glace cartoon. In-Game asset. 2d. High contrast. No shadows
Frigo. In-Game asset. 2d. High contrast. No shadows
Fond d'écran été. In-Game asset. 2d. High contrast. No shadows
Cône de glace. In-Game asset. 2d. High contrast. No shadows
Vielle glace (dessert). In-Game asset. 2d. High contrast. No shadows
Enfant. In-Game asset. 2d. High contrast. No shadows