/**** * 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