Code edit (1 edits merged)
Please save this source code
User prompt
Fireless Water: The Lost Beloved
Initial prompt
Fireless Water: The Lost Beloved" Genre: Story-driven – Platformer Theme: Searching for a lost love – Romantic and melancholic tone Concept: The player controls the "Water" character, while "Fire" has mysteriously disappeared. As Water travels through different environments, flashbacks of their time together appear — memories that feel warm, happy, and sometimes bittersweet. While progressing through platforming levels, the character talks to themselves, expressing longing, confusion, and love. The goal seems to be finding Fire, but as the story unfolds, it becomes clear that the journey is really about rediscovering the fire within oneself. Although it's a single-player experience, the duality between Water and the memory of Fire makes it feel like a two-player emotional journey.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Fire (goal) class
var Fire = Container.expand(function () {
var self = Container.call(this);
var fire = self.attachAsset('fire', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Memory orb class
var Memory = Container.expand(function () {
var self = Container.call(this);
var orb = self.attachAsset('memory', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
return self;
});
// Platform class
var Platform = Container.expand(function () {
var self = Container.call(this);
var plat = self.attachAsset('platform', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Water (player) class
var Water = Container.expand(function () {
var self = Container.call(this);
var water = self.attachAsset('water', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 0;
self.vy = 0;
self.onGround = false;
self.canJump = true;
self.jumpCooldown = 0;
self.moveDir = 0; // -1 left, 1 right, 0 none
self.jumpQueued = false;
// For touch controls
self.touchStartX = null;
self.touchStartY = null;
self.touching = false;
// For narrative triggers
self.lastMemoryIndex = -1;
// Methods
self.update = function () {
// Horizontal movement
var moveSpeed = 18;
self.x += self.vx;
// Gravity
self.vy += 2.2;
if (self.vy > 40) self.vy = 40;
self.y += self.vy;
// Friction
self.vx *= 0.85;
if (Math.abs(self.vx) < 0.5) self.vx = 0;
// Prevent out of bounds
if (self.x < 60) self.x = 60;
if (self.x > 2048 - 60) self.x = 2048 - 60;
if (self.y > 2732 - 60) {
self.y = 2732 - 60;
self.vy = 0;
self.onGround = true;
}
// Jump cooldown
if (self.jumpCooldown > 0) self.jumpCooldown--;
// Touch controls: moveDir and jumpQueued are set by game.down/move/up
if (self.moveDir !== 0) {
self.vx += self.moveDir * moveSpeed * 0.5;
if (self.vx > moveSpeed) self.vx = moveSpeed;
if (self.vx < -moveSpeed) self.vx = -moveSpeed;
}
// Jump
if (self.jumpQueued && self.onGround && self.jumpCooldown === 0) {
self.vy = -38;
self.onGround = false;
self.jumpCooldown = 20;
self.jumpQueued = false;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a237e // Deep blue
});
/****
* Game Code
****/
// Goal (Fire) - orange ellipse
// Memory orb - glowing yellow ellipse
// Platform - soft gray rectangle
// Water (player) - blue ellipse
// --- Level Data ---
var levelPlatforms = [
// [x, y, width]
[1024, 2600, 800], [600, 2200, 400], [1500, 2000, 400], [400, 1700, 400], [1200, 1400, 400], [700, 1100, 400], [1700, 900, 400], [1024, 600, 600]];
var memoryPositions = [[600, 2100], [1500, 1900], [400, 1600], [1200, 1300], [700, 1000]];
var firePosition = [1024, 500];
// --- Narrative Data ---
var memoryTexts = ["I remember the first time we met. Fire was so bright, so warm.", "We danced together under the stars, our laughter echoing.", "Sometimes, Fire would flicker, uncertain. I tried to hold on.", "We shared dreams, hopes, and gentle silences.", "But one day, Fire was gone. I felt cold, empty."];
var introText = "I am Water. I have lost my Fire. Maybe, if I follow these memories, I can find them again.";
var fireText = "There you are, Fire. But maybe, what I truly needed was to find myself.";
// --- Game State ---
var platforms = [];
var memories = [];
var fire = null;
var water = null;
var collectedMemories = 0;
var showingNarrative = false;
var narrativeBox = null;
var narrativeTimeout = null;
var canControl = true;
// --- UI ---
var memoryCounter = new Text2("Memories: 0/" + memoryTexts.length, {
size: 80,
fill: 0xFFFDE7
});
memoryCounter.anchor.set(0.5, 0);
LK.gui.top.addChild(memoryCounter);
// --- Narrative Box ---
function showNarrative(text, duration) {
if (narrativeBox) {
LK.gui.center.removeChild(narrativeBox);
narrativeBox = null;
}
showingNarrative = true;
canControl = false;
narrativeBox = new Text2(text, {
size: 70,
fill: 0xFFFDE7,
align: "center",
wordWrap: true,
wordWrapWidth: 1200
});
narrativeBox.anchor.set(0.5, 0.5);
LK.gui.center.addChild(narrativeBox);
if (narrativeTimeout) LK.clearTimeout(narrativeTimeout);
narrativeTimeout = LK.setTimeout(function () {
LK.gui.center.removeChild(narrativeBox);
narrativeBox = null;
showingNarrative = false;
canControl = true;
}, duration || 2600);
}
// --- Build Level ---
function buildLevel() {
// Platforms
for (var i = 0; i < levelPlatforms.length; i++) {
var p = new Platform();
p.x = levelPlatforms[i][0];
p.y = levelPlatforms[i][1];
// Scale platform width
var platAsset = p.children[0];
platAsset.width = levelPlatforms[i][2];
platforms.push(p);
game.addChild(p);
}
// Memories
for (var j = 0; j < memoryPositions.length; j++) {
var m = new Memory();
m.x = memoryPositions[j][0];
m.y = memoryPositions[j][1];
m.memoryIndex = j;
memories.push(m);
game.addChild(m);
}
// Fire (goal)
fire = new Fire();
fire.x = firePosition[0];
fire.y = firePosition[1];
game.addChild(fire);
// Water (player)
water = new Water();
water.x = 1024;
water.y = 2500;
game.addChild(water);
}
// --- Collision Helpers ---
function rectsIntersect(a, b) {
// a, b: Containers with anchor at 0.5,0.5
var aw = a.children[0].width,
ah = a.children[0].height;
var bw = b.children[0].width,
bh = b.children[0].height;
return Math.abs(a.x - b.x) < aw / 2 + bw / 2 && Math.abs(a.y - b.y) < ah / 2 + bh / 2;
}
// --- Platform Collision ---
function handlePlatformCollision() {
water.onGround = false;
for (var i = 0; i < platforms.length; i++) {
var plat = platforms[i];
var pw = plat.children[0].width,
ph = plat.children[0].height;
var wx = water.x,
wy = water.y;
var ww = water.children[0].width,
wh = water.children[0].height;
// Simple AABB
if (wx + ww / 2 > plat.x - pw / 2 && wx - ww / 2 < plat.x + pw / 2 && wy + wh / 2 > plat.y - ph / 2 && wy - wh / 2 < plat.y + ph / 2) {
// Check if falling onto platform (from above)
var prevY = wy - water.vy;
if (prevY + wh / 2 <= plat.y - ph / 2) {
// Land on platform
water.y = plat.y - ph / 2 - wh / 2;
water.vy = 0;
water.onGround = true;
} else if (prevY - wh / 2 >= plat.y + ph / 2) {
// Hit from below
water.y = plat.y + ph / 2 + wh / 2;
water.vy = 2;
} else {
// Side collision: push out
if (wx < plat.x) {
water.x = plat.x - pw / 2 - ww / 2;
} else {
water.x = plat.x + pw / 2 + ww / 2;
}
water.vx = 0;
}
}
}
}
// --- Memory Collection ---
function handleMemoryCollection() {
for (var i = 0; i < memories.length; i++) {
var m = memories[i];
if (!m.collected && rectsIntersect(water, m)) {
m.collected = true;
collectedMemories++;
memoryCounter.setText("Memories: " + collectedMemories + "/" + memoryTexts.length);
// Animate and remove
tween(m, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 600,
easing: tween.easeOut,
onFinish: function onFinish() {
m.destroy();
}
});
// Show narrative
showNarrative(memoryTexts[m.memoryIndex], 3200);
}
}
}
// --- Fire (Goal) ---
var reachedFire = false;
function handleFireReach() {
if (!reachedFire && rectsIntersect(water, fire)) {
reachedFire = true;
showNarrative(fireText, 3500);
LK.setTimeout(function () {
LK.showYouWin();
}, 3600);
}
}
// --- Intro ---
showNarrative(introText, 3500);
// --- Build Level ---
buildLevel();
// --- Touch Controls ---
// Touch: left half = move left, right half = move right, swipe up = jump
game.down = function (x, y, obj) {
if (!canControl) return;
if (x < 2048 / 2) {
water.moveDir = -1;
} else {
water.moveDir = 1;
}
water.touchStartX = x;
water.touchStartY = y;
water.touching = true;
};
game.move = function (x, y, obj) {
if (!canControl) return;
if (!water.touching) return;
// Detect swipe up for jump
if (water.touchStartY - y > 80) {
water.jumpQueued = true;
water.touchStartY = y; // Prevent multiple jumps per swipe
}
};
game.up = function (x, y, obj) {
if (!canControl) return;
water.moveDir = 0;
water.touching = false;
};
// --- Game Update ---
game.update = function () {
if (!water) return;
if (!canControl) return;
water.update();
handlePlatformCollision();
handleMemoryCollection();
handleFireReach();
};
// --- Reset on Game Over ---
game.on('gameover', function () {
// All state will be reset by LK
}); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,319 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Fire (goal) class
+var Fire = Container.expand(function () {
+ var self = Container.call(this);
+ var fire = self.attachAsset('fire', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+// Memory orb class
+var Memory = Container.expand(function () {
+ var self = Container.call(this);
+ var orb = self.attachAsset('memory', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.collected = false;
+ return self;
+});
+// Platform class
+var Platform = Container.expand(function () {
+ var self = Container.call(this);
+ var plat = self.attachAsset('platform', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+// Water (player) class
+var Water = Container.expand(function () {
+ var self = Container.call(this);
+ var water = self.attachAsset('water', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.vx = 0;
+ self.vy = 0;
+ self.onGround = false;
+ self.canJump = true;
+ self.jumpCooldown = 0;
+ self.moveDir = 0; // -1 left, 1 right, 0 none
+ self.jumpQueued = false;
+ // For touch controls
+ self.touchStartX = null;
+ self.touchStartY = null;
+ self.touching = false;
+ // For narrative triggers
+ self.lastMemoryIndex = -1;
+ // Methods
+ self.update = function () {
+ // Horizontal movement
+ var moveSpeed = 18;
+ self.x += self.vx;
+ // Gravity
+ self.vy += 2.2;
+ if (self.vy > 40) self.vy = 40;
+ self.y += self.vy;
+ // Friction
+ self.vx *= 0.85;
+ if (Math.abs(self.vx) < 0.5) self.vx = 0;
+ // Prevent out of bounds
+ if (self.x < 60) self.x = 60;
+ if (self.x > 2048 - 60) self.x = 2048 - 60;
+ if (self.y > 2732 - 60) {
+ self.y = 2732 - 60;
+ self.vy = 0;
+ self.onGround = true;
+ }
+ // Jump cooldown
+ if (self.jumpCooldown > 0) self.jumpCooldown--;
+ // Touch controls: moveDir and jumpQueued are set by game.down/move/up
+ if (self.moveDir !== 0) {
+ self.vx += self.moveDir * moveSpeed * 0.5;
+ if (self.vx > moveSpeed) self.vx = moveSpeed;
+ if (self.vx < -moveSpeed) self.vx = -moveSpeed;
+ }
+ // Jump
+ if (self.jumpQueued && self.onGround && self.jumpCooldown === 0) {
+ self.vy = -38;
+ self.onGround = false;
+ self.jumpCooldown = 20;
+ self.jumpQueued = false;
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
+ backgroundColor: 0x1a237e // Deep blue
+});
+
+/****
+* Game Code
+****/
+// Goal (Fire) - orange ellipse
+// Memory orb - glowing yellow ellipse
+// Platform - soft gray rectangle
+// Water (player) - blue ellipse
+// --- Level Data ---
+var levelPlatforms = [
+// [x, y, width]
+[1024, 2600, 800], [600, 2200, 400], [1500, 2000, 400], [400, 1700, 400], [1200, 1400, 400], [700, 1100, 400], [1700, 900, 400], [1024, 600, 600]];
+var memoryPositions = [[600, 2100], [1500, 1900], [400, 1600], [1200, 1300], [700, 1000]];
+var firePosition = [1024, 500];
+// --- Narrative Data ---
+var memoryTexts = ["I remember the first time we met. Fire was so bright, so warm.", "We danced together under the stars, our laughter echoing.", "Sometimes, Fire would flicker, uncertain. I tried to hold on.", "We shared dreams, hopes, and gentle silences.", "But one day, Fire was gone. I felt cold, empty."];
+var introText = "I am Water. I have lost my Fire. Maybe, if I follow these memories, I can find them again.";
+var fireText = "There you are, Fire. But maybe, what I truly needed was to find myself.";
+// --- Game State ---
+var platforms = [];
+var memories = [];
+var fire = null;
+var water = null;
+var collectedMemories = 0;
+var showingNarrative = false;
+var narrativeBox = null;
+var narrativeTimeout = null;
+var canControl = true;
+// --- UI ---
+var memoryCounter = new Text2("Memories: 0/" + memoryTexts.length, {
+ size: 80,
+ fill: 0xFFFDE7
+});
+memoryCounter.anchor.set(0.5, 0);
+LK.gui.top.addChild(memoryCounter);
+// --- Narrative Box ---
+function showNarrative(text, duration) {
+ if (narrativeBox) {
+ LK.gui.center.removeChild(narrativeBox);
+ narrativeBox = null;
+ }
+ showingNarrative = true;
+ canControl = false;
+ narrativeBox = new Text2(text, {
+ size: 70,
+ fill: 0xFFFDE7,
+ align: "center",
+ wordWrap: true,
+ wordWrapWidth: 1200
+ });
+ narrativeBox.anchor.set(0.5, 0.5);
+ LK.gui.center.addChild(narrativeBox);
+ if (narrativeTimeout) LK.clearTimeout(narrativeTimeout);
+ narrativeTimeout = LK.setTimeout(function () {
+ LK.gui.center.removeChild(narrativeBox);
+ narrativeBox = null;
+ showingNarrative = false;
+ canControl = true;
+ }, duration || 2600);
+}
+// --- Build Level ---
+function buildLevel() {
+ // Platforms
+ for (var i = 0; i < levelPlatforms.length; i++) {
+ var p = new Platform();
+ p.x = levelPlatforms[i][0];
+ p.y = levelPlatforms[i][1];
+ // Scale platform width
+ var platAsset = p.children[0];
+ platAsset.width = levelPlatforms[i][2];
+ platforms.push(p);
+ game.addChild(p);
+ }
+ // Memories
+ for (var j = 0; j < memoryPositions.length; j++) {
+ var m = new Memory();
+ m.x = memoryPositions[j][0];
+ m.y = memoryPositions[j][1];
+ m.memoryIndex = j;
+ memories.push(m);
+ game.addChild(m);
+ }
+ // Fire (goal)
+ fire = new Fire();
+ fire.x = firePosition[0];
+ fire.y = firePosition[1];
+ game.addChild(fire);
+ // Water (player)
+ water = new Water();
+ water.x = 1024;
+ water.y = 2500;
+ game.addChild(water);
+}
+// --- Collision Helpers ---
+function rectsIntersect(a, b) {
+ // a, b: Containers with anchor at 0.5,0.5
+ var aw = a.children[0].width,
+ ah = a.children[0].height;
+ var bw = b.children[0].width,
+ bh = b.children[0].height;
+ return Math.abs(a.x - b.x) < aw / 2 + bw / 2 && Math.abs(a.y - b.y) < ah / 2 + bh / 2;
+}
+// --- Platform Collision ---
+function handlePlatformCollision() {
+ water.onGround = false;
+ for (var i = 0; i < platforms.length; i++) {
+ var plat = platforms[i];
+ var pw = plat.children[0].width,
+ ph = plat.children[0].height;
+ var wx = water.x,
+ wy = water.y;
+ var ww = water.children[0].width,
+ wh = water.children[0].height;
+ // Simple AABB
+ if (wx + ww / 2 > plat.x - pw / 2 && wx - ww / 2 < plat.x + pw / 2 && wy + wh / 2 > plat.y - ph / 2 && wy - wh / 2 < plat.y + ph / 2) {
+ // Check if falling onto platform (from above)
+ var prevY = wy - water.vy;
+ if (prevY + wh / 2 <= plat.y - ph / 2) {
+ // Land on platform
+ water.y = plat.y - ph / 2 - wh / 2;
+ water.vy = 0;
+ water.onGround = true;
+ } else if (prevY - wh / 2 >= plat.y + ph / 2) {
+ // Hit from below
+ water.y = plat.y + ph / 2 + wh / 2;
+ water.vy = 2;
+ } else {
+ // Side collision: push out
+ if (wx < plat.x) {
+ water.x = plat.x - pw / 2 - ww / 2;
+ } else {
+ water.x = plat.x + pw / 2 + ww / 2;
+ }
+ water.vx = 0;
+ }
+ }
+ }
+}
+// --- Memory Collection ---
+function handleMemoryCollection() {
+ for (var i = 0; i < memories.length; i++) {
+ var m = memories[i];
+ if (!m.collected && rectsIntersect(water, m)) {
+ m.collected = true;
+ collectedMemories++;
+ memoryCounter.setText("Memories: " + collectedMemories + "/" + memoryTexts.length);
+ // Animate and remove
+ tween(m, {
+ alpha: 0,
+ scaleX: 2,
+ scaleY: 2
+ }, {
+ duration: 600,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ m.destroy();
+ }
+ });
+ // Show narrative
+ showNarrative(memoryTexts[m.memoryIndex], 3200);
+ }
+ }
+}
+// --- Fire (Goal) ---
+var reachedFire = false;
+function handleFireReach() {
+ if (!reachedFire && rectsIntersect(water, fire)) {
+ reachedFire = true;
+ showNarrative(fireText, 3500);
+ LK.setTimeout(function () {
+ LK.showYouWin();
+ }, 3600);
+ }
+}
+// --- Intro ---
+showNarrative(introText, 3500);
+// --- Build Level ---
+buildLevel();
+// --- Touch Controls ---
+// Touch: left half = move left, right half = move right, swipe up = jump
+game.down = function (x, y, obj) {
+ if (!canControl) return;
+ if (x < 2048 / 2) {
+ water.moveDir = -1;
+ } else {
+ water.moveDir = 1;
+ }
+ water.touchStartX = x;
+ water.touchStartY = y;
+ water.touching = true;
+};
+game.move = function (x, y, obj) {
+ if (!canControl) return;
+ if (!water.touching) return;
+ // Detect swipe up for jump
+ if (water.touchStartY - y > 80) {
+ water.jumpQueued = true;
+ water.touchStartY = y; // Prevent multiple jumps per swipe
+ }
+};
+game.up = function (x, y, obj) {
+ if (!canControl) return;
+ water.moveDir = 0;
+ water.touching = false;
+};
+// --- Game Update ---
+game.update = function () {
+ if (!water) return;
+ if (!canControl) return;
+ water.update();
+ handlePlatformCollision();
+ handleMemoryCollection();
+ handleFireReach();
+};
+// --- Reset on Game Over ---
+game.on('gameover', function () {
+ // All state will be reset by LK
});
\ No newline at end of file