/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Barikat (Barricade) class: simple container with building asset, size and anchor centered
var Barikat = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = gfx.width;
self.height = gfx.height;
return self;
});
// Player class: simple container with player asset, size and anchor centered
var Player = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Set width/height for collision
self.width = gfx.width;
self.height = gfx.height;
return self;
});
// Shadow class: simple container with shadow asset, size and anchor centered
var Shadow = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = gfx.width;
self.height = gfx.height;
return self;
});
/****
* Initialize Game
****/
// Neighborhood class: represents a single neighborhood with its own buildings and offset
// Register wall asset (gray box)
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Neighborhood class: represents a single neighborhood with its own buildings and offset
// --- Game constants ---
// Building size and color
// Register building asset (gray box)
var Neighborhood = function Neighborhood(opts) {
// opts: {x, y, buildings: [{x, y}], id}
this.x = opts.x;
this.y = opts.y;
this.id = opts.id;
this.buildings = [];
// Store barikat positions directly (Barikat objects will be created later)
for (var i = 0; i < opts.buildings.length; i++) {
var pos = {
x: opts.buildings[i].x + this.x,
y: opts.buildings[i].y + this.y
};
this.buildings.push(pos);
}
};
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAYER_SIZE = 120;
var SHADOW_SIZE = 320;
var DELAY_SECONDS = 2; // Shadow delay in seconds
var DELAY_FRAMES = DELAY_SECONDS * 60; // 60 FPS
// --- Neighborhoods ---
var neighborhoods = [];
var currentNeighborhood = null;
// No buildings
var NEIGHBORHOOD_SIZE = 2048; // Each neighborhood is 2048x2732, but we use 2048x2048 for easier transitions
// Helper to generate random barikat positions (not too close to center)
function randomBarikats(count) {
var arr = [];
for (var i = 0; i < count; i++) {
// Avoid center 600x600 area, bias toward edges
var edge = Math.random() < 0.5;
var x, y;
if (edge) {
// Place near edge
x = Math.random() < 0.5 ? 200 + Math.random() * 300 : NEIGHBORHOOD_SIZE - 200 - Math.random() * 300;
y = 200 + Math.random() * (NEIGHBORHOOD_SIZE - 400);
} else {
// Place anywhere but not center
do {
x = 200 + Math.random() * (NEIGHBORHOOD_SIZE - 400);
y = 200 + Math.random() * (NEIGHBORHOOD_SIZE - 400);
} while (Math.abs(x - NEIGHBORHOOD_SIZE / 2) < 300 && Math.abs(y - NEIGHBORHOOD_SIZE / 2) < 300);
}
arr.push({
x: Math.floor(x),
y: Math.floor(y)
});
}
return arr;
}
neighborhoods = [new Neighborhood({
x: 0,
y: 0,
id: 0,
buildings: randomBarikats(3)
}),
// top-left
new Neighborhood({
x: NEIGHBORHOOD_SIZE,
y: 0,
id: 1,
buildings: randomBarikats(3)
}),
// top-right
new Neighborhood({
x: 0,
y: NEIGHBORHOOD_SIZE,
id: 2,
buildings: randomBarikats(3)
}),
// bottom-left
new Neighborhood({
x: NEIGHBORHOOD_SIZE,
y: NEIGHBORHOOD_SIZE,
id: 3,
buildings: randomBarikats(3)
}) // bottom-right
];
currentNeighborhood = neighborhoods[0];
// Add background asset covering the whole game area
var bg_full = LK.getAsset('bg_full', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(bg_full);
var player = new Player();
var shadow = new Shadow();
var moveHistory = []; // Array of {x, y} for each frame
var dragNode = null;
var lastIntersecting = false;
var timeSurvived = 0; // in frames
// --- UI ---
var timerTxt = new Text2('0.0', {
size: 120,
fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
// --- Initial positions (centered in first neighborhood, but offset so shadow doesn't start on top) ---
player.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
player.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 + 200;
shadow.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
shadow.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 - 200;
game.addChild(player);
game.addChild(shadow);
// --- Add all barikats to the game world (from all neighborhoods) ---
for (var n = 0; n < neighborhoods.length; n++) {
for (var b = 0; b < neighborhoods[n].buildings.length; b++) {
var barikat = new Barikat();
barikat.x = neighborhoods[n].buildings[b].x + neighborhoods[n].x;
barikat.y = neighborhoods[n].buildings[b].y + neighborhoods[n].y;
game.addChild(barikat);
// Store reference for collision (already in buildings array)
neighborhoods[n].buildings[b] = barikat;
}
}
// --- Move handler (dragging the player) ---
function handleMove(x, y, obj) {
// Always follow mouse/touch position directly
// Clamp to current neighborhood area, keep player fully visible
var half = PLAYER_SIZE / 2;
var nX = currentNeighborhood.x;
var nY = currentNeighborhood.y;
var nW = NEIGHBORHOOD_SIZE;
var nH = NEIGHBORHOOD_SIZE;
var newX = Math.max(nX + half, Math.min(nX + nW - half, x));
var newY = Math.max(nY + half, Math.min(nY + nH - half, y));
// Barikat collision: block player if would overlap a barikat in current neighborhood
var blocked = false;
for (var i = 0; i < currentNeighborhood.buildings.length; i++) {
var b = currentNeighborhood.buildings[i];
// Axis-aligned bounding box collision
if (Math.abs(newX - b.x) < PLAYER_SIZE / 2 + 200 &&
// 200 = barikat half size
Math.abs(newY - b.y) < PLAYER_SIZE / 2 + 200) {
blocked = true;
break;
}
}
if (!blocked) {
player.x = newX;
player.y = newY;
}
// If blocked, player stays at previous position
// --- Neighborhood transition logic ---
// If player reaches edge, move to adjacent neighborhood (wrap if needed)
var changed = false;
if (player.x <= nX + half + 2) {
// Move to left neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].x === nX - nW && neighborhoods[i].y === nY) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.x = currentNeighborhood.x + nW - half - 2;
break;
}
}
}
if (player.x >= nX + nW - half - 2) {
// Move to right neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].x === nX + nW && neighborhoods[i].y === nY) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.x = currentNeighborhood.x + half + 2;
break;
}
}
}
if (player.y <= nY + half + 2) {
// Move to top neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].y === nY - nH && neighborhoods[i].x === nX) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.y = currentNeighborhood.y + nH - half - 2;
break;
}
}
}
if (player.y >= nY + nH - half - 2) {
// Move to bottom neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].y === nY + nH && neighborhoods[i].x === nX) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.y = currentNeighborhood.y + half + 2;
break;
}
}
}
// Check collision (shadow catches player)
var currentIntersecting = player.intersects(shadow);
if (!lastIntersecting && currentIntersecting) {
// Flash screen red and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
lastIntersecting = currentIntersecting;
}
// --- Touch/drag events ---
game.down = function (x, y, obj) {
// Only start drag if touch is on player
var local = player.toLocal(game.toGlobal({
x: x,
y: y
}));
// Check if inside player bounds
if (Math.abs(local.x) <= PLAYER_SIZE / 2 && Math.abs(local.y) <= PLAYER_SIZE / 2) {
dragNode = player;
handleMove(x, y, obj);
}
};
game.move = handleMove;
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Main game loop ---
game.update = function () {
// --- Record player position for shadow to follow ---
// Store only x and y (no rotation/scale)
moveHistory.push({
x: player.x,
y: player.y
});
if (moveHistory.length > DELAY_FRAMES + 1) {
// Keep only needed history
moveHistory.shift();
}
// --- Move shadow directly toward player ---
// Shadow waits DELAY_SECONDS before starting to move
if (timeSurvived >= DELAY_FRAMES) {
// Shadow moves directly toward the player's current position, even across neighborhoods
var dx = player.x - shadow.x;
var dy = player.y - shadow.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0.1) {
var speed = 18; // Shadow speed per frame (tune as needed for difficulty)
var moveX = dx / dist * Math.min(speed, dist);
var moveY = dy / dist * Math.min(speed, dist);
shadow.x = shadow.x + moveX;
shadow.y = shadow.y + moveY;
}
}
// --- Update timer ---
timeSurvived++;
var seconds = timeSurvived / 60;
// Show with 1 decimal
timerTxt.setText(seconds.toFixed(1));
// --- Instant death if shadow touches player (even if already intersecting) ---
if (player.intersects(shadow)) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// --- Win condition? (Optional: survive X seconds) ---
// For MVP, no win condition, just survive as long as possible
};
// --- Reset state on game restart ---
LK.on('gameStart', function () {
// Reset to first neighborhood
currentNeighborhood = neighborhoods[0];
player.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
player.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 + 200;
shadow.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
shadow.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 - 200;
moveHistory = [];
timeSurvived = 0;
lastIntersecting = false;
dragNode = null;
timerTxt.setText('0.0');
}); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Barikat (Barricade) class: simple container with building asset, size and anchor centered
var Barikat = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = gfx.width;
self.height = gfx.height;
return self;
});
// Player class: simple container with player asset, size and anchor centered
var Player = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Set width/height for collision
self.width = gfx.width;
self.height = gfx.height;
return self;
});
// Shadow class: simple container with shadow asset, size and anchor centered
var Shadow = Container.expand(function () {
var self = Container.call(this);
var gfx = self.attachAsset('shadow', {
anchorX: 0.5,
anchorY: 0.5
});
self.width = gfx.width;
self.height = gfx.height;
return self;
});
/****
* Initialize Game
****/
// Neighborhood class: represents a single neighborhood with its own buildings and offset
// Register wall asset (gray box)
var game = new LK.Game({
backgroundColor: 0x181818
});
/****
* Game Code
****/
// Neighborhood class: represents a single neighborhood with its own buildings and offset
// --- Game constants ---
// Building size and color
// Register building asset (gray box)
var Neighborhood = function Neighborhood(opts) {
// opts: {x, y, buildings: [{x, y}], id}
this.x = opts.x;
this.y = opts.y;
this.id = opts.id;
this.buildings = [];
// Store barikat positions directly (Barikat objects will be created later)
for (var i = 0; i < opts.buildings.length; i++) {
var pos = {
x: opts.buildings[i].x + this.x,
y: opts.buildings[i].y + this.y
};
this.buildings.push(pos);
}
};
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAYER_SIZE = 120;
var SHADOW_SIZE = 320;
var DELAY_SECONDS = 2; // Shadow delay in seconds
var DELAY_FRAMES = DELAY_SECONDS * 60; // 60 FPS
// --- Neighborhoods ---
var neighborhoods = [];
var currentNeighborhood = null;
// No buildings
var NEIGHBORHOOD_SIZE = 2048; // Each neighborhood is 2048x2732, but we use 2048x2048 for easier transitions
// Helper to generate random barikat positions (not too close to center)
function randomBarikats(count) {
var arr = [];
for (var i = 0; i < count; i++) {
// Avoid center 600x600 area, bias toward edges
var edge = Math.random() < 0.5;
var x, y;
if (edge) {
// Place near edge
x = Math.random() < 0.5 ? 200 + Math.random() * 300 : NEIGHBORHOOD_SIZE - 200 - Math.random() * 300;
y = 200 + Math.random() * (NEIGHBORHOOD_SIZE - 400);
} else {
// Place anywhere but not center
do {
x = 200 + Math.random() * (NEIGHBORHOOD_SIZE - 400);
y = 200 + Math.random() * (NEIGHBORHOOD_SIZE - 400);
} while (Math.abs(x - NEIGHBORHOOD_SIZE / 2) < 300 && Math.abs(y - NEIGHBORHOOD_SIZE / 2) < 300);
}
arr.push({
x: Math.floor(x),
y: Math.floor(y)
});
}
return arr;
}
neighborhoods = [new Neighborhood({
x: 0,
y: 0,
id: 0,
buildings: randomBarikats(3)
}),
// top-left
new Neighborhood({
x: NEIGHBORHOOD_SIZE,
y: 0,
id: 1,
buildings: randomBarikats(3)
}),
// top-right
new Neighborhood({
x: 0,
y: NEIGHBORHOOD_SIZE,
id: 2,
buildings: randomBarikats(3)
}),
// bottom-left
new Neighborhood({
x: NEIGHBORHOOD_SIZE,
y: NEIGHBORHOOD_SIZE,
id: 3,
buildings: randomBarikats(3)
}) // bottom-right
];
currentNeighborhood = neighborhoods[0];
// Add background asset covering the whole game area
var bg_full = LK.getAsset('bg_full', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(bg_full);
var player = new Player();
var shadow = new Shadow();
var moveHistory = []; // Array of {x, y} for each frame
var dragNode = null;
var lastIntersecting = false;
var timeSurvived = 0; // in frames
// --- UI ---
var timerTxt = new Text2('0.0', {
size: 120,
fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
// --- Initial positions (centered in first neighborhood, but offset so shadow doesn't start on top) ---
player.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
player.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 + 200;
shadow.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
shadow.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 - 200;
game.addChild(player);
game.addChild(shadow);
// --- Add all barikats to the game world (from all neighborhoods) ---
for (var n = 0; n < neighborhoods.length; n++) {
for (var b = 0; b < neighborhoods[n].buildings.length; b++) {
var barikat = new Barikat();
barikat.x = neighborhoods[n].buildings[b].x + neighborhoods[n].x;
barikat.y = neighborhoods[n].buildings[b].y + neighborhoods[n].y;
game.addChild(barikat);
// Store reference for collision (already in buildings array)
neighborhoods[n].buildings[b] = barikat;
}
}
// --- Move handler (dragging the player) ---
function handleMove(x, y, obj) {
// Always follow mouse/touch position directly
// Clamp to current neighborhood area, keep player fully visible
var half = PLAYER_SIZE / 2;
var nX = currentNeighborhood.x;
var nY = currentNeighborhood.y;
var nW = NEIGHBORHOOD_SIZE;
var nH = NEIGHBORHOOD_SIZE;
var newX = Math.max(nX + half, Math.min(nX + nW - half, x));
var newY = Math.max(nY + half, Math.min(nY + nH - half, y));
// Barikat collision: block player if would overlap a barikat in current neighborhood
var blocked = false;
for (var i = 0; i < currentNeighborhood.buildings.length; i++) {
var b = currentNeighborhood.buildings[i];
// Axis-aligned bounding box collision
if (Math.abs(newX - b.x) < PLAYER_SIZE / 2 + 200 &&
// 200 = barikat half size
Math.abs(newY - b.y) < PLAYER_SIZE / 2 + 200) {
blocked = true;
break;
}
}
if (!blocked) {
player.x = newX;
player.y = newY;
}
// If blocked, player stays at previous position
// --- Neighborhood transition logic ---
// If player reaches edge, move to adjacent neighborhood (wrap if needed)
var changed = false;
if (player.x <= nX + half + 2) {
// Move to left neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].x === nX - nW && neighborhoods[i].y === nY) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.x = currentNeighborhood.x + nW - half - 2;
break;
}
}
}
if (player.x >= nX + nW - half - 2) {
// Move to right neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].x === nX + nW && neighborhoods[i].y === nY) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.x = currentNeighborhood.x + half + 2;
break;
}
}
}
if (player.y <= nY + half + 2) {
// Move to top neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].y === nY - nH && neighborhoods[i].x === nX) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.y = currentNeighborhood.y + nH - half - 2;
break;
}
}
}
if (player.y >= nY + nH - half - 2) {
// Move to bottom neighbor if exists
for (var i = 0; i < neighborhoods.length; i++) {
if (neighborhoods[i].y === nY + nH && neighborhoods[i].x === nX) {
currentNeighborhood = neighborhoods[i];
buildings = currentNeighborhood.buildings;
changed = true;
player.y = currentNeighborhood.y + half + 2;
break;
}
}
}
// Check collision (shadow catches player)
var currentIntersecting = player.intersects(shadow);
if (!lastIntersecting && currentIntersecting) {
// Flash screen red and show game over
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
}
lastIntersecting = currentIntersecting;
}
// --- Touch/drag events ---
game.down = function (x, y, obj) {
// Only start drag if touch is on player
var local = player.toLocal(game.toGlobal({
x: x,
y: y
}));
// Check if inside player bounds
if (Math.abs(local.x) <= PLAYER_SIZE / 2 && Math.abs(local.y) <= PLAYER_SIZE / 2) {
dragNode = player;
handleMove(x, y, obj);
}
};
game.move = handleMove;
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Main game loop ---
game.update = function () {
// --- Record player position for shadow to follow ---
// Store only x and y (no rotation/scale)
moveHistory.push({
x: player.x,
y: player.y
});
if (moveHistory.length > DELAY_FRAMES + 1) {
// Keep only needed history
moveHistory.shift();
}
// --- Move shadow directly toward player ---
// Shadow waits DELAY_SECONDS before starting to move
if (timeSurvived >= DELAY_FRAMES) {
// Shadow moves directly toward the player's current position, even across neighborhoods
var dx = player.x - shadow.x;
var dy = player.y - shadow.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0.1) {
var speed = 18; // Shadow speed per frame (tune as needed for difficulty)
var moveX = dx / dist * Math.min(speed, dist);
var moveY = dy / dist * Math.min(speed, dist);
shadow.x = shadow.x + moveX;
shadow.y = shadow.y + moveY;
}
}
// --- Update timer ---
timeSurvived++;
var seconds = timeSurvived / 60;
// Show with 1 decimal
timerTxt.setText(seconds.toFixed(1));
// --- Instant death if shadow touches player (even if already intersecting) ---
if (player.intersects(shadow)) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
// --- Win condition? (Optional: survive X seconds) ---
// For MVP, no win condition, just survive as long as possible
};
// --- Reset state on game restart ---
LK.on('gameStart', function () {
// Reset to first neighborhood
currentNeighborhood = neighborhoods[0];
player.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
player.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 + 200;
shadow.x = currentNeighborhood.x + NEIGHBORHOOD_SIZE / 2;
shadow.y = currentNeighborhood.y + NEIGHBORHOOD_SIZE / 2 - 200;
moveHistory = [];
timeSurvived = 0;
lastIntersecting = false;
dragNode = null;
timerTxt.setText('0.0');
});
karanlık bir gölge , duman. In-Game asset. 2d. High contrast. No shadows
dümdüz gıpgri bir yer kuşbakışı 2d. In-Game asset. 2d. High contrast. No shadows
konteyınr. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
korkmuş bir adam. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat