/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Boat = Container.expand(function () { var self = Container.call(this); var boatGraphics = self.attachAsset('boat', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.floatSpeed = Math.random() * 1 + 0.5; self.direction = Math.random() < 0.5 ? -1 : 1; self.update = function () { if (!self.collected) { self.x += self.floatSpeed * self.direction; self.y += Math.sin(LK.ticks * 0.05) * 0.3; // Bounce off edges if (self.x < 200 || self.x > 1848) { self.direction *= -1; } } }; self.collect = function () { if (!self.collected) { self.collected = true; tween(self, { scaleX: 0.1, scaleY: 0.1, alpha: 0, y: self.y - 100 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); LK.getSound('collect').play(); LK.setScore(LK.getScore() + 20); boatsCollected++; } }; self.down = function (x, y, obj) { self.collect(); }; return self; }); var Bubble = Container.expand(function () { var self = Container.call(this); var bubbleGraphics = self.attachAsset('bubble', { anchorX: 0.5, anchorY: 0.5 }); self.floatSpeed = Math.random() * 2 + 1; self.bobAmount = Math.random() * 30 + 10; self.bobSpeed = Math.random() * 0.1 + 0.05; self.startY = 0; self.update = function () { self.y -= self.floatSpeed; self.x += Math.sin(LK.ticks * self.bobSpeed) * 0.5; bubbleGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.1) * 0.3; }; self.pop = function () { tween(bubbleGraphics, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); LK.getSound('pop').play(); LK.setScore(LK.getScore() + 5); }; self.down = function (x, y, obj) { self.pop(); }; return self; }); var Character = Container.expand(function (name, isClean) { var self = Container.call(this); self.name = name; self.isClean = isClean || false; self.dirtSpots = []; // Main character body var body = self.attachAsset(self.isClean ? 'cleanCharacter' : 'character', { anchorX: 0.5, anchorY: 0.5 }); // Add dirt spots if not clean if (!self.isClean) { // Tummy dirt var tummyDirt = self.attachAsset('dirt', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 50 }); // Head dirt var headDirt = self.attachAsset('dirt', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -120 }); self.dirtSpots.push(tummyDirt, headDirt); } self.cleanSpot = function (spot) { var index = self.dirtSpots.indexOf(spot); if (index > -1) { tween(spot, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { spot.destroy(); } }); self.dirtSpots.splice(index, 1); // Check if fully clean if (self.dirtSpots.length === 0) { self.isClean = true; self.makeClean(); } } }; self.makeClean = function () { tween(body, { tint: 0xFFB6C1 }, { duration: 500, easing: tween.easeOut }); tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200, easing: tween.bounceOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.bounceOut }); } }); }; self.down = function (x, y, obj) { for (var i = 0; i < self.dirtSpots.length; i++) { var spot = self.dirtSpots[i]; var spotPos = self.toLocal(spot.toGlobal({ x: 0, y: 0 })); var distance = Math.sqrt((x - spotPos.x) * (x - spotPos.x) + (y - spotPos.y) * (y - spotPos.y)); if (distance < 60) { self.cleanSpot(spot); LK.getSound('scrub').play(); LK.setScore(LK.getScore() + 10); break; } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ var characters = []; var bubbles = []; var boats = []; var boatsCollected = 0; var bubbleTimer = 0; // Create bathtub var bathtub = game.attachAsset('bathtub', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); // Create score display var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create characters var blossom = new Character('Blossom', false); blossom.x = 1024 - 200; blossom.y = 1366; characters.push(blossom); game.addChild(blossom); var bubbles_char = new Character('Bubbles', false); bubbles_char.x = 1024 + 200; bubbles_char.y = 1366; characters.push(bubbles_char); game.addChild(bubbles_char); // Create boats for (var i = 0; i < 3; i++) { var boat = new Boat(); boat.x = 300 + i * 600 + Math.random() * 200; boat.y = 1200 + Math.random() * 100; boats.push(boat); game.addChild(boat); } function checkWinCondition() { var allClean = true; for (var i = 0; i < characters.length; i++) { if (!characters[i].isClean) { allClean = false; break; } } if (allClean && boatsCollected >= 3) { LK.showYouWin(); } } function spawnBubble() { var bubble = new Bubble(); bubble.x = Math.random() * 1600 + 224; bubble.y = 1800; bubble.startY = bubble.y; bubbles.push(bubble); game.addChild(bubble); } game.update = function () { // Update score display scoreTxt.setText('Score: ' + LK.getScore()); // Spawn bubbles occasionally bubbleTimer++; if (bubbleTimer > 120 && Math.random() < 0.02) { spawnBubble(); bubbleTimer = 0; } // Clean up off-screen bubbles for (var i = bubbles.length - 1; i >= 0; i--) { var bubble = bubbles[i]; if (bubble.y < -100) { bubble.destroy(); bubbles.splice(i, 1); } } // Clean up collected boats for (var i = boats.length - 1; i >= 0; i--) { var boat = boats[i]; if (boat.collected && boat.alpha <= 0) { boats.splice(i, 1); } } checkWinCondition(); };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Boat = Container.expand(function () {
var self = Container.call(this);
var boatGraphics = self.attachAsset('boat', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.floatSpeed = Math.random() * 1 + 0.5;
self.direction = Math.random() < 0.5 ? -1 : 1;
self.update = function () {
if (!self.collected) {
self.x += self.floatSpeed * self.direction;
self.y += Math.sin(LK.ticks * 0.05) * 0.3;
// Bounce off edges
if (self.x < 200 || self.x > 1848) {
self.direction *= -1;
}
}
};
self.collect = function () {
if (!self.collected) {
self.collected = true;
tween(self, {
scaleX: 0.1,
scaleY: 0.1,
alpha: 0,
y: self.y - 100
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
self.destroy();
}
});
LK.getSound('collect').play();
LK.setScore(LK.getScore() + 20);
boatsCollected++;
}
};
self.down = function (x, y, obj) {
self.collect();
};
return self;
});
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('bubble', {
anchorX: 0.5,
anchorY: 0.5
});
self.floatSpeed = Math.random() * 2 + 1;
self.bobAmount = Math.random() * 30 + 10;
self.bobSpeed = Math.random() * 0.1 + 0.05;
self.startY = 0;
self.update = function () {
self.y -= self.floatSpeed;
self.x += Math.sin(LK.ticks * self.bobSpeed) * 0.5;
bubbleGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.1) * 0.3;
};
self.pop = function () {
tween(bubbleGraphics, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
LK.getSound('pop').play();
LK.setScore(LK.getScore() + 5);
};
self.down = function (x, y, obj) {
self.pop();
};
return self;
});
var Character = Container.expand(function (name, isClean) {
var self = Container.call(this);
self.name = name;
self.isClean = isClean || false;
self.dirtSpots = [];
// Main character body
var body = self.attachAsset(self.isClean ? 'cleanCharacter' : 'character', {
anchorX: 0.5,
anchorY: 0.5
});
// Add dirt spots if not clean
if (!self.isClean) {
// Tummy dirt
var tummyDirt = self.attachAsset('dirt', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 50
});
// Head dirt
var headDirt = self.attachAsset('dirt', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -120
});
self.dirtSpots.push(tummyDirt, headDirt);
}
self.cleanSpot = function (spot) {
var index = self.dirtSpots.indexOf(spot);
if (index > -1) {
tween(spot, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
spot.destroy();
}
});
self.dirtSpots.splice(index, 1);
// Check if fully clean
if (self.dirtSpots.length === 0) {
self.isClean = true;
self.makeClean();
}
}
};
self.makeClean = function () {
tween(body, {
tint: 0xFFB6C1
}, {
duration: 500,
easing: tween.easeOut
});
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.bounceOut
});
}
});
};
self.down = function (x, y, obj) {
for (var i = 0; i < self.dirtSpots.length; i++) {
var spot = self.dirtSpots[i];
var spotPos = self.toLocal(spot.toGlobal({
x: 0,
y: 0
}));
var distance = Math.sqrt((x - spotPos.x) * (x - spotPos.x) + (y - spotPos.y) * (y - spotPos.y));
if (distance < 60) {
self.cleanSpot(spot);
LK.getSound('scrub').play();
LK.setScore(LK.getScore() + 10);
break;
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var characters = [];
var bubbles = [];
var boats = [];
var boatsCollected = 0;
var bubbleTimer = 0;
// Create bathtub
var bathtub = game.attachAsset('bathtub', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create characters
var blossom = new Character('Blossom', false);
blossom.x = 1024 - 200;
blossom.y = 1366;
characters.push(blossom);
game.addChild(blossom);
var bubbles_char = new Character('Bubbles', false);
bubbles_char.x = 1024 + 200;
bubbles_char.y = 1366;
characters.push(bubbles_char);
game.addChild(bubbles_char);
// Create boats
for (var i = 0; i < 3; i++) {
var boat = new Boat();
boat.x = 300 + i * 600 + Math.random() * 200;
boat.y = 1200 + Math.random() * 100;
boats.push(boat);
game.addChild(boat);
}
function checkWinCondition() {
var allClean = true;
for (var i = 0; i < characters.length; i++) {
if (!characters[i].isClean) {
allClean = false;
break;
}
}
if (allClean && boatsCollected >= 3) {
LK.showYouWin();
}
}
function spawnBubble() {
var bubble = new Bubble();
bubble.x = Math.random() * 1600 + 224;
bubble.y = 1800;
bubble.startY = bubble.y;
bubbles.push(bubble);
game.addChild(bubble);
}
game.update = function () {
// Update score display
scoreTxt.setText('Score: ' + LK.getScore());
// Spawn bubbles occasionally
bubbleTimer++;
if (bubbleTimer > 120 && Math.random() < 0.02) {
spawnBubble();
bubbleTimer = 0;
}
// Clean up off-screen bubbles
for (var i = bubbles.length - 1; i >= 0; i--) {
var bubble = bubbles[i];
if (bubble.y < -100) {
bubble.destroy();
bubbles.splice(i, 1);
}
}
// Clean up collected boats
for (var i = boats.length - 1; i >= 0; i--) {
var boat = boats[i];
if (boat.collected && boat.alpha <= 0) {
boats.splice(i, 1);
}
}
checkWinCondition();
};