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