/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Heart = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); self.driftX = 3; self.driftY = 2; self.baseSize = 1; self.lettersCollected = 0; self.update = function () { self.x += self.driftX; self.y += self.driftY; // Wrap around screen edges if (self.x < 0) self.x = 2048; if (self.x > 2048) self.x = 0; if (self.y < 0) self.y = 2732; if (self.y > 2732) self.y = 0; }; self.changeDriftDirection = function () { self.driftX = -self.driftX; self.driftY = -self.driftY; }; self.collectLetter = function () { self.lettersCollected++; var newScale = self.baseSize + self.lettersCollected * 0.1; tween(heartGraphics, { scaleX: newScale, scaleY: newScale }, { duration: 300, easing: tween.easeOut }); // Change color based on letters collected var colors = [0xff69b4, 0xff1493, 0xdc143c, 0xb22222]; var colorIndex = Math.min(Math.floor(self.lettersCollected / 3), colors.length - 1); tween(heartGraphics, { tint: colors[colorIndex] }, { duration: 500 }); }; return self; }); var LoveLetter = Container.expand(function () { var self = Container.call(this); var letterGraphics = self.attachAsset('loveLetter', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.update = function () { letterGraphics.rotation += 0.05; // Gentle floating animation letterGraphics.y += Math.sin(LK.ticks * 0.1 + self.x * 0.01) * 0.5; }; return self; }); var Obstacle = Container.expand(function () { var self = Container.call(this); var obstacleGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000022 }); /**** * Game Code ****/ var heart = game.addChild(new Heart()); heart.x = 1024; heart.y = 1366; var loveLetters = []; var obstacles = []; var targetLetters = 10; var currentLevel = 1; // UI Elements var scoreTxt = new Text2('Letters: 0/' + targetLetters, { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var levelTxt = new Text2('Level ' + currentLevel, { size: 60, fill: 0xFFB6C1 }); levelTxt.anchor.set(1, 0); LK.gui.topRight.addChild(levelTxt); levelTxt.x -= 50; levelTxt.y += 50; // Generate initial love letters function spawnLoveLetters() { for (var i = 0; i < targetLetters; i++) { var letter = new LoveLetter(); letter.x = Math.random() * 1800 + 124; letter.y = Math.random() * 2400 + 166; loveLetters.push(letter); game.addChild(letter); } } // Generate obstacles function spawnObstacles() { var obstacleCount = currentLevel + 2; for (var i = 0; i < obstacleCount; i++) { var obstacle = new Obstacle(); obstacle.x = Math.random() * 1800 + 124; obstacle.y = Math.random() * 2400 + 166; // Make sure obstacles don't spawn too close to heart or letters var tooClose = true; var attempts = 0; while (tooClose && attempts < 20) { tooClose = false; // Check distance from heart var heartDist = Math.sqrt(Math.pow(obstacle.x - heart.x, 2) + Math.pow(obstacle.y - heart.y, 2)); if (heartDist < 200) tooClose = true; // Check distance from letters for (var j = 0; j < loveLetters.length; j++) { var letterDist = Math.sqrt(Math.pow(obstacle.x - loveLetters[j].x, 2) + Math.pow(obstacle.y - loveLetters[j].y, 2)); if (letterDist < 150) tooClose = true; } if (tooClose) { obstacle.x = Math.random() * 1800 + 124; obstacle.y = Math.random() * 2400 + 166; } attempts++; } obstacles.push(obstacle); game.addChild(obstacle); } } function nextLevel() { currentLevel++; targetLetters += 3; // Clear existing letters and obstacles for (var i = loveLetters.length - 1; i >= 0; i--) { loveLetters[i].destroy(); } loveLetters = []; for (var i = obstacles.length - 1; i >= 0; i--) { obstacles[i].destroy(); } obstacles = []; // Reset heart position heart.x = 1024; heart.y = 1366; heart.lettersCollected = 0; // Update UI scoreTxt.setText('Letters: 0/' + targetLetters); levelTxt.setText('Level ' + currentLevel); // Spawn new elements spawnLoveLetters(); spawnObstacles(); // Flash screen to indicate level change LK.effects.flashScreen(0x9370db, 800); } // Initialize first level spawnLoveLetters(); spawnObstacles(); // Game input handling game.down = function (x, y, obj) { heart.changeDriftDirection(); }; // Main game loop game.update = function () { // Check collision with love letters for (var i = loveLetters.length - 1; i >= 0; i--) { var letter = loveLetters[i]; if (!letter.collected && heart.intersects(letter)) { letter.collected = true; heart.collectLetter(); LK.setScore(LK.getScore() + 10); LK.getSound('collect').play(); // Remove letter with animation tween(letter, { alpha: 0, scaleX: 2, scaleY: 2 }, { duration: 300, onFinish: function onFinish() { letter.destroy(); } }); loveLetters.splice(i, 1); // Update score display scoreTxt.setText('Letters: ' + heart.lettersCollected + '/' + targetLetters); // Check if level complete if (heart.lettersCollected >= targetLetters) { LK.setTimeout(function () { nextLevel(); }, 500); } } } // Check collision with obstacles for (var i = 0; i < obstacles.length; i++) { var obstacle = obstacles[i]; if (heart.intersects(obstacle)) { LK.getSound('hit').play(); LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } } // Victory condition if (currentLevel > 5) { LK.showYouWin(); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Heart = Container.expand(function () {
var self = Container.call(this);
var heartGraphics = self.attachAsset('heart', {
anchorX: 0.5,
anchorY: 0.5
});
self.driftX = 3;
self.driftY = 2;
self.baseSize = 1;
self.lettersCollected = 0;
self.update = function () {
self.x += self.driftX;
self.y += self.driftY;
// Wrap around screen edges
if (self.x < 0) self.x = 2048;
if (self.x > 2048) self.x = 0;
if (self.y < 0) self.y = 2732;
if (self.y > 2732) self.y = 0;
};
self.changeDriftDirection = function () {
self.driftX = -self.driftX;
self.driftY = -self.driftY;
};
self.collectLetter = function () {
self.lettersCollected++;
var newScale = self.baseSize + self.lettersCollected * 0.1;
tween(heartGraphics, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 300,
easing: tween.easeOut
});
// Change color based on letters collected
var colors = [0xff69b4, 0xff1493, 0xdc143c, 0xb22222];
var colorIndex = Math.min(Math.floor(self.lettersCollected / 3), colors.length - 1);
tween(heartGraphics, {
tint: colors[colorIndex]
}, {
duration: 500
});
};
return self;
});
var LoveLetter = Container.expand(function () {
var self = Container.call(this);
var letterGraphics = self.attachAsset('loveLetter', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
letterGraphics.rotation += 0.05;
// Gentle floating animation
letterGraphics.y += Math.sin(LK.ticks * 0.1 + self.x * 0.01) * 0.5;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000022
});
/****
* Game Code
****/
var heart = game.addChild(new Heart());
heart.x = 1024;
heart.y = 1366;
var loveLetters = [];
var obstacles = [];
var targetLetters = 10;
var currentLevel = 1;
// UI Elements
var scoreTxt = new Text2('Letters: 0/' + targetLetters, {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var levelTxt = new Text2('Level ' + currentLevel, {
size: 60,
fill: 0xFFB6C1
});
levelTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(levelTxt);
levelTxt.x -= 50;
levelTxt.y += 50;
// Generate initial love letters
function spawnLoveLetters() {
for (var i = 0; i < targetLetters; i++) {
var letter = new LoveLetter();
letter.x = Math.random() * 1800 + 124;
letter.y = Math.random() * 2400 + 166;
loveLetters.push(letter);
game.addChild(letter);
}
}
// Generate obstacles
function spawnObstacles() {
var obstacleCount = currentLevel + 2;
for (var i = 0; i < obstacleCount; i++) {
var obstacle = new Obstacle();
obstacle.x = Math.random() * 1800 + 124;
obstacle.y = Math.random() * 2400 + 166;
// Make sure obstacles don't spawn too close to heart or letters
var tooClose = true;
var attempts = 0;
while (tooClose && attempts < 20) {
tooClose = false;
// Check distance from heart
var heartDist = Math.sqrt(Math.pow(obstacle.x - heart.x, 2) + Math.pow(obstacle.y - heart.y, 2));
if (heartDist < 200) tooClose = true;
// Check distance from letters
for (var j = 0; j < loveLetters.length; j++) {
var letterDist = Math.sqrt(Math.pow(obstacle.x - loveLetters[j].x, 2) + Math.pow(obstacle.y - loveLetters[j].y, 2));
if (letterDist < 150) tooClose = true;
}
if (tooClose) {
obstacle.x = Math.random() * 1800 + 124;
obstacle.y = Math.random() * 2400 + 166;
}
attempts++;
}
obstacles.push(obstacle);
game.addChild(obstacle);
}
}
function nextLevel() {
currentLevel++;
targetLetters += 3;
// Clear existing letters and obstacles
for (var i = loveLetters.length - 1; i >= 0; i--) {
loveLetters[i].destroy();
}
loveLetters = [];
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
}
obstacles = [];
// Reset heart position
heart.x = 1024;
heart.y = 1366;
heart.lettersCollected = 0;
// Update UI
scoreTxt.setText('Letters: 0/' + targetLetters);
levelTxt.setText('Level ' + currentLevel);
// Spawn new elements
spawnLoveLetters();
spawnObstacles();
// Flash screen to indicate level change
LK.effects.flashScreen(0x9370db, 800);
}
// Initialize first level
spawnLoveLetters();
spawnObstacles();
// Game input handling
game.down = function (x, y, obj) {
heart.changeDriftDirection();
};
// Main game loop
game.update = function () {
// Check collision with love letters
for (var i = loveLetters.length - 1; i >= 0; i--) {
var letter = loveLetters[i];
if (!letter.collected && heart.intersects(letter)) {
letter.collected = true;
heart.collectLetter();
LK.setScore(LK.getScore() + 10);
LK.getSound('collect').play();
// Remove letter with animation
tween(letter, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
letter.destroy();
}
});
loveLetters.splice(i, 1);
// Update score display
scoreTxt.setText('Letters: ' + heart.lettersCollected + '/' + targetLetters);
// Check if level complete
if (heart.lettersCollected >= targetLetters) {
LK.setTimeout(function () {
nextLevel();
}, 500);
}
}
}
// Check collision with obstacles
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (heart.intersects(obstacle)) {
LK.getSound('hit').play();
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Victory condition
if (currentLevel > 5) {
LK.showYouWin();
}
};