/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('collectible', {
anchorX: 0.5,
anchorY: 0.5
});
// Random bubble size
var size = 0.3 + Math.random() * 0.7;
bubbleGraphics.scaleX = size;
bubbleGraphics.scaleY = size;
// Random bubble speed
self.speed = 1 + Math.random() * 2;
// Side drift
self.drift = (Math.random() - 0.5) * 0.5;
self.update = function () {
// Move upward
self.y -= self.speed;
// Add slight horizontal drift
self.x += self.drift;
// Remove if off screen
if (self.y < -50) {
var bubbleIndex = bubbles.indexOf(self);
if (bubbleIndex !== -1) {
bubbles.splice(bubbleIndex, 1);
}
self.destroy();
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = 0;
self.targetY = 0;
self.lastIntersecting = false;
self.returningToSpawn = false;
self.update = function () {
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// When reached target, destroy bullet instead of returning
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
}
// Check intersection with central monster
var currentIntersecting = self.intersects(centralMonster);
if (!self.lastIntersecting && currentIntersecting) {
// Hit the monster
monsterHits++;
centralMonster.grow();
// Award 100 points for each hit on the monster
playerScore += 100;
scoreText.setText('Score: ' + playerScore);
// Play monster hit sound
LK.getSound('monsterhit').play();
// Check if monster should explode after 10 hits
if (monsterHits >= hitsToWin) {
centralMonster.explode();
}
// Remove from bullets array
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
}
self.lastIntersecting = currentIntersecting;
// Check intersection with enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (self.intersects(enemy)) {
// Hit an enemy - destroy both bullet and enemy
// Award 50 points for killing fish
playerScore += 50;
scoreText.setText('Score: ' + playerScore);
// Play monster hit sound
LK.getSound('monsterhit').play();
enemy.destroy();
enemies.splice(i, 1);
// Remove bullet from bullets array
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
break; // Exit loop since bullet is destroyed
}
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
// Remove from bullets array
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
}
};
return self;
});
var CentralMonster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('centralMonster', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
self.spawnTimer = 0;
self.spawnInterval = 120; // Spawn every 2 seconds at 60fps
self.armPositions = [{
x: -250,
y: -200
},
// Top left arm
{
x: 250,
y: -200
},
// Top right arm
{
x: -300,
y: 0
},
// Left arm
{
x: 300,
y: 0
},
// Right arm
{
x: -250,
y: 200
},
// Bottom left arm
{
x: 250,
y: 200
} // Bottom right arm
];
self.startMovement = function () {
// Create continuous floating movement
self.animateMovement();
};
self.animateMovement = function () {
// Escape from Pacman - move away from him
var dx = self.x - pacman.x;
var dy = self.y - pacman.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If too close to Pacman, move away
if (distance < 400) {
// Normalize direction and move away
dx = dx / distance;
dy = dy / distance;
} else {
// Random movement when far enough
dx = (Math.random() - 0.5) * 2;
dy = (Math.random() - 0.5) * 2;
}
// Calculate new position (escape direction)
var newX = self.x + dx * (200 + Math.random() * 200);
var newY = self.y + dy * (200 + Math.random() * 200);
// Keep within screen bounds
newX = Math.max(200, Math.min(1848, newX));
newY = Math.max(200, Math.min(2532, newY));
tween(self, {
x: newX,
y: newY
}, {
duration: 1500 + Math.random() * 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.animateMovement(); // Continue movement
}
});
// Add rotation animation
tween(self, {
rotation: self.rotation + (Math.random() - 0.5) * 0.5
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeInOut
});
};
self.update = function () {
self.spawnTimer++;
// Spawn enemies from arms
if (self.spawnTimer >= self.spawnInterval) {
self.spawnTimer = 0;
self.spawnEnemy();
}
};
self.spawnEnemy = function () {
// Pick random arm position
var armIndex = Math.floor(Math.random() * self.armPositions.length);
var armPos = self.armPositions[armIndex];
// Create enemy at arm position (relative to monster)
var enemy = new Enemy();
enemy.x = self.x + armPos.x;
enemy.y = self.y + armPos.y;
// Store spawn position for reference
enemy.spawnX = enemy.x;
enemy.spawnY = enemy.y;
// Use level-specific follow chance
enemy.shouldFollowPlayer = Math.random() < currentLevelFollowChance;
// Set level-specific enemy speed
enemy.speed = currentLevelEnemySpeed;
// Enemy will follow Pacman automatically in its update method
enemies.push(enemy);
game.addChild(enemy);
// Add spawn effect
enemy.alpha = 0;
tween(enemy, {
alpha: 1,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 500,
easing: tween.easeOut
});
};
self.grow = function () {
// Calculate scaling factor that decreases with each hit
// Start with 0.1 scale increment and reduce by 0.002 per hit
var scaleIncrement = Math.max(0.01, 0.1 - monsterHits * 0.002);
var newScale = monsterGraphics.scaleX + scaleIncrement;
tween(monsterGraphics, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 300,
easing: tween.easeOut
});
// Flash effect when hit
tween(monsterGraphics, {
tint: 0xff0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 100
});
}
});
};
self.explode = function () {
// Stop all movement
tween.stop(self);
// Check if player is close enough to be killed by explosion
var dx = pacman.x - self.x;
var dy = pacman.y - self.y;
var explosionDistance = Math.sqrt(dx * dx + dy * dy);
var explosionRadius = 600; // Lethal explosion radius
// Kill player if within explosion radius
if (explosionDistance <= explosionRadius) {
playerLives--;
// Update lives display by hiding icons
if (livesIcons[playerLives]) {
livesIcons[playerLives].visible = false;
}
// Flash effect on hit
LK.effects.flashScreen(0xff0000, 300);
// End game when lives reach 0
if (playerLives <= 0) {
LK.showGameOver();
return;
}
}
// Destroy all enemies when monster dies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.destroy();
enemies.splice(i, 1);
}
// Create dramatic death sequence with multiple effects
// First: Rapid growth and red tint
tween(monsterGraphics, {
scaleX: monsterGraphics.scaleX * 1.8,
scaleY: monsterGraphics.scaleY * 1.8,
tint: 0xff0000
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Second: Violent shaking effect
var originalX = self.x;
var originalY = self.y;
var shakeCount = 0;
var maxShakes = 10;
function shake() {
if (shakeCount < maxShakes) {
tween(self, {
x: originalX + (Math.random() - 0.5) * 60,
y: originalY + (Math.random() - 0.5) * 60
}, {
duration: 50,
onFinish: function onFinish() {
shakeCount++;
shake();
}
});
} else {
// Third: Spin and shrink rapidly
tween(self, {
rotation: self.rotation + Math.PI * 4,
x: originalX,
y: originalY
}, {
duration: 800,
easing: tween.easeIn
});
tween(monsterGraphics, {
scaleX: 0,
scaleY: 0,
alpha: 0,
tint: 0xffffff
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
// Flash screen multiple times
LK.effects.flashScreen(0xffffff, 200);
LK.setTimeout(function () {
LK.effects.flashScreen(0xff0000, 200);
}, 250);
LK.setTimeout(function () {
LK.effects.flashScreen(0xffffff, 500);
}, 500);
// Show game won instead of resetting
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
}
});
}
}
shake();
}
});
};
return self;
});
// Create central monster
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
self.speed = 2;
self.targetX = 0;
self.targetY = 0;
self.lastX = 0;
self.lastY = 0;
self.directionChangeTimer = 0;
self.directionChangeInterval = 60 + Math.random() * 60; // Random direction changes
self.isChangingDirection = false;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Check if this enemy should follow the player
if (self.shouldFollowPlayer) {
// Follow player behavior - move towards Pacman
var dx = pacman.x - self.x;
var dy = pacman.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Move towards Pacman
var direction = Math.min(1, self.speed / distance);
self.x += dx * direction;
self.y += dy * direction;
}
} else {
// Random movement behavior
// Direction change timer
self.directionChangeTimer++;
if (self.directionChangeTimer >= self.directionChangeInterval && !self.isChangingDirection) {
self.directionChangeTimer = 0;
self.directionChangeInterval = 60 + Math.random() * 60;
self.isChangingDirection = true;
// Simple left/right movement only
var swimmingDirection = Math.random() > 0.5 ? 1 : -1; // Left or right
var swimDistance = 200 + Math.random() * 300; // Random swim distance
var tempTargetX = self.x + swimmingDirection * swimDistance;
// Keep within bounds
tempTargetX = Math.max(100, Math.min(1948, tempTargetX));
// Smooth horizontal movement only
tween(self, {
x: tempTargetX
}, {
duration: 1000 + Math.random() * 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isChangingDirection = false;
}
});
}
// Move towards Pacman horizontally only when not changing direction
if (!self.isChangingDirection) {
var dx = pacman.x - self.x;
var distance = Math.abs(dx);
if (distance > 0) {
// Move horizontally towards Pacman
var direction = dx > 0 ? 1 : -1;
self.x += direction * self.speed;
}
}
}
// Keep enemies within screen bounds instead of destroying them
if (self.x < 100) self.x = 100;
if (self.x > 1948) self.x = 1948;
if (self.y < 100) self.y = 100;
if (self.y > 2632) self.y = 2632;
};
return self;
});
var Pacman = Container.expand(function () {
var self = Container.call(this);
var pacmanGraphics = self.attachAsset('pacman', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.targetX = 0;
self.targetY = 0;
self.returningToSpawn = false;
self.update = function () {
// Move towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// When reached target, start returning to spawn after a delay
if (!self.returningToSpawn) {
self.returningToSpawn = true;
LK.setTimeout(function () {
tween(self, {
x: spawnX,
y: spawnY
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.returningToSpawn = false;
}
});
}, 1000);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0066cc
});
/****
* Game Code
****/
// Add sea background
var seaBackground = game.addChild(LK.getAsset('seaBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create Pacman character
var pacman = game.addChild(new Pacman());
pacman.x = 200;
pacman.y = 200;
// Create central monster
var centralMonster = game.addChild(new CentralMonster());
centralMonster.x = 1024;
centralMonster.y = 1366;
// Array to track enemies
var enemies = [];
// Array to track bullets
var bullets = [];
// Array to track bubbles
var bubbles = [];
// Bubble spawn timer
var bubbleSpawnTimer = 0;
// Track monster hits
var monsterHits = 0;
var hitsToWin = 50;
// Remove level tracking - make game continuous
// Player lives
var playerLives = 3;
// Player score
var playerScore = 0;
// Extra life tracking
var nextExtraLifeScore = 2500;
// Current level enemy settings
var currentLevelEnemySpeed = 2.0;
var currentLevelFollowChance = 0.5;
// Game timer removed
// Store spawn position - start from top-left corner
var spawnX = 200;
var spawnY = 200;
// Touch controls for Pacman movement and shooting
game.down = function (x, y, obj) {
pacman.targetX = x;
pacman.targetY = y;
// Calculate angle from Pacman to target and rotate Pacman
var dx = x - pacman.x;
var dy = y - pacman.y;
var angle = Math.atan2(dy, dx);
// Rotate Pacman to face the firing direction
tween(pacman, {
rotation: angle
}, {
duration: 200,
easing: tween.easeOut
});
// Create bullet towards touch position
var bullet = new Bullet();
bullet.x = pacman.x;
bullet.y = pacman.y;
bullet.targetX = x;
bullet.targetY = y;
bullets.push(bullet);
game.addChild(bullet);
// Play bubble sound effect
LK.getSound('bubble').play();
};
game.move = function (x, y, obj) {
pacman.targetX = x;
pacman.targetY = y;
};
// Game update loop
game.update = function () {
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.parent) {
// Bullet is still active
} else {
// Bullet was destroyed, remove from array
bullets.splice(i, 1);
}
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (enemy.parent) {
// Check collision with player
if (enemy.intersects(pacman)) {
// Player hit by enemy
playerLives--;
// Update lives display by hiding icons
if (livesIcons[playerLives]) {
livesIcons[playerLives].visible = false;
}
// Flash effect on hit
LK.effects.flashScreen(0xff0000, 300);
// End game when lives reach 0
if (playerLives <= 0) {
LK.showGameOver();
return;
}
// Remove enemy that hit player
enemy.destroy();
enemies.splice(j, 1);
continue;
}
} else {
// Enemy was destroyed, remove from array
enemies.splice(j, 1);
}
}
// Check collision with central monster
if (centralMonster.intersects(pacman)) {
// Player hit by central monster
playerLives--;
// Update lives display by hiding icons
if (livesIcons[playerLives]) {
livesIcons[playerLives].visible = false;
}
// Flash effect on hit
LK.effects.flashScreen(0xff0000, 300);
// End game when lives reach 0
if (playerLives <= 0) {
LK.showGameOver();
return;
}
// Push player away from monster
var dx = pacman.x - centralMonster.x;
var dy = pacman.y - centralMonster.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
pacman.x += dx / distance * 100;
pacman.y += dy / distance * 100;
}
}
// Timer system removed
// Spawn bubbles
bubbleSpawnTimer++;
if (bubbleSpawnTimer >= 15) {
// Spawn every 15 frames (4 times per second)
bubbleSpawnTimer = 0;
// Create new bubble at random position at bottom
var bubble = new Bubble();
bubble.x = Math.random() * 2048;
bubble.y = 2732 + 50; // Start below screen
bubbles.push(bubble);
game.addChild(bubble);
// Add floating animation with tween
tween(bubble, {
alpha: 0.7,
scaleX: bubble.scaleX * 1.2,
scaleY: bubble.scaleY * 1.2
}, {
duration: 2000 + Math.random() * 3000,
easing: tween.easeInOut
});
}
// Check for extra life at 2500 points
if (playerScore >= nextExtraLifeScore) {
playerLives++;
nextExtraLifeScore += 2500; // Next extra life at 5000, 7500, etc.
// Add new life icon if we have room
if (livesIcons.length < playerLives) {
var newLifeIcon = LK.getAsset('pacman', {
anchorX: 0,
anchorY: 1,
scaleX: 0.3,
scaleY: 0.3,
x: 50 + livesIcons.length * 80,
y: -50
});
livesIcons.push(newLifeIcon);
LK.gui.bottomLeft.addChild(newLifeIcon);
}
// Make sure all current life icons are visible
for (var l = 0; l < Math.min(livesIcons.length, playerLives); l++) {
livesIcons[l].visible = true;
}
// Flash screen green for extra life
LK.effects.flashScreen(0x00ff00, 500);
}
// Update bubbles
for (var k = bubbles.length - 1; k >= 0; k--) {
var bubble = bubbles[k];
if (!bubble.parent) {
// Bubble was destroyed, remove from array
bubbles.splice(k, 1);
}
}
};
// Create lives display in bottom left corner with player image icons only
var livesIcons = [];
for (var i = 0; i < playerLives; i++) {
var livesIcon = LK.getAsset('pacman', {
anchorX: 0,
anchorY: 1,
scaleX: 0.3,
scaleY: 0.3,
x: 50 + i * 80,
y: -50
});
livesIcons.push(livesIcon);
LK.gui.bottomLeft.addChild(livesIcon);
}
// Create score display
var scoreText = new Text2('Score: ' + playerScore, {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
scoreText.x = -50;
scoreText.y = 50;
LK.gui.topRight.addChild(scoreText);
// Timer display removed
// Level display removed - continuous gameplay
// Continuous gameplay - no level progression
// Continuous gameplay - no level progression function needed
// Initialize continuous gameplay settings
currentLevelEnemySpeed = 2.0;
currentLevelFollowChance = 0.5;
centralMonster.spawnInterval = 100;
hitsToWin = 50;
// Start monster movement
centralMonster.startMovement();
// Play the uploaded diver music
LK.playMusic('diver'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bubble = Container.expand(function () {
var self = Container.call(this);
var bubbleGraphics = self.attachAsset('collectible', {
anchorX: 0.5,
anchorY: 0.5
});
// Random bubble size
var size = 0.3 + Math.random() * 0.7;
bubbleGraphics.scaleX = size;
bubbleGraphics.scaleY = size;
// Random bubble speed
self.speed = 1 + Math.random() * 2;
// Side drift
self.drift = (Math.random() - 0.5) * 0.5;
self.update = function () {
// Move upward
self.y -= self.speed;
// Add slight horizontal drift
self.x += self.drift;
// Remove if off screen
if (self.y < -50) {
var bubbleIndex = bubbles.indexOf(self);
if (bubbleIndex !== -1) {
bubbles.splice(bubbleIndex, 1);
}
self.destroy();
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = 0;
self.targetY = 0;
self.lastIntersecting = false;
self.returningToSpawn = false;
self.update = function () {
// Move towards target
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// When reached target, destroy bullet instead of returning
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
}
// Check intersection with central monster
var currentIntersecting = self.intersects(centralMonster);
if (!self.lastIntersecting && currentIntersecting) {
// Hit the monster
monsterHits++;
centralMonster.grow();
// Award 100 points for each hit on the monster
playerScore += 100;
scoreText.setText('Score: ' + playerScore);
// Play monster hit sound
LK.getSound('monsterhit').play();
// Check if monster should explode after 10 hits
if (monsterHits >= hitsToWin) {
centralMonster.explode();
}
// Remove from bullets array
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
}
self.lastIntersecting = currentIntersecting;
// Check intersection with enemies
for (var i = 0; i < enemies.length; i++) {
var enemy = enemies[i];
if (self.intersects(enemy)) {
// Hit an enemy - destroy both bullet and enemy
// Award 50 points for killing fish
playerScore += 50;
scoreText.setText('Score: ' + playerScore);
// Play monster hit sound
LK.getSound('monsterhit').play();
enemy.destroy();
enemies.splice(i, 1);
// Remove bullet from bullets array
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
break; // Exit loop since bullet is destroyed
}
}
// Remove if off screen
if (self.x < -50 || self.x > 2098 || self.y < -50 || self.y > 2782) {
// Remove from bullets array
var bulletIndex = bullets.indexOf(self);
if (bulletIndex !== -1) {
bullets.splice(bulletIndex, 1);
}
self.destroy();
}
};
return self;
});
var CentralMonster = Container.expand(function () {
var self = Container.call(this);
var monsterGraphics = self.attachAsset('centralMonster', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
self.spawnTimer = 0;
self.spawnInterval = 120; // Spawn every 2 seconds at 60fps
self.armPositions = [{
x: -250,
y: -200
},
// Top left arm
{
x: 250,
y: -200
},
// Top right arm
{
x: -300,
y: 0
},
// Left arm
{
x: 300,
y: 0
},
// Right arm
{
x: -250,
y: 200
},
// Bottom left arm
{
x: 250,
y: 200
} // Bottom right arm
];
self.startMovement = function () {
// Create continuous floating movement
self.animateMovement();
};
self.animateMovement = function () {
// Escape from Pacman - move away from him
var dx = self.x - pacman.x;
var dy = self.y - pacman.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If too close to Pacman, move away
if (distance < 400) {
// Normalize direction and move away
dx = dx / distance;
dy = dy / distance;
} else {
// Random movement when far enough
dx = (Math.random() - 0.5) * 2;
dy = (Math.random() - 0.5) * 2;
}
// Calculate new position (escape direction)
var newX = self.x + dx * (200 + Math.random() * 200);
var newY = self.y + dy * (200 + Math.random() * 200);
// Keep within screen bounds
newX = Math.max(200, Math.min(1848, newX));
newY = Math.max(200, Math.min(2532, newY));
tween(self, {
x: newX,
y: newY
}, {
duration: 1500 + Math.random() * 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.animateMovement(); // Continue movement
}
});
// Add rotation animation
tween(self, {
rotation: self.rotation + (Math.random() - 0.5) * 0.5
}, {
duration: 1500 + Math.random() * 1000,
easing: tween.easeInOut
});
};
self.update = function () {
self.spawnTimer++;
// Spawn enemies from arms
if (self.spawnTimer >= self.spawnInterval) {
self.spawnTimer = 0;
self.spawnEnemy();
}
};
self.spawnEnemy = function () {
// Pick random arm position
var armIndex = Math.floor(Math.random() * self.armPositions.length);
var armPos = self.armPositions[armIndex];
// Create enemy at arm position (relative to monster)
var enemy = new Enemy();
enemy.x = self.x + armPos.x;
enemy.y = self.y + armPos.y;
// Store spawn position for reference
enemy.spawnX = enemy.x;
enemy.spawnY = enemy.y;
// Use level-specific follow chance
enemy.shouldFollowPlayer = Math.random() < currentLevelFollowChance;
// Set level-specific enemy speed
enemy.speed = currentLevelEnemySpeed;
// Enemy will follow Pacman automatically in its update method
enemies.push(enemy);
game.addChild(enemy);
// Add spawn effect
enemy.alpha = 0;
tween(enemy, {
alpha: 1,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 500,
easing: tween.easeOut
});
};
self.grow = function () {
// Calculate scaling factor that decreases with each hit
// Start with 0.1 scale increment and reduce by 0.002 per hit
var scaleIncrement = Math.max(0.01, 0.1 - monsterHits * 0.002);
var newScale = monsterGraphics.scaleX + scaleIncrement;
tween(monsterGraphics, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 300,
easing: tween.easeOut
});
// Flash effect when hit
tween(monsterGraphics, {
tint: 0xff0000
}, {
duration: 100,
onFinish: function onFinish() {
tween(monsterGraphics, {
tint: 0xffffff
}, {
duration: 100
});
}
});
};
self.explode = function () {
// Stop all movement
tween.stop(self);
// Check if player is close enough to be killed by explosion
var dx = pacman.x - self.x;
var dy = pacman.y - self.y;
var explosionDistance = Math.sqrt(dx * dx + dy * dy);
var explosionRadius = 600; // Lethal explosion radius
// Kill player if within explosion radius
if (explosionDistance <= explosionRadius) {
playerLives--;
// Update lives display by hiding icons
if (livesIcons[playerLives]) {
livesIcons[playerLives].visible = false;
}
// Flash effect on hit
LK.effects.flashScreen(0xff0000, 300);
// End game when lives reach 0
if (playerLives <= 0) {
LK.showGameOver();
return;
}
}
// Destroy all enemies when monster dies
for (var i = enemies.length - 1; i >= 0; i--) {
var enemy = enemies[i];
enemy.destroy();
enemies.splice(i, 1);
}
// Create dramatic death sequence with multiple effects
// First: Rapid growth and red tint
tween(monsterGraphics, {
scaleX: monsterGraphics.scaleX * 1.8,
scaleY: monsterGraphics.scaleY * 1.8,
tint: 0xff0000
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Second: Violent shaking effect
var originalX = self.x;
var originalY = self.y;
var shakeCount = 0;
var maxShakes = 10;
function shake() {
if (shakeCount < maxShakes) {
tween(self, {
x: originalX + (Math.random() - 0.5) * 60,
y: originalY + (Math.random() - 0.5) * 60
}, {
duration: 50,
onFinish: function onFinish() {
shakeCount++;
shake();
}
});
} else {
// Third: Spin and shrink rapidly
tween(self, {
rotation: self.rotation + Math.PI * 4,
x: originalX,
y: originalY
}, {
duration: 800,
easing: tween.easeIn
});
tween(monsterGraphics, {
scaleX: 0,
scaleY: 0,
alpha: 0,
tint: 0xffffff
}, {
duration: 800,
easing: tween.easeIn,
onFinish: function onFinish() {
// Flash screen multiple times
LK.effects.flashScreen(0xffffff, 200);
LK.setTimeout(function () {
LK.effects.flashScreen(0xff0000, 200);
}, 250);
LK.setTimeout(function () {
LK.effects.flashScreen(0xffffff, 500);
}, 500);
// Show game won instead of resetting
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
}
});
}
}
shake();
}
});
};
return self;
});
// Create central monster
var Enemy = Container.expand(function () {
var self = Container.call(this);
var enemyGraphics = self.attachAsset('enemy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
self.speed = 2;
self.targetX = 0;
self.targetY = 0;
self.lastX = 0;
self.lastY = 0;
self.directionChangeTimer = 0;
self.directionChangeInterval = 60 + Math.random() * 60; // Random direction changes
self.isChangingDirection = false;
self.update = function () {
self.lastX = self.x;
self.lastY = self.y;
// Check if this enemy should follow the player
if (self.shouldFollowPlayer) {
// Follow player behavior - move towards Pacman
var dx = pacman.x - self.x;
var dy = pacman.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
// Move towards Pacman
var direction = Math.min(1, self.speed / distance);
self.x += dx * direction;
self.y += dy * direction;
}
} else {
// Random movement behavior
// Direction change timer
self.directionChangeTimer++;
if (self.directionChangeTimer >= self.directionChangeInterval && !self.isChangingDirection) {
self.directionChangeTimer = 0;
self.directionChangeInterval = 60 + Math.random() * 60;
self.isChangingDirection = true;
// Simple left/right movement only
var swimmingDirection = Math.random() > 0.5 ? 1 : -1; // Left or right
var swimDistance = 200 + Math.random() * 300; // Random swim distance
var tempTargetX = self.x + swimmingDirection * swimDistance;
// Keep within bounds
tempTargetX = Math.max(100, Math.min(1948, tempTargetX));
// Smooth horizontal movement only
tween(self, {
x: tempTargetX
}, {
duration: 1000 + Math.random() * 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isChangingDirection = false;
}
});
}
// Move towards Pacman horizontally only when not changing direction
if (!self.isChangingDirection) {
var dx = pacman.x - self.x;
var distance = Math.abs(dx);
if (distance > 0) {
// Move horizontally towards Pacman
var direction = dx > 0 ? 1 : -1;
self.x += direction * self.speed;
}
}
}
// Keep enemies within screen bounds instead of destroying them
if (self.x < 100) self.x = 100;
if (self.x > 1948) self.x = 1948;
if (self.y < 100) self.y = 100;
if (self.y > 2632) self.y = 2632;
};
return self;
});
var Pacman = Container.expand(function () {
var self = Container.call(this);
var pacmanGraphics = self.attachAsset('pacman', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.targetX = 0;
self.targetY = 0;
self.returningToSpawn = false;
self.update = function () {
// Move towards target position
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 10) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
} else {
// When reached target, start returning to spawn after a delay
if (!self.returningToSpawn) {
self.returningToSpawn = true;
LK.setTimeout(function () {
tween(self, {
x: spawnX,
y: spawnY
}, {
duration: 2000,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.returningToSpawn = false;
}
});
}, 1000);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0066cc
});
/****
* Game Code
****/
// Add sea background
var seaBackground = game.addChild(LK.getAsset('seaBackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
// Create Pacman character
var pacman = game.addChild(new Pacman());
pacman.x = 200;
pacman.y = 200;
// Create central monster
var centralMonster = game.addChild(new CentralMonster());
centralMonster.x = 1024;
centralMonster.y = 1366;
// Array to track enemies
var enemies = [];
// Array to track bullets
var bullets = [];
// Array to track bubbles
var bubbles = [];
// Bubble spawn timer
var bubbleSpawnTimer = 0;
// Track monster hits
var monsterHits = 0;
var hitsToWin = 50;
// Remove level tracking - make game continuous
// Player lives
var playerLives = 3;
// Player score
var playerScore = 0;
// Extra life tracking
var nextExtraLifeScore = 2500;
// Current level enemy settings
var currentLevelEnemySpeed = 2.0;
var currentLevelFollowChance = 0.5;
// Game timer removed
// Store spawn position - start from top-left corner
var spawnX = 200;
var spawnY = 200;
// Touch controls for Pacman movement and shooting
game.down = function (x, y, obj) {
pacman.targetX = x;
pacman.targetY = y;
// Calculate angle from Pacman to target and rotate Pacman
var dx = x - pacman.x;
var dy = y - pacman.y;
var angle = Math.atan2(dy, dx);
// Rotate Pacman to face the firing direction
tween(pacman, {
rotation: angle
}, {
duration: 200,
easing: tween.easeOut
});
// Create bullet towards touch position
var bullet = new Bullet();
bullet.x = pacman.x;
bullet.y = pacman.y;
bullet.targetX = x;
bullet.targetY = y;
bullets.push(bullet);
game.addChild(bullet);
// Play bubble sound effect
LK.getSound('bubble').play();
};
game.move = function (x, y, obj) {
pacman.targetX = x;
pacman.targetY = y;
};
// Game update loop
game.update = function () {
// Update bullets
for (var i = bullets.length - 1; i >= 0; i--) {
var bullet = bullets[i];
if (bullet.parent) {
// Bullet is still active
} else {
// Bullet was destroyed, remove from array
bullets.splice(i, 1);
}
}
// Update enemies
for (var j = enemies.length - 1; j >= 0; j--) {
var enemy = enemies[j];
if (enemy.parent) {
// Check collision with player
if (enemy.intersects(pacman)) {
// Player hit by enemy
playerLives--;
// Update lives display by hiding icons
if (livesIcons[playerLives]) {
livesIcons[playerLives].visible = false;
}
// Flash effect on hit
LK.effects.flashScreen(0xff0000, 300);
// End game when lives reach 0
if (playerLives <= 0) {
LK.showGameOver();
return;
}
// Remove enemy that hit player
enemy.destroy();
enemies.splice(j, 1);
continue;
}
} else {
// Enemy was destroyed, remove from array
enemies.splice(j, 1);
}
}
// Check collision with central monster
if (centralMonster.intersects(pacman)) {
// Player hit by central monster
playerLives--;
// Update lives display by hiding icons
if (livesIcons[playerLives]) {
livesIcons[playerLives].visible = false;
}
// Flash effect on hit
LK.effects.flashScreen(0xff0000, 300);
// End game when lives reach 0
if (playerLives <= 0) {
LK.showGameOver();
return;
}
// Push player away from monster
var dx = pacman.x - centralMonster.x;
var dy = pacman.y - centralMonster.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
pacman.x += dx / distance * 100;
pacman.y += dy / distance * 100;
}
}
// Timer system removed
// Spawn bubbles
bubbleSpawnTimer++;
if (bubbleSpawnTimer >= 15) {
// Spawn every 15 frames (4 times per second)
bubbleSpawnTimer = 0;
// Create new bubble at random position at bottom
var bubble = new Bubble();
bubble.x = Math.random() * 2048;
bubble.y = 2732 + 50; // Start below screen
bubbles.push(bubble);
game.addChild(bubble);
// Add floating animation with tween
tween(bubble, {
alpha: 0.7,
scaleX: bubble.scaleX * 1.2,
scaleY: bubble.scaleY * 1.2
}, {
duration: 2000 + Math.random() * 3000,
easing: tween.easeInOut
});
}
// Check for extra life at 2500 points
if (playerScore >= nextExtraLifeScore) {
playerLives++;
nextExtraLifeScore += 2500; // Next extra life at 5000, 7500, etc.
// Add new life icon if we have room
if (livesIcons.length < playerLives) {
var newLifeIcon = LK.getAsset('pacman', {
anchorX: 0,
anchorY: 1,
scaleX: 0.3,
scaleY: 0.3,
x: 50 + livesIcons.length * 80,
y: -50
});
livesIcons.push(newLifeIcon);
LK.gui.bottomLeft.addChild(newLifeIcon);
}
// Make sure all current life icons are visible
for (var l = 0; l < Math.min(livesIcons.length, playerLives); l++) {
livesIcons[l].visible = true;
}
// Flash screen green for extra life
LK.effects.flashScreen(0x00ff00, 500);
}
// Update bubbles
for (var k = bubbles.length - 1; k >= 0; k--) {
var bubble = bubbles[k];
if (!bubble.parent) {
// Bubble was destroyed, remove from array
bubbles.splice(k, 1);
}
}
};
// Create lives display in bottom left corner with player image icons only
var livesIcons = [];
for (var i = 0; i < playerLives; i++) {
var livesIcon = LK.getAsset('pacman', {
anchorX: 0,
anchorY: 1,
scaleX: 0.3,
scaleY: 0.3,
x: 50 + i * 80,
y: -50
});
livesIcons.push(livesIcon);
LK.gui.bottomLeft.addChild(livesIcon);
}
// Create score display
var scoreText = new Text2('Score: ' + playerScore, {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(1, 0);
scoreText.x = -50;
scoreText.y = 50;
LK.gui.topRight.addChild(scoreText);
// Timer display removed
// Level display removed - continuous gameplay
// Continuous gameplay - no level progression
// Continuous gameplay - no level progression function needed
// Initialize continuous gameplay settings
currentLevelEnemySpeed = 2.0;
currentLevelFollowChance = 0.5;
centralMonster.spawnInterval = 100;
hitsToWin = 50;
// Start monster movement
centralMonster.startMovement();
// Play the uploaded diver music
LK.playMusic('diver');