User prompt
Make it mandatory to collect all everything at level 8
User prompt
remove all the errors in the game
User prompt
Level 18 is wrong, fix it
User prompt
Level 17 is wrong, fix it.
User prompt
Level 12 is wrong, fix it.
User prompt
Level 16 is wrong, fix it,
User prompt
Remove the shadows, I want to try something
User prompt
Add a life bar to the game and let it stand under the fog on the top right, every touch to the shadows will take 1 life. Have a maximum of 3 lives
User prompt
He's jumping from level 7 to 9a,fix it
User prompt
Edit the level numbers
User prompt
place the fog on the top right
User prompt
Add more levels
User prompt
Add more levels
User prompt
Finalize the first playable level – The ruined laboratory escape sequence. Expand the world – Adding the ruined city and survival camp locations. Enhance enemy AI – Shadow creatures react dynamically to light and sound. Implement story-driven choices – Players shape the narrative through decisions. Optimize for mobile – Ensuring smooth controls and UI for touchscreens. ↪💡 Consider importing and using the following plugins: @upit/tween.v1, @upit/storage.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Shadow Realm: Veil of Light
Initial prompt
Game Development Progress: "Shadow Realm" We've started designing the first game scene and defining the mechanics. Now, we'll focus on fine-tuning the gameplay features and expanding the world using Upit.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Artifact class: collectible for score
var Artifact = Container.expand(function () {
var self = Container.call(this);
var artifactSprite = self.attachAsset('artifact', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = artifactSprite.width / 2;
self.collected = false;
self.getCenter = function () {
return {
x: self.x,
y: self.y
};
};
return self;
});
// Door class: exit to next area
var Door = Container.expand(function () {
var self = Container.call(this);
var doorSprite = self.attachAsset('door', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = doorSprite.width;
self.height = doorSprite.height;
self.getRect = function () {
return {
x: self.x - self.width / 2,
y: self.y - self.height / 2,
width: self.width,
height: self.height
};
};
return self;
});
// Hero class: player character
var Hero = Container.expand(function () {
var self = Container.call(this);
var heroSprite = self.attachAsset('hero', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = heroSprite.width / 2;
self.lightRadius = 300; // Initial light radius
self.hasLight = false; // If currently holding a light orb
// For dragging
self.isDragging = false;
// For upgrades
self.abilities = {
lightRadius: 300
};
// For collision detection
self.getCenter = function () {
return {
x: self.x,
y: self.y
};
};
// For light effect
self.setLightRadius = function (r) {
self.lightRadius = r;
};
return self;
});
// LightOrb class: collectible light source
var LightOrb = Container.expand(function () {
var self = Container.call(this);
var orbSprite = self.attachAsset('lightOrb', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = orbSprite.width / 2;
self.collected = false;
self.getCenter = function () {
return {
x: self.x,
y: self.y
};
};
return self;
});
// Shadow class: obstacles/enemies
var Shadow = Container.expand(function () {
var self = Container.call(this);
var shadowSprite = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = shadowSprite.width / 2;
self.speed = 2 + Math.random() * 2; // Random speed for movement
self.direction = Math.random() * Math.PI * 2; // Random direction
// For simple movement (patrol)
self.update = function () {
// If reactive (Survival Camp), chase or avoid hero based on light
if (self.isReactive && typeof hero !== "undefined") {
var dx = hero.x - self.x;
var dy = hero.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (hero.hasLight && dist < hero.lightRadius + 100) {
// Avoid hero if hero has light
var angle = Math.atan2(-dy, -dx);
self.direction = angle + (Math.random() - 0.5) * 0.5;
self.speed = 3.5 + Math.random() * 1.5;
} else if (dist < 600) {
// Chase hero if close and not lit
var angle = Math.atan2(dy, dx);
self.direction = angle + (Math.random() - 0.5) * 0.2;
self.speed = 3 + Math.random();
}
}
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Bounce off walls
if (self.x < self.radius || self.x > 2048 - self.radius) {
self.direction = Math.PI - self.direction;
}
if (self.y < self.radius + 100 || self.y > 2732 - self.radius) {
self.direction = -self.direction;
}
};
// For collision detection
self.getCenter = function () {
return {
x: self.x,
y: self.y
};
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111122
});
/****
* Game Code
****/
// --- Global variables ---
/*
We use simple shapes for the MVP:
- 'hero': the player character (circle, bright color)
- 'shadow': shadow obstacles (ellipse, dark color)
- 'lightOrb': collectible light source (circle, yellowish)
- 'door': exit to next area (rectangle, light blue)
- 'fog': semi-transparent overlay for darkness (rectangle, black, alpha)
- 'artifact': collectible (star-shaped, but use ellipse for MVP, gold)
*/
var hero;
var shadows = [];
var lightOrbs = [];
var artifacts = [];
var door;
var fogOverlay;
var dragging = false;
var dragOffset = {
x: 0,
y: 0
};
var lastTouch = {
x: 0,
y: 0
};
var level = 1;
var maxLevel = 15;
var artifactCount = 0;
var artifactTotal = 0;
var lightFadeTween = null;
// --- GUI ---
var artifactTxt = new Text2('Artifacts: 0/0', {
size: 80,
fill: 0xFFE066
});
artifactTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(artifactTxt);
var levelTxt = new Text2('Level 1', {
size: 80,
fill: 0x66CCFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
// Position GUI elements
artifactTxt.y = 100;
levelTxt.y = 10;
// --- Helper functions ---
function distance(a, b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
function circleRectIntersect(cx, cy, cr, rx, ry, rw, rh) {
// Find the closest point to the circle within the rectangle
var closestX = Math.max(rx, Math.min(cx, rx + rw));
var closestY = Math.max(ry, Math.min(cy, ry + rh));
// Calculate the distance between the circle's center and this closest point
var dx = cx - closestX;
var dy = cy - closestY;
// If the distance is less than the circle's radius, an intersection occurs
return dx * dx + dy * dy < cr * cr;
}
// --- Level setup ---
function setupLevel(lvl) {
// Clear previous
for (var i = 0; i < shadows.length; i++) {
shadows[i].destroy();
}
for (var i = 0; i < lightOrbs.length; i++) {
lightOrbs[i].destroy();
}
for (var i = 0; i < artifacts.length; i++) {
artifacts[i].destroy();
}
if (door) door.destroy();
if (fogOverlay) fogOverlay.destroy();
shadows = [];
lightOrbs = [];
artifacts = [];
door = null;
fogOverlay = null;
artifactCount = 0;
// Hero position
if (!hero) {
hero = new Hero();
game.addChild(hero);
}
hero.x = 400;
hero.y = 2732 / 2;
hero.setLightRadius(300 + (lvl - 1) * 40);
hero.hasLight = false;
// --- Location logic ---
// Ruined Laboratory (level 1): default
// Ruined City (level 2-4): more shadows, more artifacts, shadows move faster
// Survival Camp (level 5+): shadows react to hero, more light orbs, artifacts clustered
if (lvl === 1) {
// Ruined Laboratory: default
var shadowCount = 3;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
do {
s.x = 700 + Math.random() * (2048 - 900);
s.y = 200 + Math.random() * (2732 - 400);
} while (distance({
x: s.x,
y: s.y
}, {
x: hero.x,
y: hero.y
}) < 400);
shadows.push(s);
game.addChild(s);
}
// Light orb: always one, placed randomly
var orb = new LightOrb();
orb.x = 400 + Math.random() * (2048 - 800);
orb.y = 300 + Math.random() * (2732 - 600);
lightOrbs.push(orb);
game.addChild(orb);
// Artifacts: 1-2
artifactTotal = 1 + Math.floor(Math.random() * 2);
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
var tries = 0;
do {
a.x = 400 + Math.random() * (2048 - 800);
a.y = 300 + Math.random() * (2732 - 600);
var ok = true;
if (distance({
x: a.x,
y: a.y
}, {
x: hero.x,
y: hero.y
}) < 300) ok = false;
for (var j = 0; j < artifacts.length; j++) {
if (distance({
x: a.x,
y: a.y
}, {
x: artifacts[j].x,
y: artifacts[j].y
}) < 200) ok = false;
}
tries++;
if (tries > 10) break;
} while (!ok);
artifacts.push(a);
game.addChild(a);
}
} else if (lvl >= 2 && lvl <= 4) {
// Ruined City: more/faster shadows, more artifacts
var shadowCount = 4 + lvl;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 1 + Math.random(); // Shadows move faster in city
do {
s.x = 400 + Math.random() * (2048 - 800);
s.y = 200 + Math.random() * (2732 - 400);
} while (distance({
x: s.x,
y: s.y
}, {
x: hero.x,
y: hero.y
}) < 400);
shadows.push(s);
game.addChild(s);
}
// Light orb: always one, placed randomly
var orb = new LightOrb();
orb.x = 400 + Math.random() * (2048 - 800);
orb.y = 300 + Math.random() * (2732 - 600);
lightOrbs.push(orb);
game.addChild(orb);
// Artifacts: 2-4
artifactTotal = 2 + Math.floor(Math.random() * 3);
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
var tries = 0;
do {
a.x = 400 + Math.random() * (2048 - 800);
a.y = 300 + Math.random() * (2732 - 600);
var ok = true;
if (distance({
x: a.x,
y: a.y
}, {
x: hero.x,
y: hero.y
}) < 300) ok = false;
for (var j = 0; j < artifacts.length; j++) {
if (distance({
x: a.x,
y: a.y
}, {
x: artifacts[j].x,
y: artifacts[j].y
}) < 200) ok = false;
}
tries++;
if (tries > 10) break;
} while (!ok);
artifacts.push(a);
game.addChild(a);
}
} else if (lvl >= 5 && lvl <= 7) {
// Survival Camp (lvl 5-7): shadows react to hero, more light orbs, artifacts clustered
var shadowCount = 6 + lvl;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 1.5 + Math.random() * 1.5;
// Shadows in camp will react to hero (AI, see update)
s.isReactive = true;
do {
s.x = 400 + Math.random() * (2048 - 800);
s.y = 200 + Math.random() * (2732 - 400);
} while (distance({
x: s.x,
y: s.y
}, {
x: hero.x,
y: hero.y
}) < 500);
shadows.push(s);
game.addChild(s);
}
// Two light orbs, placed near each other
for (var i = 0; i < 2; i++) {
var orb = new LightOrb();
orb.x = 1200 + Math.random() * 400;
orb.y = 1000 + Math.random() * 400;
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 3-5, clustered
artifactTotal = 3 + Math.floor(Math.random() * 3);
var clusterX = 1500 + Math.random() * 300;
var clusterY = 1500 + Math.random() * 300;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = clusterX + Math.random() * 120 - 60;
a.y = clusterY + Math.random() * 120 - 60;
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 8) {
// Level 8: "Collapsed Tunnels" - narrow corridor, many shadows, few orbs
var shadowCount = 12;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 2 + Math.random() * 2;
s.x = 800 + Math.random() * 400;
s.y = 400 + Math.random() * (2732 - 800);
shadows.push(s);
game.addChild(s);
}
// Only one light orb, placed at far end
var orb = new LightOrb();
orb.x = 1800;
orb.y = 2732 / 2;
lightOrbs.push(orb);
game.addChild(orb);
// Artifacts: 2, placed at dangerous spots
artifactTotal = 2;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = 1200 + i * 300;
a.y = 800 + Math.random() * 1200;
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 9) {
// Level 9: "Watcher’s Lair" - fewer, but very fast shadows, more orbs, artifacts near center
var shadowCount = 5;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 4 + Math.random() * 2;
s.x = 1000 + Math.random() * 800;
s.y = 800 + Math.random() * 1200;
s.isReactive = true;
shadows.push(s);
game.addChild(s);
}
// Three light orbs, spread out
for (var i = 0; i < 3; i++) {
var orb = new LightOrb();
orb.x = 700 + i * 400;
orb.y = 700 + Math.random() * 1500;
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 4, near center
artifactTotal = 4;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = 1000 + Math.random() * 400;
a.y = 1200 + Math.random() * 400;
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 10) {
// Level 10: "Shadow Nexus" - final, many reactive shadows, clustered orbs/artifacts
var shadowCount = 15;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 3 + Math.random() * 2;
s.isReactive = true;
s.x = 800 + Math.random() * 1000;
s.y = 600 + Math.random() * 1600;
shadows.push(s);
game.addChild(s);
}
// Four light orbs, clustered
for (var i = 0; i < 4; i++) {
var orb = new LightOrb();
orb.x = 1600 + Math.random() * 200;
orb.y = 1200 + Math.random() * 400;
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 5, clustered
artifactTotal = 5;
var clusterX = 1700;
var clusterY = 1400;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = clusterX + Math.random() * 100 - 50;
a.y = clusterY + Math.random() * 100 - 50;
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 11) {
// Level 11: "The Forgotten Vault" - maze-like, slow but smart shadows, orbs at dead ends
var shadowCount = 8;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 1 + Math.random();
s.isReactive = true;
s.x = 600 + Math.random() * 800;
s.y = 400 + Math.random() * 1800;
shadows.push(s);
game.addChild(s);
}
// Two light orbs, at far left and right
for (var i = 0; i < 2; i++) {
var orb = new LightOrb();
orb.x = i === 0 ? 400 : 2048 - 400;
orb.y = 400 + Math.random() * (2732 - 800);
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 3, spaced out
artifactTotal = 3;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = 700 + i * 400;
a.y = 800 + Math.random() * 1200;
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 12) {
// Level 12: "Flooded Passage" - fast shadows, orbs near water (bottom), artifacts top
var shadowCount = 10;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 3 + Math.random() * 2;
s.x = 600 + Math.random() * 1000;
s.y = 1000 + Math.random() * 1200;
shadows.push(s);
game.addChild(s);
}
// Three light orbs, near bottom
for (var i = 0; i < 3; i++) {
var orb = new LightOrb();
orb.x = 600 + i * 400;
orb.y = 2300 + Math.random() * 200;
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 2, near top
artifactTotal = 2;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = 800 + i * 400;
a.y = 300 + Math.random() * 200;
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 13) {
// Level 13: "The Mirror Hall" - shadows mirror hero's movement, orbs/artifacts in corners
var shadowCount = 6;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 2 + Math.random();
s.isReactive = true;
s.x = 2048 - hero.x;
s.y = 2732 - hero.y;
shadows.push(s);
game.addChild(s);
}
// Four light orbs, one in each corner
var corners = [{
x: 200,
y: 200
}, {
x: 1848,
y: 200
}, {
x: 200,
y: 2532
}, {
x: 1848,
y: 2532
}];
for (var i = 0; i < 4; i++) {
var orb = new LightOrb();
orb.x = corners[i].x;
orb.y = corners[i].y;
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 4, one in each corner (offset from orbs)
artifactTotal = 4;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = corners[i].x + 60;
a.y = corners[i].y + 60;
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 14) {
// Level 14: "The Gauntlet" - many fast, non-reactive shadows, orbs in a line, artifacts in zigzag
var shadowCount = 18;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 4 + Math.random() * 2;
s.x = 400 + Math.random() * (2048 - 800);
s.y = 200 + Math.random() * (2732 - 400);
shadows.push(s);
game.addChild(s);
}
// Five light orbs, in a horizontal line
for (var i = 0; i < 5; i++) {
var orb = new LightOrb();
orb.x = 400 + i * 320;
orb.y = 2732 / 2;
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 5, zigzag pattern
artifactTotal = 5;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = 500 + i * 300;
a.y = 600 + (i % 2 === 0 ? 400 : 1200);
artifacts.push(a);
game.addChild(a);
}
} else if (lvl === 15) {
// Level 15: "The Final Eclipse" - all shadows reactive, orbs/artifacts at center, max difficulty
var shadowCount = 20;
for (var i = 0; i < shadowCount; i++) {
var s = new Shadow();
s.speed += 5 + Math.random() * 2;
s.isReactive = true;
s.x = 400 + Math.random() * (2048 - 800);
s.y = 200 + Math.random() * (2732 - 400);
shadows.push(s);
game.addChild(s);
}
// Six light orbs, clustered at center
for (var i = 0; i < 6; i++) {
var orb = new LightOrb();
orb.x = 1024 + Math.random() * 120 - 60;
orb.y = 1366 + Math.random() * 120 - 60;
lightOrbs.push(orb);
game.addChild(orb);
}
// Artifacts: 6, clustered at center
artifactTotal = 6;
for (var i = 0; i < artifactTotal; i++) {
var a = new Artifact();
a.x = 1024 + Math.random() * 100 - 50;
a.y = 1366 + Math.random() * 100 - 50;
artifacts.push(a);
game.addChild(a);
}
}
// Door: always at far right
door = new Door();
door.x = 2048 - 200;
door.y = 2732 / 2;
game.addChild(door);
// Fog overlay: covers the whole screen, alpha depends on light
fogOverlay = LK.getAsset('fog', {
anchorX: 1,
anchorY: 0,
x: 2048,
y: 0
});
fogOverlay.alpha = 0.7;
game.addChild(fogOverlay);
// Update GUI
artifactTxt.setText('Artifacts: 0/' + artifactTotal);
levelTxt.setText('Level ' + lvl);
// --- Save progress for persistence ---
if (typeof storage !== "undefined") {
storage.level = lvl;
storage.artifacts = artifactCount;
}
}
// --- Light effect ---
function updateFogAlpha() {
// Fog alpha is lower if hero has light
if (!fogOverlay) return;
var targetAlpha = hero.hasLight ? 0.2 : 0.7;
if (lightFadeTween) tween.stop(fogOverlay, {
alpha: true
});
lightFadeTween = tween(fogOverlay, {
alpha: targetAlpha
}, {
duration: 400,
easing: tween.easeInOut
});
}
// --- Touch controls ---
game.down = function (x, y, obj) {
// Only start drag if touch is inside hero
var local = {
x: x,
y: y
};
if (distance(local, {
x: hero.x,
y: hero.y
}) < hero.radius + 30) {
dragging = true;
dragOffset.x = hero.x - x;
dragOffset.y = hero.y - y;
lastTouch.x = x;
lastTouch.y = y;
}
};
game.move = function (x, y, obj) {
if (dragging) {
// Clamp hero position to screen
var nx = x + dragOffset.x;
var ny = y + dragOffset.y;
nx = Math.max(hero.radius, Math.min(2048 - hero.radius, nx));
ny = Math.max(hero.radius + 100, Math.min(2732 - hero.radius, ny));
hero.x = nx;
hero.y = ny;
lastTouch.x = x;
lastTouch.y = y;
}
};
game.up = function (x, y, obj) {
dragging = false;
};
// --- Main update loop ---
game.update = function () {
// Shadows move
for (var i = 0; i < shadows.length; i++) {
shadows[i].update();
}
// Light orb collection
for (var i = 0; i < lightOrbs.length; i++) {
var orb = lightOrbs[i];
if (!orb.collected && distance(hero.getCenter(), orb.getCenter()) < hero.radius + orb.radius + 10) {
orb.collected = true;
hero.hasLight = true;
hero.setLightRadius(500 + (level - 1) * 50);
updateFogAlpha();
// Animate orb fade out
tween(orb, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
orb.destroy();
}
});
}
}
// Artifact collection
for (var i = 0; i < artifacts.length; i++) {
var a = artifacts[i];
if (!a.collected && distance(hero.getCenter(), a.getCenter()) < hero.radius + a.radius + 10) {
a.collected = true;
artifactCount++;
artifactTxt.setText('Artifacts: ' + artifactCount + '/' + artifactTotal);
tween(a, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
a.destroy();
}
});
// --- Story-driven choice: prompt on artifact collection ---
if (level >= 2) {
// Only show for city/camp, not tutorial
LK.setTimeout(function () {
// Show a simple choice popup (simulate with LK.effects.flashScreen and Text2 for MVP)
var choiceTxt = new Text2("You found a mysterious artifact!\nDo you use it for power or save it for later?\n(Tap left: Power, Tap right: Save)", {
size: 70,
fill: 0xFFD700
});
choiceTxt.anchor.set(0.5, 0.5);
choiceTxt.x = 2048 / 2;
choiceTxt.y = 2732 / 2;
LK.gui.center.addChild(choiceTxt);
// Listen for tap (simulate with game.down)
var choiceHandler = function choiceHandler(x, y, obj) {
if (x < 2048 / 2) {
// Power: increase light radius
hero.setLightRadius(hero.lightRadius + 80);
LK.effects.flashObject(hero, 0xFFE066, 800);
} else {
// Save: bonus score (simulate with artifactCount++)
artifactCount++;
artifactTxt.setText('Artifacts: ' + artifactCount + '/' + artifactTotal);
LK.effects.flashObject(artifactTxt, 0xFFD700, 800);
}
LK.gui.center.removeChild(choiceTxt);
game.down = origDown;
};
var origDown = game.down;
game.down = choiceHandler;
}, 500);
}
}
}
// Door: check if hero is at door and has light
if (hero.hasLight && circleRectIntersect(hero.x, hero.y, hero.radius, door.x - door.width / 2, door.y - door.height / 2, door.width, door.height)) {
// Next level or win
if (level < maxLevel) {
level++;
setupLevel(level);
} else {
LK.showYouWin();
}
return;
}
// Shadows: collision with hero (if not holding light, or if shadow is inside light radius)
for (var i = 0; i < shadows.length; i++) {
var s = shadows[i];
var d = distance(hero.getCenter(), s.getCenter());
if (d < hero.radius + s.radius - 10) {
// If hero has light, shadow is weakened (fades out if inside light radius)
if (hero.hasLight && d < hero.lightRadius) {
// Shadow fades out and is destroyed
tween(s, {
alpha: 0
}, {
duration: 400,
onFinish: function (shadow) {
return function () {
shadow.destroy();
};
}(s)
});
shadows.splice(i, 1);
i--;
continue;
} else {
// Game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
}
// Fog overlay: create a "light hole" around hero if has light
if (fogOverlay) {
// For MVP, just set fog alpha lower if hero has light
// (Advanced: could use a mask, but not supported in MVP)
// Optionally, animate a "pulse" when light is collected
}
};
// --- Start game ---
setupLevel(level); ===================================================================
--- original.js
+++ change.js
@@ -643,11 +643,11 @@
door.y = 2732 / 2;
game.addChild(door);
// Fog overlay: covers the whole screen, alpha depends on light
fogOverlay = LK.getAsset('fog', {
- anchorX: 0,
+ anchorX: 1,
anchorY: 0,
- x: 0,
+ x: 2048,
y: 0
});
fogOverlay.alpha = 0.7;
game.addChild(fogOverlay);
food. In-Game asset. 2d. High contrast. No shadows
Shadow creature. In-Game asset. 2d. High contrast. No shadows
first aid kit. In-Game asset. 2d. High contrast. No shadows
✅ Hair: Medium-length, slightly unkempt dark hair—indicating survival hardships. ✅ Height: Around 1.75m (5'9"), agile but not overly strong. ✅ Build: Lean, slightly worn-out clothing, showing signs of past struggles. ✅ Eyes: Piercing green or amber eyes, reflecting a determined personality. ✅ Accessories: A damaged jacket with scratches, adding realism to the post-apocalyptic theme. ✅ Hand Item: A broken flashlight – essential for revealing enemies but risky in the dark! Arin’s design should reflect their survival skills—not looking overly combat-ready but practical for the harsh environment. The flashlight mechanic will play a big role in interacting with the game’s shadow creatures.. In-Game asset. 2d. High contrast. No shadows
The door. In-Game asset. 2d. High contrast. No shadows