/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Enemy Cube Class
var EnemyCube = Container.expand(function () {
var self = Container.call(this);
// Assign a unique asset per enemy
var assetId = self.assetId || 'enemyCube1';
var enemyAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Movement speed in px per frame
self.speed = 7 + Math.random() * 3; // 7-10 px/frame
// Current movement direction (angle in radians)
self.direction = Math.random() * Math.PI * 2;
// Time until next direction change (in ticks)
self.ticksToChange = 60 + Math.floor(Math.random() * 90); // 1-2.5 seconds
// Update method: move, bounce, randomize direction
self.update = function () {
// Move in current direction
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Bounce off walls
var halfW = enemyAsset.width / 2;
var halfH = enemyAsset.height / 2;
// Left/right
if (self.x - halfW < 0) {
self.x = halfW;
self.direction = Math.PI - self.direction;
}
if (self.x + halfW > 2048) {
self.x = 2048 - halfW;
self.direction = Math.PI - self.direction;
}
// Top/bottom
if (self.y - halfH < 0) {
self.y = halfH;
self.direction = -self.direction;
}
if (self.y + halfH > 2732) {
self.y = 2732 - halfH;
self.direction = -self.direction;
}
// Randomly change direction
self.ticksToChange--;
if (self.ticksToChange <= 0) {
// Pick a new random direction, keep speed
var oldDir = self.direction;
// Avoid picking a direction too close to the current one
var delta = (Math.random() - 0.5) * Math.PI; // -90 to +90 deg
self.direction = (self.direction + delta) % (Math.PI * 2);
self.ticksToChange = 60 + Math.floor(Math.random() * 90);
}
};
return self;
});
// Player Cube Class
var PlayerCube = Container.expand(function () {
var self = Container.call(this);
var playerAsset = self.attachAsset('playerCube', {
anchorX: 0.5,
anchorY: 0.5
});
// Store reference to asset for safe access elsewhere
self.playerAsset = playerAsset;
// No update needed; movement is handled by drag
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xffffff // White background for clear visibility
});
/****
* Game Code
****/
// Score variables
// Add background asset behind all cubes
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(background);
// Player and enemy cubes (distinct colors)
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: 0x222222
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Player setup
var player = new PlayerCube();
game.addChild(player);
// Center player
player.x = 2048 / 2;
player.y = 2732 / 2;
// Enemy setup
var enemyAssets = ['enemyCube1', 'enemyCube2', 'enemyCube3', 'enemyCube4'];
var enemies = [];
for (var i = 0; i < 4; i++) {
var enemy = new EnemyCube();
enemy.assetId = enemyAssets[i];
// Place enemies at random positions, not overlapping player
var safe = false;
while (!safe) {
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 200 + Math.random() * (2732 - 400);
// Check not overlapping player using bounding box intersection
var eW = LK.getAsset(enemy.assetId, {
anchorX: 0.5,
anchorY: 0.5
}).width;
var eH = LK.getAsset(enemy.assetId, {
anchorX: 0.5,
anchorY: 0.5
}).height;
var pW = player.playerAsset.width;
var pH = player.playerAsset.height;
if (Math.abs(enemy.x - player.x) > (eW + pW) / 2 || Math.abs(enemy.y - player.y) > (eH + pH) / 2) safe = true;
}
enemies.push(enemy);
game.addChild(enemy);
}
// Dragging logic
var pointerDown = false;
// Move handler: move player directly to pointer position while pointer is down, clamp to screen
function handleMove(x, y, obj) {
// Always move player to pointer/finger position, regardless of pointerDown
var halfW = player.playerAsset.width / 2;
var halfH = player.playerAsset.height / 2;
var nx = Math.max(halfW, Math.min(2048 - halfW, x));
var ny = Math.max(halfH, Math.min(2732 - halfH, y));
player.x = nx;
player.y = ny;
}
game.move = handleMove;
// Down: start moving player to pointer position
game.down = function (x, y, obj) {
pointerDown = true;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
pointerDown = false;
};
// Collision detection helper
function checkCollision(a, b) {
// Both are containers with anchor 0.5,0.5, use bounding box
var aw = a.playerAsset ? a.playerAsset.width : a.children && a.children[0] ? a.children[0].width : 0,
ah = a.playerAsset ? a.playerAsset.height : a.children && a.children[0] ? a.children[0].height : 0;
var bw = b.playerAsset ? b.playerAsset.width : b.children && b.children[0] ? b.children[0].width : 0,
bh = b.playerAsset ? b.playerAsset.height : b.children && b.children[0] ? b.children[0].height : 0;
return Math.abs(a.x - b.x) < (aw + bw) / 2 && Math.abs(a.y - b.y) < (ah + bh) / 2;
}
// Score timer: +1 every second
var scoreTimer = LK.setInterval(function () {
score++;
scoreTxt.setText(score);
}, 1000);
// Game update: move enemies, check collisions
var gameOver = false;
game.update = function () {
if (gameOver) return;
// Move enemies
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
// Track last collision state for each enemy
if (typeof enemies[i].lastWasIntersecting === "undefined") {
enemies[i].lastWasIntersecting = false;
}
var nowIntersecting = player.intersects(enemies[i]);
// Only trigger game over on collision start
if (!enemies[i].lastWasIntersecting && nowIntersecting) {
LK.effects.flashScreen(0xff0000, 1000);
gameOver = true;
LK.clearInterval(scoreTimer);
LK.showGameOver();
return;
}
enemies[i].lastWasIntersecting = nowIntersecting;
}
};
// Reset score on game restart
LK.on('gameStart', function () {
score = 0;
scoreTxt.setText(score);
gameOver = false;
// Reset player position
player.x = 2048 / 2;
player.y = 2732 / 2;
// Reset enemies to new random positions
for (var i = 0; i < enemies.length; i++) {
var safe = false;
while (!safe) {
enemies[i].x = 200 + Math.random() * (2048 - 400);
enemies[i].y = 200 + Math.random() * (2732 - 400);
// Check not overlapping player using bounding box intersection
var eW = LK.getAsset(enemies[i].assetId, {
anchorX: 0.5,
anchorY: 0.5
}).width;
var eH = LK.getAsset(enemies[i].assetId, {
anchorX: 0.5,
anchorY: 0.5
}).height;
var pW = player.playerAsset.width;
var pH = player.playerAsset.height;
if (Math.abs(enemies[i].x - player.x) > (eW + pW) / 2 || Math.abs(enemies[i].y - player.y) > (eH + pH) / 2) safe = true;
}
enemies[i].direction = Math.random() * Math.PI * 2;
enemies[i].ticksToChange = 60 + Math.floor(Math.random() * 90);
}
// Restart score timer
LK.clearInterval(scoreTimer);
scoreTimer = LK.setInterval(function () {
score++;
scoreTxt.setText(score);
}, 1000);
}); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Enemy Cube Class
var EnemyCube = Container.expand(function () {
var self = Container.call(this);
// Assign a unique asset per enemy
var assetId = self.assetId || 'enemyCube1';
var enemyAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Movement speed in px per frame
self.speed = 7 + Math.random() * 3; // 7-10 px/frame
// Current movement direction (angle in radians)
self.direction = Math.random() * Math.PI * 2;
// Time until next direction change (in ticks)
self.ticksToChange = 60 + Math.floor(Math.random() * 90); // 1-2.5 seconds
// Update method: move, bounce, randomize direction
self.update = function () {
// Move in current direction
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
// Bounce off walls
var halfW = enemyAsset.width / 2;
var halfH = enemyAsset.height / 2;
// Left/right
if (self.x - halfW < 0) {
self.x = halfW;
self.direction = Math.PI - self.direction;
}
if (self.x + halfW > 2048) {
self.x = 2048 - halfW;
self.direction = Math.PI - self.direction;
}
// Top/bottom
if (self.y - halfH < 0) {
self.y = halfH;
self.direction = -self.direction;
}
if (self.y + halfH > 2732) {
self.y = 2732 - halfH;
self.direction = -self.direction;
}
// Randomly change direction
self.ticksToChange--;
if (self.ticksToChange <= 0) {
// Pick a new random direction, keep speed
var oldDir = self.direction;
// Avoid picking a direction too close to the current one
var delta = (Math.random() - 0.5) * Math.PI; // -90 to +90 deg
self.direction = (self.direction + delta) % (Math.PI * 2);
self.ticksToChange = 60 + Math.floor(Math.random() * 90);
}
};
return self;
});
// Player Cube Class
var PlayerCube = Container.expand(function () {
var self = Container.call(this);
var playerAsset = self.attachAsset('playerCube', {
anchorX: 0.5,
anchorY: 0.5
});
// Store reference to asset for safe access elsewhere
self.playerAsset = playerAsset;
// No update needed; movement is handled by drag
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xffffff // White background for clear visibility
});
/****
* Game Code
****/
// Score variables
// Add background asset behind all cubes
var background = LK.getAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
game.addChild(background);
// Player and enemy cubes (distinct colors)
var score = 0;
var scoreTxt = new Text2('0', {
size: 120,
fill: 0x222222
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Player setup
var player = new PlayerCube();
game.addChild(player);
// Center player
player.x = 2048 / 2;
player.y = 2732 / 2;
// Enemy setup
var enemyAssets = ['enemyCube1', 'enemyCube2', 'enemyCube3', 'enemyCube4'];
var enemies = [];
for (var i = 0; i < 4; i++) {
var enemy = new EnemyCube();
enemy.assetId = enemyAssets[i];
// Place enemies at random positions, not overlapping player
var safe = false;
while (!safe) {
enemy.x = 200 + Math.random() * (2048 - 400);
enemy.y = 200 + Math.random() * (2732 - 400);
// Check not overlapping player using bounding box intersection
var eW = LK.getAsset(enemy.assetId, {
anchorX: 0.5,
anchorY: 0.5
}).width;
var eH = LK.getAsset(enemy.assetId, {
anchorX: 0.5,
anchorY: 0.5
}).height;
var pW = player.playerAsset.width;
var pH = player.playerAsset.height;
if (Math.abs(enemy.x - player.x) > (eW + pW) / 2 || Math.abs(enemy.y - player.y) > (eH + pH) / 2) safe = true;
}
enemies.push(enemy);
game.addChild(enemy);
}
// Dragging logic
var pointerDown = false;
// Move handler: move player directly to pointer position while pointer is down, clamp to screen
function handleMove(x, y, obj) {
// Always move player to pointer/finger position, regardless of pointerDown
var halfW = player.playerAsset.width / 2;
var halfH = player.playerAsset.height / 2;
var nx = Math.max(halfW, Math.min(2048 - halfW, x));
var ny = Math.max(halfH, Math.min(2732 - halfH, y));
player.x = nx;
player.y = ny;
}
game.move = handleMove;
// Down: start moving player to pointer position
game.down = function (x, y, obj) {
pointerDown = true;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
pointerDown = false;
};
// Collision detection helper
function checkCollision(a, b) {
// Both are containers with anchor 0.5,0.5, use bounding box
var aw = a.playerAsset ? a.playerAsset.width : a.children && a.children[0] ? a.children[0].width : 0,
ah = a.playerAsset ? a.playerAsset.height : a.children && a.children[0] ? a.children[0].height : 0;
var bw = b.playerAsset ? b.playerAsset.width : b.children && b.children[0] ? b.children[0].width : 0,
bh = b.playerAsset ? b.playerAsset.height : b.children && b.children[0] ? b.children[0].height : 0;
return Math.abs(a.x - b.x) < (aw + bw) / 2 && Math.abs(a.y - b.y) < (ah + bh) / 2;
}
// Score timer: +1 every second
var scoreTimer = LK.setInterval(function () {
score++;
scoreTxt.setText(score);
}, 1000);
// Game update: move enemies, check collisions
var gameOver = false;
game.update = function () {
if (gameOver) return;
// Move enemies
for (var i = 0; i < enemies.length; i++) {
enemies[i].update();
// Track last collision state for each enemy
if (typeof enemies[i].lastWasIntersecting === "undefined") {
enemies[i].lastWasIntersecting = false;
}
var nowIntersecting = player.intersects(enemies[i]);
// Only trigger game over on collision start
if (!enemies[i].lastWasIntersecting && nowIntersecting) {
LK.effects.flashScreen(0xff0000, 1000);
gameOver = true;
LK.clearInterval(scoreTimer);
LK.showGameOver();
return;
}
enemies[i].lastWasIntersecting = nowIntersecting;
}
};
// Reset score on game restart
LK.on('gameStart', function () {
score = 0;
scoreTxt.setText(score);
gameOver = false;
// Reset player position
player.x = 2048 / 2;
player.y = 2732 / 2;
// Reset enemies to new random positions
for (var i = 0; i < enemies.length; i++) {
var safe = false;
while (!safe) {
enemies[i].x = 200 + Math.random() * (2048 - 400);
enemies[i].y = 200 + Math.random() * (2732 - 400);
// Check not overlapping player using bounding box intersection
var eW = LK.getAsset(enemies[i].assetId, {
anchorX: 0.5,
anchorY: 0.5
}).width;
var eH = LK.getAsset(enemies[i].assetId, {
anchorX: 0.5,
anchorY: 0.5
}).height;
var pW = player.playerAsset.width;
var pH = player.playerAsset.height;
if (Math.abs(enemies[i].x - player.x) > (eW + pW) / 2 || Math.abs(enemies[i].y - player.y) > (eH + pH) / 2) safe = true;
}
enemies[i].direction = Math.random() * Math.PI * 2;
enemies[i].ticksToChange = 60 + Math.floor(Math.random() * 90);
}
// Restart score timer
LK.clearInterval(scoreTimer);
scoreTimer = LK.setInterval(function () {
score++;
scoreTxt.setText(score);
}, 1000);
});