/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BlueMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('blueMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 4;
self.chargeSpeed = 8;
self.detectionRange = 400;
self.isCharging = false;
self.shootCooldown = 0;
self.maxShootCooldown = 150; // 2.5 seconds at 60fps
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect (blue tinted)
malwareGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.3) * 0.3;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.25) * 0.15;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.25) * 0.15;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Shooting behavior - shoot at player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.shootCooldown <= 0) {
self.shootCooldown = self.maxShootCooldown;
// Create projectile
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
// Calculate direction to player
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
projectile.velocityX = Math.cos(angleToPlayer) * projectile.speed;
projectile.velocityY = Math.sin(angleToPlayer) * projectile.speed;
// Add to game and projectiles array
projectiles.push(projectile);
game.addChild(projectile);
}
// Ramming behavior - detect player and start charging
if (distanceToPlayer < self.detectionRange && !self.isCharging) {
self.isCharging = true;
// Calculate charge direction
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
self.velocityX = Math.cos(angleToPlayer) * self.chargeSpeed;
self.velocityY = Math.sin(angleToPlayer) * self.chargeSpeed;
}
// Move malware
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction when not charging
if (!self.isCharging) {
self.velocityX *= 0.95;
self.velocityY *= 0.95;
}
// Stop charging if too far from original position or hit boundaries
if (self.isCharging && (distanceToPlayer > self.detectionRange * 2 || self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732)) {
self.isCharging = false;
self.velocityX *= 0.5;
self.velocityY *= 0.5;
}
// Check collision with player
var currentIntersecting = self.intersects(player);
if (!self.lastPlayerIntersecting && currentIntersecting && !playerInvulnerable) {
// Ram into player - apply strong knockback
var pushForce = 22;
var pushDirection = player.x > self.x ? 1 : -1;
player.velocityX = pushDirection * pushForce;
player.velocityY = -10;
playerHit();
}
self.lastPlayerIntersecting = currentIntersecting;
// Decrease shoot cooldown
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var DataPacket = Container.expand(function () {
var self = Container.call(this);
var packetGraphics = self.attachAsset('dataPacket', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.rotationSpeed = 0.05;
self.update = function () {
packetGraphics.rotation += self.rotationSpeed;
// Floating animation
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
};
self.collect = function () {
if (!self.collected) {
self.collected = true;
LK.setScore(LK.getScore() + 10);
scoreText.setText('Data: ' + LK.getScore());
LK.getSound('collect').play();
// Tween out
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var ElectricSpark = Container.expand(function () {
var self = Container.call(this);
var sparkGraphics = self.attachAsset('electricSpark', {
anchorX: 0.5,
anchorY: 0.5
});
self.moveDirection = 1;
self.moveSpeed = 3;
self.moveRange = 150;
self.startX = 0;
self.update = function () {
// Flash effect
sparkGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.5;
// Move back and forth
self.x += self.moveSpeed * self.moveDirection;
if (Math.abs(self.x - self.startX) > self.moveRange) {
self.moveDirection *= -1;
}
// Check player collision
if (self.intersects(player) && !playerInvulnerable) {
playerHit();
}
};
return self;
});
var GreenMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('greenMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.shootCooldown = 0;
self.maxShootCooldown = 120; // 2 seconds at 60fps
self.detectionRange = 300;
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect
malwareGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.25) * 0.3;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.1;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.2) * 0.1;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Shoot at player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.shootCooldown <= 0) {
self.shootCooldown = self.maxShootCooldown;
// Create projectile
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
// Calculate direction to player
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
projectile.velocityX = Math.cos(angleToPlayer) * projectile.speed;
projectile.velocityY = Math.sin(angleToPlayer) * projectile.speed;
// Add to game and projectiles array
projectiles.push(projectile);
game.addChild(projectile);
}
// Decrease cooldown
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var Malware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('electricSpark', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 4;
self.chargeSpeed = 8;
self.detectionRange = 400;
self.isCharging = false;
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect
malwareGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.2) * 0.4;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.15) * 0.2;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.15) * 0.2;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Detect player and start charging
if (distanceToPlayer < self.detectionRange && !self.isCharging) {
self.isCharging = true;
// Calculate charge direction
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
self.velocityX = Math.cos(angleToPlayer) * self.chargeSpeed;
self.velocityY = Math.sin(angleToPlayer) * self.chargeSpeed;
}
// Move malware
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction when not charging
if (!self.isCharging) {
self.velocityX *= 0.95;
self.velocityY *= 0.95;
}
// Stop charging if too far from original position or hit boundaries
if (self.isCharging && (distanceToPlayer > self.detectionRange * 2 || self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732)) {
self.isCharging = false;
self.velocityX *= 0.5;
self.velocityY *= 0.5;
}
// Check collision with player
var currentIntersecting = self.intersects(player);
if (!self.lastPlayerIntersecting && currentIntersecting && !playerInvulnerable) {
// Ram into player - apply strong knockback
var pushForce = 20;
var pushDirection = player.x > self.x ? 1 : -1;
player.velocityX = pushDirection * pushForce;
player.velocityY = -8;
playerHit();
}
self.lastPlayerIntersecting = currentIntersecting;
};
return self;
});
var PinkMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('pinkMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.shootCooldown = 0;
self.maxShootCooldown = 180; // 3 seconds at 60fps
self.detectionRange = 350;
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect (pink tinted)
malwareGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.35) * 0.3;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.28) * 0.12;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.28) * 0.12;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Shoot three projectiles at player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.shootCooldown <= 0) {
self.shootCooldown = self.maxShootCooldown;
// Calculate base direction to player
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
// Create three projectiles with spread
var spreadAngles = [-0.3, 0, 0.3]; // 30 degree spread
for (var i = 0; i < spreadAngles.length; i++) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
// Apply spread to angle
var shotAngle = angleToPlayer + spreadAngles[i];
projectile.velocityX = Math.cos(shotAngle) * projectile.speed;
projectile.velocityY = Math.sin(shotAngle) * projectile.speed;
// Add to game and projectiles array
projectiles.push(projectile);
game.addChild(projectile);
}
}
// Decrease cooldown
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var Platform = Container.expand(function (type) {
var self = Container.call(this);
var assetType = type || 'platform';
var platformGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 8;
self.jumpPower = -18;
self.gravity = 0.8;
self.onGround = false;
self.canJump = true;
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
// Apply velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Friction
self.velocityX *= 0.85;
// Keep player in bounds
if (self.x < 20) self.x = 20;
if (self.x > 2028) self.x = 2028;
// Reset ground state
self.onGround = false;
// Check platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform)) {
if (self.velocityY > 0 && self.y - 30 < platform.y) {
self.y = platform.y;
self.velocityY = 0;
self.onGround = true;
self.canJump = true;
}
}
}
// Fall limit
if (self.y > 2800) {
self.x = playerStartX;
self.y = playerStartY;
self.velocityX = 0;
self.velocityY = 0;
}
};
self.jump = function () {
if (self.canJump && self.onGround) {
self.velocityY = self.jumpPower;
self.onGround = false;
self.canJump = false;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
self.velocityX = -self.speed;
};
self.moveRight = function () {
self.velocityX = self.speed;
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 6;
self.lastPlayerIntersecting = false;
self.update = function () {
// Move projectile
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with player
var currentIntersecting = self.intersects(player);
if (!self.lastPlayerIntersecting && currentIntersecting && !playerInvulnerable) {
// Strong knockback to shoot player off platform
var pushForce = 25;
var pushDirection = player.x > self.x ? 1 : -1;
player.velocityX = pushDirection * pushForce;
player.velocityY = -12;
playerHit();
// Remove projectile after hit
self.destroy();
}
self.lastPlayerIntersecting = currentIntersecting;
// Remove projectile if it goes off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
}
};
return self;
});
var PurpleMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('purpleMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.detectionRange = 350;
self.slowCooldown = 0;
self.maxSlowCooldown = 180; // 3 seconds at 60fps
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect (purple tinted)
malwareGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.4) * 0.4;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Slow player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.slowCooldown <= 0) {
self.slowCooldown = self.maxSlowCooldown;
// Apply slow effect to player using tween
tween(player, {
speed: 2
}, {
duration: 2000,
onFinish: function onFinish() {
// Restore normal speed
player.speed = 8;
}
});
// Visual feedback - purple tint on player
tween(player, {
tint: 0x8a2be2
}, {
duration: 100,
onFinish: function onFinish() {
tween(player, {
tint: 0xffffff
}, {
duration: 100
});
}
});
}
// Decrease cooldown
if (self.slowCooldown > 0) {
self.slowCooldown--;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game variables
var player;
var platforms = [];
var dataPackets = [];
var electricSparks = [];
var malwareEnemies = [];
var greenMalwareEnemies = [];
var blueMalwareEnemies = [];
var purpleMalwareEnemies = [];
var pinkMalwareEnemies = [];
var projectiles = [];
var playerStartX = 100;
var playerStartY = 2400;
var playerInvulnerable = false;
var leftPressed = false;
var rightPressed = false;
var touchStartX = 0;
var isTouching = false;
// Add background
var bg = game.attachAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Create UI
var scoreText = new Text2('Data: 0', {
size: 60,
fill: '#00ffff'
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 120;
var instructionText = new Text2('Tap left/right to move, tap anywhere to jump', {
size: 40,
fill: '#ffffff'
});
instructionText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionText);
instructionText.y = -50;
// Create player
player = game.addChild(new Player());
player.x = playerStartX;
player.y = playerStartY;
// Create level platforms (motherboard circuit layout)
createLevel();
// Game event handlers
game.down = function (x, y, obj) {
isTouching = true;
touchStartX = x;
// Jump on tap
player.jump();
};
game.up = function (x, y, obj) {
isTouching = false;
leftPressed = false;
rightPressed = false;
};
game.move = function (x, y, obj) {
if (isTouching) {
var deltaX = x - touchStartX;
if (deltaX < -50 && !leftPressed) {
leftPressed = true;
rightPressed = false;
} else if (deltaX > 50 && !rightPressed) {
rightPressed = true;
leftPressed = false;
}
}
};
// Player hit function
function playerHit() {
playerInvulnerable = true;
LK.getSound('electric').play();
// Flash player red
tween(player, {
alpha: 0.3
}, {
duration: 100
});
tween(player, {
alpha: 1
}, {
duration: 100
});
// Knockback
player.velocityX = player.x < 1024 ? 15 : -15;
player.velocityY = -10;
LK.setTimeout(function () {
playerInvulnerable = false;
}, 1000);
}
// Level creation function
function createLevel() {
// Main platform path (motherboard traces)
var platformPositions = [{
x: 200,
y: 2500,
type: 'platform'
}, {
x: 500,
y: 2400,
type: 'circuit'
}, {
x: 800,
y: 2300,
type: 'platform'
}, {
x: 1100,
y: 2200,
type: 'circuit'
}, {
x: 1400,
y: 2100,
type: 'platform'
}, {
x: 1700,
y: 2000,
type: 'circuit'
}, {
x: 1400,
y: 1900,
type: 'platform'
}, {
x: 1100,
y: 1800,
type: 'circuit'
}, {
x: 800,
y: 1700,
type: 'platform'
}, {
x: 500,
y: 1600,
type: 'circuit'
}, {
x: 200,
y: 1500,
type: 'platform'
}, {
x: 500,
y: 1400,
type: 'platform'
}, {
x: 800,
y: 1300,
type: 'circuit'
}, {
x: 1100,
y: 1200,
type: 'platform'
}, {
x: 1400,
y: 1100,
type: 'circuit'
}, {
x: 1700,
y: 1000,
type: 'platform'
}];
// Create platforms
for (var i = 0; i < platformPositions.length; i++) {
var pos = platformPositions[i];
var platform = new Platform(pos.type);
platform.x = pos.x;
platform.y = pos.y;
platforms.push(platform);
game.addChild(platform);
}
// Create data packets
var packetPositions = [{
x: 500,
y: 2350
}, {
x: 1100,
y: 2150
}, {
x: 1700,
y: 1950
}, {
x: 800,
y: 1650
}, {
x: 200,
y: 1450
}, {
x: 800,
y: 1250
}, {
x: 1400,
y: 1050
}, {
x: 1700,
y: 950
}];
for (var j = 0; j < packetPositions.length; j++) {
var packetPos = packetPositions[j];
var packet = new DataPacket();
packet.x = packetPos.x;
packet.y = packetPos.y;
dataPackets.push(packet);
game.addChild(packet);
}
// Create electric sparks (hazards)
var sparkPositions = [{
x: 650,
y: 2350
}, {
x: 950,
y: 2250
}, {
x: 1250,
y: 2150
}, {
x: 1550,
y: 2050
}, {
x: 950,
y: 1750
}, {
x: 650,
y: 1550
}, {
x: 950,
y: 1350
}];
for (var k = 0; k < sparkPositions.length; k++) {
var sparkPos = sparkPositions[k];
var spark = new ElectricSpark();
spark.x = sparkPos.x;
spark.y = sparkPos.y;
spark.startX = spark.x;
electricSparks.push(spark);
game.addChild(spark);
}
// Create malware enemies
var malwarePositions = [{
x: 350,
y: 2450
}, {
x: 650,
y: 2200
}, {
x: 1250,
y: 1950
}, {
x: 650,
y: 1750
}, {
x: 350,
y: 1450
}, {
x: 950,
y: 1150
}];
for (var m = 0; m < malwarePositions.length; m++) {
var malwarePos = malwarePositions[m];
var malware = new Malware();
malware.x = malwarePos.x;
malware.y = malwarePos.y;
malwareEnemies.push(malware);
game.addChild(malware);
}
// Create green malware enemies (shooters)
var greenMalwarePositions = [{
x: 750,
y: 2300
}, {
x: 1550,
y: 2100
}, {
x: 350,
y: 1800
}, {
x: 1250,
y: 1600
}, {
x: 650,
y: 1400
}, {
x: 1550,
y: 1100
}];
for (var n = 0; n < greenMalwarePositions.length; n++) {
var greenMalwarePos = greenMalwarePositions[n];
var greenMalware = new GreenMalware();
greenMalware.x = greenMalwarePos.x;
greenMalware.y = greenMalwarePos.y;
greenMalwareEnemies.push(greenMalware);
game.addChild(greenMalware);
}
// Create blue malware enemies (both ram and shoot)
var blueMalwarePositions = [{
x: 400,
y: 2350
}, {
x: 1000,
y: 2150
}, {
x: 1600,
y: 1850
}, {
x: 450,
y: 1650
}, {
x: 1150,
y: 1250
}];
for (var p = 0; p < blueMalwarePositions.length; p++) {
var blueMalwarePos = blueMalwarePositions[p];
var blueMalware = new BlueMalware();
blueMalware.x = blueMalwarePos.x;
blueMalware.y = blueMalwarePos.y;
blueMalwareEnemies.push(blueMalware);
game.addChild(blueMalware);
}
// Create purple malware enemies (slowers)
var purpleMalwarePositions = [{
x: 600,
y: 2400
}, {
x: 1300,
y: 2000
}, {
x: 700,
y: 1700
}, {
x: 1000,
y: 1400
}, {
x: 500,
y: 1200
}];
for (var q = 0; q < purpleMalwarePositions.length; q++) {
var purpleMalwarePos = purpleMalwarePositions[q];
var purpleMalware = new PurpleMalware();
purpleMalware.x = purpleMalwarePos.x;
purpleMalware.y = purpleMalwarePos.y;
purpleMalwareEnemies.push(purpleMalware);
game.addChild(purpleMalware);
}
// Create pink malware enemies (triple shooters)
var pinkMalwarePositions = [{
x: 850,
y: 2450
}, {
x: 1200,
y: 2250
}, {
x: 550,
y: 1950
}, {
x: 1450,
y: 1750
}, {
x: 750,
y: 1550
}, {
x: 1100,
y: 1350
}];
for (var r = 0; r < pinkMalwarePositions.length; r++) {
var pinkMalwarePos = pinkMalwarePositions[r];
var pinkMalware = new PinkMalware();
pinkMalware.x = pinkMalwarePos.x;
pinkMalware.y = pinkMalwarePos.y;
pinkMalwareEnemies.push(pinkMalware);
game.addChild(pinkMalware);
}
}
// Main game loop
game.update = function () {
// Handle movement input
if (leftPressed && !rightPressed) {
player.moveLeft();
} else if (rightPressed && !leftPressed) {
player.moveRight();
}
// Check data packet collection
for (var i = dataPackets.length - 1; i >= 0; i--) {
var packet = dataPackets[i];
if (player.intersects(packet) && !packet.collected) {
packet.collect();
dataPackets.splice(i, 1);
}
}
// Clean up destroyed projectiles
for (var j = projectiles.length - 1; j >= 0; j--) {
var projectile = projectiles[j];
if (!projectile.parent) {
projectiles.splice(j, 1);
}
}
// Check win condition
if (dataPackets.length === 0 && LK.getScore() >= 80) {
LK.showYouWin();
}
// Camera follow (simple vertical follow)
if (player.y < 1500) {
var targetY = Math.max(0, 1366 - player.y);
game.y += (targetY - game.y) * 0.05;
}
};
// Start background music
LK.playMusic('bgmusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BlueMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('blueMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 4;
self.chargeSpeed = 8;
self.detectionRange = 400;
self.isCharging = false;
self.shootCooldown = 0;
self.maxShootCooldown = 150; // 2.5 seconds at 60fps
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect (blue tinted)
malwareGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.3) * 0.3;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.25) * 0.15;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.25) * 0.15;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Shooting behavior - shoot at player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.shootCooldown <= 0) {
self.shootCooldown = self.maxShootCooldown;
// Create projectile
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
// Calculate direction to player
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
projectile.velocityX = Math.cos(angleToPlayer) * projectile.speed;
projectile.velocityY = Math.sin(angleToPlayer) * projectile.speed;
// Add to game and projectiles array
projectiles.push(projectile);
game.addChild(projectile);
}
// Ramming behavior - detect player and start charging
if (distanceToPlayer < self.detectionRange && !self.isCharging) {
self.isCharging = true;
// Calculate charge direction
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
self.velocityX = Math.cos(angleToPlayer) * self.chargeSpeed;
self.velocityY = Math.sin(angleToPlayer) * self.chargeSpeed;
}
// Move malware
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction when not charging
if (!self.isCharging) {
self.velocityX *= 0.95;
self.velocityY *= 0.95;
}
// Stop charging if too far from original position or hit boundaries
if (self.isCharging && (distanceToPlayer > self.detectionRange * 2 || self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732)) {
self.isCharging = false;
self.velocityX *= 0.5;
self.velocityY *= 0.5;
}
// Check collision with player
var currentIntersecting = self.intersects(player);
if (!self.lastPlayerIntersecting && currentIntersecting && !playerInvulnerable) {
// Ram into player - apply strong knockback
var pushForce = 22;
var pushDirection = player.x > self.x ? 1 : -1;
player.velocityX = pushDirection * pushForce;
player.velocityY = -10;
playerHit();
}
self.lastPlayerIntersecting = currentIntersecting;
// Decrease shoot cooldown
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var DataPacket = Container.expand(function () {
var self = Container.call(this);
var packetGraphics = self.attachAsset('dataPacket', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.rotationSpeed = 0.05;
self.update = function () {
packetGraphics.rotation += self.rotationSpeed;
// Floating animation
self.y += Math.sin(LK.ticks * 0.1) * 0.5;
};
self.collect = function () {
if (!self.collected) {
self.collected = true;
LK.setScore(LK.getScore() + 10);
scoreText.setText('Data: ' + LK.getScore());
LK.getSound('collect').play();
// Tween out
tween(self, {
alpha: 0,
scaleX: 2,
scaleY: 2
}, {
duration: 300,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var ElectricSpark = Container.expand(function () {
var self = Container.call(this);
var sparkGraphics = self.attachAsset('electricSpark', {
anchorX: 0.5,
anchorY: 0.5
});
self.moveDirection = 1;
self.moveSpeed = 3;
self.moveRange = 150;
self.startX = 0;
self.update = function () {
// Flash effect
sparkGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.3) * 0.5;
// Move back and forth
self.x += self.moveSpeed * self.moveDirection;
if (Math.abs(self.x - self.startX) > self.moveRange) {
self.moveDirection *= -1;
}
// Check player collision
if (self.intersects(player) && !playerInvulnerable) {
playerHit();
}
};
return self;
});
var GreenMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('greenMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.shootCooldown = 0;
self.maxShootCooldown = 120; // 2 seconds at 60fps
self.detectionRange = 300;
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect
malwareGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.25) * 0.3;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.1;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.2) * 0.1;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Shoot at player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.shootCooldown <= 0) {
self.shootCooldown = self.maxShootCooldown;
// Create projectile
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
// Calculate direction to player
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
projectile.velocityX = Math.cos(angleToPlayer) * projectile.speed;
projectile.velocityY = Math.sin(angleToPlayer) * projectile.speed;
// Add to game and projectiles array
projectiles.push(projectile);
game.addChild(projectile);
}
// Decrease cooldown
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var Malware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('electricSpark', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 4;
self.chargeSpeed = 8;
self.detectionRange = 400;
self.isCharging = false;
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect
malwareGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.2) * 0.4;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.15) * 0.2;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.15) * 0.2;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Detect player and start charging
if (distanceToPlayer < self.detectionRange && !self.isCharging) {
self.isCharging = true;
// Calculate charge direction
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
self.velocityX = Math.cos(angleToPlayer) * self.chargeSpeed;
self.velocityY = Math.sin(angleToPlayer) * self.chargeSpeed;
}
// Move malware
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction when not charging
if (!self.isCharging) {
self.velocityX *= 0.95;
self.velocityY *= 0.95;
}
// Stop charging if too far from original position or hit boundaries
if (self.isCharging && (distanceToPlayer > self.detectionRange * 2 || self.x < 0 || self.x > 2048 || self.y < 0 || self.y > 2732)) {
self.isCharging = false;
self.velocityX *= 0.5;
self.velocityY *= 0.5;
}
// Check collision with player
var currentIntersecting = self.intersects(player);
if (!self.lastPlayerIntersecting && currentIntersecting && !playerInvulnerable) {
// Ram into player - apply strong knockback
var pushForce = 20;
var pushDirection = player.x > self.x ? 1 : -1;
player.velocityX = pushDirection * pushForce;
player.velocityY = -8;
playerHit();
}
self.lastPlayerIntersecting = currentIntersecting;
};
return self;
});
var PinkMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('pinkMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.shootCooldown = 0;
self.maxShootCooldown = 180; // 3 seconds at 60fps
self.detectionRange = 350;
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect (pink tinted)
malwareGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.35) * 0.3;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.28) * 0.12;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.28) * 0.12;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Shoot three projectiles at player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.shootCooldown <= 0) {
self.shootCooldown = self.maxShootCooldown;
// Calculate base direction to player
var angleToPlayer = Math.atan2(player.y - self.y, player.x - self.x);
// Create three projectiles with spread
var spreadAngles = [-0.3, 0, 0.3]; // 30 degree spread
for (var i = 0; i < spreadAngles.length; i++) {
var projectile = new Projectile();
projectile.x = self.x;
projectile.y = self.y;
// Apply spread to angle
var shotAngle = angleToPlayer + spreadAngles[i];
projectile.velocityX = Math.cos(shotAngle) * projectile.speed;
projectile.velocityY = Math.sin(shotAngle) * projectile.speed;
// Add to game and projectiles array
projectiles.push(projectile);
game.addChild(projectile);
}
}
// Decrease cooldown
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
return self;
});
var Platform = Container.expand(function (type) {
var self = Container.call(this);
var assetType = type || 'platform';
var platformGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 8;
self.jumpPower = -18;
self.gravity = 0.8;
self.onGround = false;
self.canJump = true;
self.update = function () {
// Apply gravity
self.velocityY += self.gravity;
// Apply velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Friction
self.velocityX *= 0.85;
// Keep player in bounds
if (self.x < 20) self.x = 20;
if (self.x > 2028) self.x = 2028;
// Reset ground state
self.onGround = false;
// Check platform collisions
for (var i = 0; i < platforms.length; i++) {
var platform = platforms[i];
if (self.intersects(platform)) {
if (self.velocityY > 0 && self.y - 30 < platform.y) {
self.y = platform.y;
self.velocityY = 0;
self.onGround = true;
self.canJump = true;
}
}
}
// Fall limit
if (self.y > 2800) {
self.x = playerStartX;
self.y = playerStartY;
self.velocityX = 0;
self.velocityY = 0;
}
};
self.jump = function () {
if (self.canJump && self.onGround) {
self.velocityY = self.jumpPower;
self.onGround = false;
self.canJump = false;
LK.getSound('jump').play();
}
};
self.moveLeft = function () {
self.velocityX = -self.speed;
};
self.moveRight = function () {
self.velocityX = self.speed;
};
return self;
});
var Projectile = Container.expand(function () {
var self = Container.call(this);
var projectileGraphics = self.attachAsset('projectile', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 6;
self.lastPlayerIntersecting = false;
self.update = function () {
// Move projectile
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with player
var currentIntersecting = self.intersects(player);
if (!self.lastPlayerIntersecting && currentIntersecting && !playerInvulnerable) {
// Strong knockback to shoot player off platform
var pushForce = 25;
var pushDirection = player.x > self.x ? 1 : -1;
player.velocityX = pushDirection * pushForce;
player.velocityY = -12;
playerHit();
// Remove projectile after hit
self.destroy();
}
self.lastPlayerIntersecting = currentIntersecting;
// Remove projectile if it goes off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
self.destroy();
}
};
return self;
});
var PurpleMalware = Container.expand(function () {
var self = Container.call(this);
var malwareGraphics = self.attachAsset('purpleMalware', {
anchorX: 0.5,
anchorY: 0.5
});
self.detectionRange = 350;
self.slowCooldown = 0;
self.maxSlowCooldown = 180; // 3 seconds at 60fps
self.lastPlayerIntersecting = false;
self.update = function () {
// Pulsing visual effect (purple tinted)
malwareGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.4) * 0.4;
malwareGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
malwareGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.3) * 0.2;
// Calculate distance to player
var distanceToPlayer = Math.sqrt(Math.pow(player.x - self.x, 2) + Math.pow(player.y - self.y, 2));
// Slow player if in range and cooldown is ready
if (distanceToPlayer < self.detectionRange && self.slowCooldown <= 0) {
self.slowCooldown = self.maxSlowCooldown;
// Apply slow effect to player using tween
tween(player, {
speed: 2
}, {
duration: 2000,
onFinish: function onFinish() {
// Restore normal speed
player.speed = 8;
}
});
// Visual feedback - purple tint on player
tween(player, {
tint: 0x8a2be2
}, {
duration: 100,
onFinish: function onFinish() {
tween(player, {
tint: 0xffffff
}, {
duration: 100
});
}
});
}
// Decrease cooldown
if (self.slowCooldown > 0) {
self.slowCooldown--;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
// Game variables
var player;
var platforms = [];
var dataPackets = [];
var electricSparks = [];
var malwareEnemies = [];
var greenMalwareEnemies = [];
var blueMalwareEnemies = [];
var purpleMalwareEnemies = [];
var pinkMalwareEnemies = [];
var projectiles = [];
var playerStartX = 100;
var playerStartY = 2400;
var playerInvulnerable = false;
var leftPressed = false;
var rightPressed = false;
var touchStartX = 0;
var isTouching = false;
// Add background
var bg = game.attachAsset('background', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
// Create UI
var scoreText = new Text2('Data: 0', {
size: 60,
fill: '#00ffff'
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 120;
var instructionText = new Text2('Tap left/right to move, tap anywhere to jump', {
size: 40,
fill: '#ffffff'
});
instructionText.anchor.set(0.5, 1);
LK.gui.bottom.addChild(instructionText);
instructionText.y = -50;
// Create player
player = game.addChild(new Player());
player.x = playerStartX;
player.y = playerStartY;
// Create level platforms (motherboard circuit layout)
createLevel();
// Game event handlers
game.down = function (x, y, obj) {
isTouching = true;
touchStartX = x;
// Jump on tap
player.jump();
};
game.up = function (x, y, obj) {
isTouching = false;
leftPressed = false;
rightPressed = false;
};
game.move = function (x, y, obj) {
if (isTouching) {
var deltaX = x - touchStartX;
if (deltaX < -50 && !leftPressed) {
leftPressed = true;
rightPressed = false;
} else if (deltaX > 50 && !rightPressed) {
rightPressed = true;
leftPressed = false;
}
}
};
// Player hit function
function playerHit() {
playerInvulnerable = true;
LK.getSound('electric').play();
// Flash player red
tween(player, {
alpha: 0.3
}, {
duration: 100
});
tween(player, {
alpha: 1
}, {
duration: 100
});
// Knockback
player.velocityX = player.x < 1024 ? 15 : -15;
player.velocityY = -10;
LK.setTimeout(function () {
playerInvulnerable = false;
}, 1000);
}
// Level creation function
function createLevel() {
// Main platform path (motherboard traces)
var platformPositions = [{
x: 200,
y: 2500,
type: 'platform'
}, {
x: 500,
y: 2400,
type: 'circuit'
}, {
x: 800,
y: 2300,
type: 'platform'
}, {
x: 1100,
y: 2200,
type: 'circuit'
}, {
x: 1400,
y: 2100,
type: 'platform'
}, {
x: 1700,
y: 2000,
type: 'circuit'
}, {
x: 1400,
y: 1900,
type: 'platform'
}, {
x: 1100,
y: 1800,
type: 'circuit'
}, {
x: 800,
y: 1700,
type: 'platform'
}, {
x: 500,
y: 1600,
type: 'circuit'
}, {
x: 200,
y: 1500,
type: 'platform'
}, {
x: 500,
y: 1400,
type: 'platform'
}, {
x: 800,
y: 1300,
type: 'circuit'
}, {
x: 1100,
y: 1200,
type: 'platform'
}, {
x: 1400,
y: 1100,
type: 'circuit'
}, {
x: 1700,
y: 1000,
type: 'platform'
}];
// Create platforms
for (var i = 0; i < platformPositions.length; i++) {
var pos = platformPositions[i];
var platform = new Platform(pos.type);
platform.x = pos.x;
platform.y = pos.y;
platforms.push(platform);
game.addChild(platform);
}
// Create data packets
var packetPositions = [{
x: 500,
y: 2350
}, {
x: 1100,
y: 2150
}, {
x: 1700,
y: 1950
}, {
x: 800,
y: 1650
}, {
x: 200,
y: 1450
}, {
x: 800,
y: 1250
}, {
x: 1400,
y: 1050
}, {
x: 1700,
y: 950
}];
for (var j = 0; j < packetPositions.length; j++) {
var packetPos = packetPositions[j];
var packet = new DataPacket();
packet.x = packetPos.x;
packet.y = packetPos.y;
dataPackets.push(packet);
game.addChild(packet);
}
// Create electric sparks (hazards)
var sparkPositions = [{
x: 650,
y: 2350
}, {
x: 950,
y: 2250
}, {
x: 1250,
y: 2150
}, {
x: 1550,
y: 2050
}, {
x: 950,
y: 1750
}, {
x: 650,
y: 1550
}, {
x: 950,
y: 1350
}];
for (var k = 0; k < sparkPositions.length; k++) {
var sparkPos = sparkPositions[k];
var spark = new ElectricSpark();
spark.x = sparkPos.x;
spark.y = sparkPos.y;
spark.startX = spark.x;
electricSparks.push(spark);
game.addChild(spark);
}
// Create malware enemies
var malwarePositions = [{
x: 350,
y: 2450
}, {
x: 650,
y: 2200
}, {
x: 1250,
y: 1950
}, {
x: 650,
y: 1750
}, {
x: 350,
y: 1450
}, {
x: 950,
y: 1150
}];
for (var m = 0; m < malwarePositions.length; m++) {
var malwarePos = malwarePositions[m];
var malware = new Malware();
malware.x = malwarePos.x;
malware.y = malwarePos.y;
malwareEnemies.push(malware);
game.addChild(malware);
}
// Create green malware enemies (shooters)
var greenMalwarePositions = [{
x: 750,
y: 2300
}, {
x: 1550,
y: 2100
}, {
x: 350,
y: 1800
}, {
x: 1250,
y: 1600
}, {
x: 650,
y: 1400
}, {
x: 1550,
y: 1100
}];
for (var n = 0; n < greenMalwarePositions.length; n++) {
var greenMalwarePos = greenMalwarePositions[n];
var greenMalware = new GreenMalware();
greenMalware.x = greenMalwarePos.x;
greenMalware.y = greenMalwarePos.y;
greenMalwareEnemies.push(greenMalware);
game.addChild(greenMalware);
}
// Create blue malware enemies (both ram and shoot)
var blueMalwarePositions = [{
x: 400,
y: 2350
}, {
x: 1000,
y: 2150
}, {
x: 1600,
y: 1850
}, {
x: 450,
y: 1650
}, {
x: 1150,
y: 1250
}];
for (var p = 0; p < blueMalwarePositions.length; p++) {
var blueMalwarePos = blueMalwarePositions[p];
var blueMalware = new BlueMalware();
blueMalware.x = blueMalwarePos.x;
blueMalware.y = blueMalwarePos.y;
blueMalwareEnemies.push(blueMalware);
game.addChild(blueMalware);
}
// Create purple malware enemies (slowers)
var purpleMalwarePositions = [{
x: 600,
y: 2400
}, {
x: 1300,
y: 2000
}, {
x: 700,
y: 1700
}, {
x: 1000,
y: 1400
}, {
x: 500,
y: 1200
}];
for (var q = 0; q < purpleMalwarePositions.length; q++) {
var purpleMalwarePos = purpleMalwarePositions[q];
var purpleMalware = new PurpleMalware();
purpleMalware.x = purpleMalwarePos.x;
purpleMalware.y = purpleMalwarePos.y;
purpleMalwareEnemies.push(purpleMalware);
game.addChild(purpleMalware);
}
// Create pink malware enemies (triple shooters)
var pinkMalwarePositions = [{
x: 850,
y: 2450
}, {
x: 1200,
y: 2250
}, {
x: 550,
y: 1950
}, {
x: 1450,
y: 1750
}, {
x: 750,
y: 1550
}, {
x: 1100,
y: 1350
}];
for (var r = 0; r < pinkMalwarePositions.length; r++) {
var pinkMalwarePos = pinkMalwarePositions[r];
var pinkMalware = new PinkMalware();
pinkMalware.x = pinkMalwarePos.x;
pinkMalware.y = pinkMalwarePos.y;
pinkMalwareEnemies.push(pinkMalware);
game.addChild(pinkMalware);
}
}
// Main game loop
game.update = function () {
// Handle movement input
if (leftPressed && !rightPressed) {
player.moveLeft();
} else if (rightPressed && !leftPressed) {
player.moveRight();
}
// Check data packet collection
for (var i = dataPackets.length - 1; i >= 0; i--) {
var packet = dataPackets[i];
if (player.intersects(packet) && !packet.collected) {
packet.collect();
dataPackets.splice(i, 1);
}
}
// Clean up destroyed projectiles
for (var j = projectiles.length - 1; j >= 0; j--) {
var projectile = projectiles[j];
if (!projectile.parent) {
projectiles.splice(j, 1);
}
}
// Check win condition
if (dataPackets.length === 0 && LK.getScore() >= 80) {
LK.showYouWin();
}
// Camera follow (simple vertical follow)
if (player.y < 1500) {
var targetY = Math.max(0, 1366 - player.y);
game.y += (targetY - game.y) * 0.05;
}
};
// Start background music
LK.playMusic('bgmusic');