/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Cat = Container.expand(function () {
var self = Container.call(this);
var catGraphics = self.attachAsset('cat', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.baseSpeed = 6;
self.targetX = 0;
self.targetY = 0;
self.adaptationLevel = 0;
self.stuckCounter = 0;
self.lastX = 0;
self.lastY = 0;
self.jumpTimer = 0;
self.isJumping = false;
self.jumpCooldown = 300; // 5 seconds at 60fps
self.hasJumpedForObstacle = false;
self.update = function () {
// Update jump timer
self.jumpTimer++;
if (self.jumpTimer >= self.jumpCooldown) {
self.jumpTimer = 0;
}
// Check if cat is stuck
if (Math.abs(self.x - self.lastX) < 1 && Math.abs(self.y - self.lastY) < 1) {
self.stuckCounter++;
if (self.stuckCounter > 30) {
// Try alternative path when stuck
self.targetX = mouse.x + (Math.random() - 0.5) * 200;
self.targetY = mouse.y + (Math.random() - 0.5) * 200;
self.stuckCounter = 0;
}
} else {
self.stuckCounter = 0;
}
// Update cat rotation based on movement direction
var dx = self.x - self.lastX;
var dy = self.y - self.lastY;
if (Math.abs(dx) > 0.1 || Math.abs(dy) > 0.1) {
var angle = Math.atan2(dy, dx);
catGraphics.rotation = angle;
}
self.lastX = self.x;
self.lastY = self.y;
// AI pathfinding with adaptation
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Simple collision avoidance - unless jumping
var canMove = true;
var obstacleDetected = false;
if (!self.isJumping) {
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (newX > obstacle.x - obstacle.width / 2 - 60 && newX < obstacle.x + obstacle.width / 2 + 60 && newY > obstacle.y - obstacle.height / 2 - 60 && newY < obstacle.y + obstacle.height / 2 + 60) {
canMove = false;
obstacleDetected = true;
// Jump immediately when obstacle is detected, but only once
if (!self.hasJumpedForObstacle) {
self.performJump();
self.hasJumpedForObstacle = true;
}
canMove = true;
break;
}
}
// Reset jump flag when no obstacle is detected
if (!obstacleDetected) {
self.hasJumpedForObstacle = false;
}
}
if (canMove) {
self.x = newX;
self.y = newY;
}
}
};
self.performJump = function () {
if (self.isJumping) return;
self.isJumping = true;
self.jumpTimer = 0;
// Calculate jump destination - move towards mouse position over obstacles
var dx = mouse.x - self.x;
var dy = mouse.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var jumpDistance = 300; // Distance to jump
var jumpX = self.x + dx / distance * jumpDistance;
var jumpY = self.y + dy / distance * jumpDistance;
// Keep jump within bounds
jumpX = Math.max(50, Math.min(1998, jumpX));
jumpY = Math.max(50, Math.min(2682, jumpY));
// Create jump animation - scale up and add slight tint
tween(catGraphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFF99
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Scale back down after jump
tween(catGraphics, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isJumping = false;
}
});
}
});
// Actually move the cat over obstacles
tween(self, {
x: jumpX,
y: jumpY
}, {
duration: 500,
easing: tween.easeInOut
});
};
self.adaptBehavior = function () {
self.adaptationLevel++;
self.speed = self.baseSpeed + self.adaptationLevel * 0.5;
};
return self;
});
var Cheese = Container.expand(function () {
var self = Container.call(this);
var cheeseGraphics = self.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
if (!self.collected) {
cheeseGraphics.rotation += 0.1;
}
};
return self;
});
var ExitZone = Container.expand(function () {
var self = Container.call(this);
var exitGraphics = self.attachAsset('exitZone', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.update = function () {
exitGraphics.alpha = 0.4 + Math.sin(LK.ticks * 0.1) * 0.2;
};
return self;
});
var Mouse = Container.expand(function () {
var self = Container.call(this);
var mouseGraphics = self.attachAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.speedBoost = 1;
self.boostTimer = 0;
self.isStuck = false;
self.stuckInTunnel = null;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
if (self.boostTimer > 0) {
self.boostTimer--;
if (self.boostTimer === 0) {
self.speedBoost = 1;
if (!ghostMode) {
mouseGraphics.tint = 0xFFFFFF;
}
}
}
// Handle ghost mode visuals
if (ghostMode) {
mouseGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.2) * 0.3;
mouseGraphics.tint = 0x00FFFF;
} else {
mouseGraphics.alpha = 1;
if (self.boostTimer === 0) {
mouseGraphics.tint = 0xFFFFFF;
}
}
// Update mouse rotation based on movement direction
var dx = self.x - self.lastX;
var dy = self.y - self.lastY;
if (Math.abs(dx) > 0.1 || Math.abs(dy) > 0.1) {
var angle = Math.atan2(dy, dx);
mouseGraphics.rotation = angle;
}
self.lastX = self.x;
self.lastY = self.y;
};
self.applySpeedBoost = function () {
self.speedBoost = 2;
self.boostTimer = 180; // 3 seconds at 60fps
if (!ghostMode) {
mouseGraphics.tint = 0xFFFF00;
}
};
self.activateGhostMode = function () {
ghostMode = true;
ghostModeTimer = ghostModeDuration;
mouseGraphics.tint = 0x00FFFF;
mouseGraphics.alpha = 0.7;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var SpecialCheese = Container.expand(function () {
var self = Container.call(this);
var cheeseGraphics = self.attachAsset('specialCheese', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFD700
});
self.collected = false;
self.update = function () {
if (!self.collected) {
cheeseGraphics.rotation += 0.2;
// Pulse effect
cheeseGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
cheeseGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
}
};
return self;
});
var Tunnel = Container.expand(function () {
var self = Container.call(this);
var tunnelGraphics = self.attachAsset('tunnel', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F2F
});
/****
* Game Code
****/
// Add ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
var mouse;
var cat;
var obstacles = [];
var tunnels = [];
var cheeses = [];
var specialCheeses = [];
var ghostMode = false;
var ghostModeTimer = 0;
var ghostModeDuration = 300; // 5 seconds at 60fps
var exitZone;
var level = 1;
var gameStarted = false;
var escapeTimer = 0;
var maxEscapeTime = 1800; // 30 seconds at 60fps
// UI Elements
var levelTxt = new Text2('Level: 1', {
size: 80,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
var timerTxt = new Text2('Time: 30', {
size: 60,
fill: 0xFFFF00
});
timerTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(timerTxt);
var instructionTxt = new Text2('Touch to move the mouse!\nAvoid the cat and reach the green exit!', {
size: 50,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 1024;
instructionTxt.y = 1366;
game.addChild(instructionTxt);
// Create mouse
mouse = game.addChild(new Mouse());
mouse.x = 200;
mouse.y = 2500;
// Create cat
cat = game.addChild(new Cat());
cat.x = 1800;
cat.y = 2500;
cat.targetX = mouse.x;
cat.targetY = mouse.y;
// Create level
function createLevel() {
// Clear existing level elements
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
for (var i = tunnels.length - 1; i >= 0; i--) {
tunnels[i].destroy();
tunnels.splice(i, 1);
}
for (var i = cheeses.length - 1; i >= 0; i--) {
cheeses[i].destroy();
cheeses.splice(i, 1);
}
for (var i = specialCheeses.length - 1; i >= 0; i--) {
specialCheeses[i].destroy();
specialCheeses.splice(i, 1);
}
if (exitZone) {
exitZone.destroy();
}
// Create obstacles - more frequent but ensure path to exit
var numObstacles = 8 + level * 3; // Increased from 5 + level * 2
for (var i = 0; i < numObstacles; i++) {
var obstacle = game.addChild(new Obstacle());
var validPosition = false;
var attempts = 0;
// Try to find a valid position that doesn't block the path
while (!validPosition && attempts < 50) {
obstacle.x = Math.random() * 1800 + 200;
obstacle.y = Math.random() * 2000 + 400;
// Check if obstacle would be too close to mouse start position
var distToMouse = Math.sqrt((obstacle.x - 200) * (obstacle.x - 200) + (obstacle.y - 2500) * (obstacle.y - 2500));
// Check if obstacle would be too close to exit zone (if it exists)
var distToExit = exitZone ? Math.sqrt((obstacle.x - exitZone.x) * (obstacle.x - exitZone.x) + (obstacle.y - exitZone.y) * (obstacle.y - exitZone.y)) : 1000;
// Ensure minimum distance from mouse start and exit
if (distToMouse > 300 && distToExit > 250) {
validPosition = true;
}
attempts++;
}
obstacles.push(obstacle);
}
// Create tunnels (mouse can pass through, cat cannot)
var numTunnels = 3 + level;
for (var i = 0; i < numTunnels; i++) {
var tunnel = game.addChild(new Tunnel());
tunnel.x = Math.random() * 1800 + 200;
tunnel.y = Math.random() * 2000 + 400;
tunnels.push(tunnel);
}
// Create cheese power-ups
var numCheeses = 2 + Math.floor(level / 2);
for (var i = 0; i < numCheeses; i++) {
var cheese = game.addChild(new Cheese());
cheese.x = Math.random() * 1600 + 300;
cheese.y = Math.random() * 1800 + 600;
cheeses.push(cheese);
}
// Create special cheese (very rare - 20% chance per level)
if (Math.random() < 0.2) {
var specialCheese = game.addChild(new SpecialCheese());
specialCheese.x = Math.random() * 1600 + 300;
specialCheese.y = Math.random() * 1800 + 600;
specialCheeses.push(specialCheese);
}
// Create exit zone
exitZone = game.addChild(new ExitZone());
exitZone.x = Math.random() * 1000 + 500;
exitZone.y = Math.random() * 800 + 200;
// Reset positions
mouse.x = 200;
mouse.y = 2500;
cat.x = 1800;
cat.y = 2500;
// Reset mouse stuck state
mouse.isStuck = false;
mouse.stuckInTunnel = null;
// Reset timer
escapeTimer = 0;
// Update UI
levelTxt.setText('Level: ' + level);
}
// Initialize first level
createLevel();
// Game controls
var targetX = mouse.x;
var targetY = mouse.y;
var isMoving = false;
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
instructionTxt.visible = false;
}
targetX = x;
targetY = y;
isMoving = true;
};
game.move = function (x, y, obj) {
if (isMoving) {
targetX = x;
targetY = y;
}
};
game.up = function (x, y, obj) {
isMoving = false;
};
game.update = function () {
if (!gameStarted) return;
// Update ghost mode timer
if (ghostMode) {
ghostModeTimer--;
if (ghostModeTimer <= 0) {
ghostMode = false;
mouse.attachAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5
}).alpha = 1;
}
}
// Update timer
escapeTimer++;
var timeLeft = Math.max(0, Math.ceil((maxEscapeTime - escapeTimer) / 60));
timerTxt.setText('Time: ' + timeLeft);
// Check if time is up
if (escapeTimer >= maxEscapeTime) {
LK.getSound('caught').play();
LK.showGameOver();
return;
}
// Move mouse towards target with collision prevention
if (isMoving && !mouse.isStuck) {
var dx = targetX - mouse.x;
var dy = targetY - mouse.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
var moveSpeed = mouse.speed * mouse.speedBoost;
var newX = mouse.x + dx / distance * moveSpeed;
var newY = mouse.y + dy / distance * moveSpeed;
// Check if new position would collide with obstacles (unless in ghost mode)
var canMoveX = true;
var canMoveY = true;
if (!ghostMode) {
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
// Check X movement
if (newX > obstacle.x - obstacle.width / 2 - 50 && newX < obstacle.x + obstacle.width / 2 + 50 && mouse.y > obstacle.y - obstacle.height / 2 - 50 && mouse.y < obstacle.y + obstacle.height / 2 + 50) {
canMoveX = false;
}
// Check Y movement
if (mouse.x > obstacle.x - obstacle.width / 2 - 50 && mouse.x < obstacle.x + obstacle.width / 2 + 50 && newY > obstacle.y - obstacle.height / 2 - 50 && newY < obstacle.y + obstacle.height / 2 + 50) {
canMoveY = false;
}
}
}
// Apply movement only if no collision
if (canMoveX) {
mouse.x = newX;
}
if (canMoveY) {
mouse.y = newY;
}
}
}
// Update cat AI target
cat.targetX = mouse.x;
cat.targetY = mouse.y;
// Check mouse collision with obstacles - prevent movement into obstacles (unless in ghost mode)
if (!ghostMode) {
var newMouseX = mouse.x;
var newMouseY = mouse.y;
var collisionDetected = false;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
// Check if mouse would collide with obstacle
if (newMouseX > obstacle.x - obstacle.width / 2 - 50 && newMouseX < obstacle.x + obstacle.width / 2 + 50 && newMouseY > obstacle.y - obstacle.height / 2 - 50 && newMouseY < obstacle.y + obstacle.height / 2 + 50) {
collisionDetected = true;
// Find the closest edge to push mouse away
var leftDist = Math.abs(newMouseX - (obstacle.x - obstacle.width / 2 - 50));
var rightDist = Math.abs(newMouseX - (obstacle.x + obstacle.width / 2 + 50));
var topDist = Math.abs(newMouseY - (obstacle.y - obstacle.height / 2 - 50));
var bottomDist = Math.abs(newMouseY - (obstacle.y + obstacle.height / 2 + 50));
var minDist = Math.min(leftDist, rightDist, topDist, bottomDist);
if (minDist === leftDist) {
mouse.x = obstacle.x - obstacle.width / 2 - 50;
} else if (minDist === rightDist) {
mouse.x = obstacle.x + obstacle.width / 2 + 50;
} else if (minDist === topDist) {
mouse.y = obstacle.y - obstacle.height / 2 - 50;
} else {
mouse.y = obstacle.y + obstacle.height / 2 + 50;
}
break;
}
}
}
// Tunnels are mouse traps - if mouse enters, it gets stuck
for (var i = 0; i < tunnels.length; i++) {
var tunnel = tunnels[i];
// Use smaller hitbox for tunnel detection (50% of original size)
var tunnelHitboxSize = 75; // Reduced from 150 to 75
if (mouse.x > tunnel.x - tunnelHitboxSize / 2 && mouse.x < tunnel.x + tunnelHitboxSize / 2 && mouse.y > tunnel.y - tunnelHitboxSize / 2 && mouse.y < tunnel.y + tunnelHitboxSize / 2 && !mouse.isStuck) {
// Mouse gets stuck in tunnel
mouse.isStuck = true;
mouse.stuckInTunnel = tunnel;
mouse.x = tunnel.x;
mouse.y = tunnel.y;
LK.effects.flashObject(mouse, 0xFF0000, 1000);
break;
}
}
// Cats can pass through tunnels freely (no collision detection)
// Check cheese collection
for (var i = cheeses.length - 1; i >= 0; i--) {
var cheese = cheeses[i];
if (!cheese.collected && mouse.intersects(cheese)) {
cheese.collected = true;
cheese.visible = false;
mouse.applySpeedBoost();
LK.getSound('collect').play();
LK.setScore(LK.getScore() + 10);
cheeses.splice(i, 1);
cheese.destroy();
}
}
// Check special cheese collection
for (var i = specialCheeses.length - 1; i >= 0; i--) {
var specialCheese = specialCheeses[i];
if (!specialCheese.collected && mouse.intersects(specialCheese)) {
specialCheese.collected = true;
specialCheese.visible = false;
mouse.activateGhostMode();
LK.getSound('collect').play();
LK.setScore(LK.getScore() + 50);
LK.effects.flashScreen(0x00FFFF, 500);
specialCheeses.splice(i, 1);
specialCheese.destroy();
}
}
// Check if mouse reached exit
if (mouse.intersects(exitZone)) {
LK.getSound('escape').play();
LK.setScore(LK.getScore() + 100 * level);
level++;
if (level > 10) {
LK.showYouWin();
} else {
cat.adaptBehavior();
createLevel();
}
return;
}
// Check if cat caught mouse
if (cat.intersects(mouse)) {
LK.getSound('caught').play();
LK.effects.flashScreen(0xFF0000, 500);
LK.showGameOver();
}
// Keep entities within bounds
mouse.x = Math.max(50, Math.min(1998, mouse.x));
mouse.y = Math.max(50, Math.min(2682, mouse.y));
cat.x = Math.max(50, Math.min(1998, cat.x));
cat.y = Math.max(50, Math.min(2682, cat.y));
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Cat = Container.expand(function () {
var self = Container.call(this);
var catGraphics = self.attachAsset('cat', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 6;
self.baseSpeed = 6;
self.targetX = 0;
self.targetY = 0;
self.adaptationLevel = 0;
self.stuckCounter = 0;
self.lastX = 0;
self.lastY = 0;
self.jumpTimer = 0;
self.isJumping = false;
self.jumpCooldown = 300; // 5 seconds at 60fps
self.hasJumpedForObstacle = false;
self.update = function () {
// Update jump timer
self.jumpTimer++;
if (self.jumpTimer >= self.jumpCooldown) {
self.jumpTimer = 0;
}
// Check if cat is stuck
if (Math.abs(self.x - self.lastX) < 1 && Math.abs(self.y - self.lastY) < 1) {
self.stuckCounter++;
if (self.stuckCounter > 30) {
// Try alternative path when stuck
self.targetX = mouse.x + (Math.random() - 0.5) * 200;
self.targetY = mouse.y + (Math.random() - 0.5) * 200;
self.stuckCounter = 0;
}
} else {
self.stuckCounter = 0;
}
// Update cat rotation based on movement direction
var dx = self.x - self.lastX;
var dy = self.y - self.lastY;
if (Math.abs(dx) > 0.1 || Math.abs(dy) > 0.1) {
var angle = Math.atan2(dy, dx);
catGraphics.rotation = angle;
}
self.lastX = self.x;
self.lastY = self.y;
// AI pathfinding with adaptation
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
var moveX = dx / distance * self.speed;
var moveY = dy / distance * self.speed;
var newX = self.x + moveX;
var newY = self.y + moveY;
// Simple collision avoidance - unless jumping
var canMove = true;
var obstacleDetected = false;
if (!self.isJumping) {
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
if (newX > obstacle.x - obstacle.width / 2 - 60 && newX < obstacle.x + obstacle.width / 2 + 60 && newY > obstacle.y - obstacle.height / 2 - 60 && newY < obstacle.y + obstacle.height / 2 + 60) {
canMove = false;
obstacleDetected = true;
// Jump immediately when obstacle is detected, but only once
if (!self.hasJumpedForObstacle) {
self.performJump();
self.hasJumpedForObstacle = true;
}
canMove = true;
break;
}
}
// Reset jump flag when no obstacle is detected
if (!obstacleDetected) {
self.hasJumpedForObstacle = false;
}
}
if (canMove) {
self.x = newX;
self.y = newY;
}
}
};
self.performJump = function () {
if (self.isJumping) return;
self.isJumping = true;
self.jumpTimer = 0;
// Calculate jump destination - move towards mouse position over obstacles
var dx = mouse.x - self.x;
var dy = mouse.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var jumpDistance = 300; // Distance to jump
var jumpX = self.x + dx / distance * jumpDistance;
var jumpY = self.y + dy / distance * jumpDistance;
// Keep jump within bounds
jumpX = Math.max(50, Math.min(1998, jumpX));
jumpY = Math.max(50, Math.min(2682, jumpY));
// Create jump animation - scale up and add slight tint
tween(catGraphics, {
scaleX: 1.3,
scaleY: 1.3,
tint: 0xFFFF99
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Scale back down after jump
tween(catGraphics, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
self.isJumping = false;
}
});
}
});
// Actually move the cat over obstacles
tween(self, {
x: jumpX,
y: jumpY
}, {
duration: 500,
easing: tween.easeInOut
});
};
self.adaptBehavior = function () {
self.adaptationLevel++;
self.speed = self.baseSpeed + self.adaptationLevel * 0.5;
};
return self;
});
var Cheese = Container.expand(function () {
var self = Container.call(this);
var cheeseGraphics = self.attachAsset('cheese', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
if (!self.collected) {
cheeseGraphics.rotation += 0.1;
}
};
return self;
});
var ExitZone = Container.expand(function () {
var self = Container.call(this);
var exitGraphics = self.attachAsset('exitZone', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.update = function () {
exitGraphics.alpha = 0.4 + Math.sin(LK.ticks * 0.1) * 0.2;
};
return self;
});
var Mouse = Container.expand(function () {
var self = Container.call(this);
var mouseGraphics = self.attachAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.speedBoost = 1;
self.boostTimer = 0;
self.isStuck = false;
self.stuckInTunnel = null;
self.lastX = 0;
self.lastY = 0;
self.update = function () {
if (self.boostTimer > 0) {
self.boostTimer--;
if (self.boostTimer === 0) {
self.speedBoost = 1;
if (!ghostMode) {
mouseGraphics.tint = 0xFFFFFF;
}
}
}
// Handle ghost mode visuals
if (ghostMode) {
mouseGraphics.alpha = 0.5 + Math.sin(LK.ticks * 0.2) * 0.3;
mouseGraphics.tint = 0x00FFFF;
} else {
mouseGraphics.alpha = 1;
if (self.boostTimer === 0) {
mouseGraphics.tint = 0xFFFFFF;
}
}
// Update mouse rotation based on movement direction
var dx = self.x - self.lastX;
var dy = self.y - self.lastY;
if (Math.abs(dx) > 0.1 || Math.abs(dy) > 0.1) {
var angle = Math.atan2(dy, dx);
mouseGraphics.rotation = angle;
}
self.lastX = self.x;
self.lastY = self.y;
};
self.applySpeedBoost = function () {
self.speedBoost = 2;
self.boostTimer = 180; // 3 seconds at 60fps
if (!ghostMode) {
mouseGraphics.tint = 0xFFFF00;
}
};
self.activateGhostMode = function () {
ghostMode = true;
ghostModeTimer = ghostModeDuration;
mouseGraphics.tint = 0x00FFFF;
mouseGraphics.alpha = 0.7;
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var SpecialCheese = Container.expand(function () {
var self = Container.call(this);
var cheeseGraphics = self.attachAsset('specialCheese', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFD700
});
self.collected = false;
self.update = function () {
if (!self.collected) {
cheeseGraphics.rotation += 0.2;
// Pulse effect
cheeseGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
cheeseGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.2;
}
};
return self;
});
var Tunnel = Container.expand(function () {
var self = Container.call(this);
var tunnelGraphics = self.attachAsset('tunnel', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F2F
});
/****
* Game Code
****/
// Add ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
var mouse;
var cat;
var obstacles = [];
var tunnels = [];
var cheeses = [];
var specialCheeses = [];
var ghostMode = false;
var ghostModeTimer = 0;
var ghostModeDuration = 300; // 5 seconds at 60fps
var exitZone;
var level = 1;
var gameStarted = false;
var escapeTimer = 0;
var maxEscapeTime = 1800; // 30 seconds at 60fps
// UI Elements
var levelTxt = new Text2('Level: 1', {
size: 80,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
var timerTxt = new Text2('Time: 30', {
size: 60,
fill: 0xFFFF00
});
timerTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(timerTxt);
var instructionTxt = new Text2('Touch to move the mouse!\nAvoid the cat and reach the green exit!', {
size: 50,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 1024;
instructionTxt.y = 1366;
game.addChild(instructionTxt);
// Create mouse
mouse = game.addChild(new Mouse());
mouse.x = 200;
mouse.y = 2500;
// Create cat
cat = game.addChild(new Cat());
cat.x = 1800;
cat.y = 2500;
cat.targetX = mouse.x;
cat.targetY = mouse.y;
// Create level
function createLevel() {
// Clear existing level elements
for (var i = obstacles.length - 1; i >= 0; i--) {
obstacles[i].destroy();
obstacles.splice(i, 1);
}
for (var i = tunnels.length - 1; i >= 0; i--) {
tunnels[i].destroy();
tunnels.splice(i, 1);
}
for (var i = cheeses.length - 1; i >= 0; i--) {
cheeses[i].destroy();
cheeses.splice(i, 1);
}
for (var i = specialCheeses.length - 1; i >= 0; i--) {
specialCheeses[i].destroy();
specialCheeses.splice(i, 1);
}
if (exitZone) {
exitZone.destroy();
}
// Create obstacles - more frequent but ensure path to exit
var numObstacles = 8 + level * 3; // Increased from 5 + level * 2
for (var i = 0; i < numObstacles; i++) {
var obstacle = game.addChild(new Obstacle());
var validPosition = false;
var attempts = 0;
// Try to find a valid position that doesn't block the path
while (!validPosition && attempts < 50) {
obstacle.x = Math.random() * 1800 + 200;
obstacle.y = Math.random() * 2000 + 400;
// Check if obstacle would be too close to mouse start position
var distToMouse = Math.sqrt((obstacle.x - 200) * (obstacle.x - 200) + (obstacle.y - 2500) * (obstacle.y - 2500));
// Check if obstacle would be too close to exit zone (if it exists)
var distToExit = exitZone ? Math.sqrt((obstacle.x - exitZone.x) * (obstacle.x - exitZone.x) + (obstacle.y - exitZone.y) * (obstacle.y - exitZone.y)) : 1000;
// Ensure minimum distance from mouse start and exit
if (distToMouse > 300 && distToExit > 250) {
validPosition = true;
}
attempts++;
}
obstacles.push(obstacle);
}
// Create tunnels (mouse can pass through, cat cannot)
var numTunnels = 3 + level;
for (var i = 0; i < numTunnels; i++) {
var tunnel = game.addChild(new Tunnel());
tunnel.x = Math.random() * 1800 + 200;
tunnel.y = Math.random() * 2000 + 400;
tunnels.push(tunnel);
}
// Create cheese power-ups
var numCheeses = 2 + Math.floor(level / 2);
for (var i = 0; i < numCheeses; i++) {
var cheese = game.addChild(new Cheese());
cheese.x = Math.random() * 1600 + 300;
cheese.y = Math.random() * 1800 + 600;
cheeses.push(cheese);
}
// Create special cheese (very rare - 20% chance per level)
if (Math.random() < 0.2) {
var specialCheese = game.addChild(new SpecialCheese());
specialCheese.x = Math.random() * 1600 + 300;
specialCheese.y = Math.random() * 1800 + 600;
specialCheeses.push(specialCheese);
}
// Create exit zone
exitZone = game.addChild(new ExitZone());
exitZone.x = Math.random() * 1000 + 500;
exitZone.y = Math.random() * 800 + 200;
// Reset positions
mouse.x = 200;
mouse.y = 2500;
cat.x = 1800;
cat.y = 2500;
// Reset mouse stuck state
mouse.isStuck = false;
mouse.stuckInTunnel = null;
// Reset timer
escapeTimer = 0;
// Update UI
levelTxt.setText('Level: ' + level);
}
// Initialize first level
createLevel();
// Game controls
var targetX = mouse.x;
var targetY = mouse.y;
var isMoving = false;
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
instructionTxt.visible = false;
}
targetX = x;
targetY = y;
isMoving = true;
};
game.move = function (x, y, obj) {
if (isMoving) {
targetX = x;
targetY = y;
}
};
game.up = function (x, y, obj) {
isMoving = false;
};
game.update = function () {
if (!gameStarted) return;
// Update ghost mode timer
if (ghostMode) {
ghostModeTimer--;
if (ghostModeTimer <= 0) {
ghostMode = false;
mouse.attachAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5
}).alpha = 1;
}
}
// Update timer
escapeTimer++;
var timeLeft = Math.max(0, Math.ceil((maxEscapeTime - escapeTimer) / 60));
timerTxt.setText('Time: ' + timeLeft);
// Check if time is up
if (escapeTimer >= maxEscapeTime) {
LK.getSound('caught').play();
LK.showGameOver();
return;
}
// Move mouse towards target with collision prevention
if (isMoving && !mouse.isStuck) {
var dx = targetX - mouse.x;
var dy = targetY - mouse.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
var moveSpeed = mouse.speed * mouse.speedBoost;
var newX = mouse.x + dx / distance * moveSpeed;
var newY = mouse.y + dy / distance * moveSpeed;
// Check if new position would collide with obstacles (unless in ghost mode)
var canMoveX = true;
var canMoveY = true;
if (!ghostMode) {
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
// Check X movement
if (newX > obstacle.x - obstacle.width / 2 - 50 && newX < obstacle.x + obstacle.width / 2 + 50 && mouse.y > obstacle.y - obstacle.height / 2 - 50 && mouse.y < obstacle.y + obstacle.height / 2 + 50) {
canMoveX = false;
}
// Check Y movement
if (mouse.x > obstacle.x - obstacle.width / 2 - 50 && mouse.x < obstacle.x + obstacle.width / 2 + 50 && newY > obstacle.y - obstacle.height / 2 - 50 && newY < obstacle.y + obstacle.height / 2 + 50) {
canMoveY = false;
}
}
}
// Apply movement only if no collision
if (canMoveX) {
mouse.x = newX;
}
if (canMoveY) {
mouse.y = newY;
}
}
}
// Update cat AI target
cat.targetX = mouse.x;
cat.targetY = mouse.y;
// Check mouse collision with obstacles - prevent movement into obstacles (unless in ghost mode)
if (!ghostMode) {
var newMouseX = mouse.x;
var newMouseY = mouse.y;
var collisionDetected = false;
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
// Check if mouse would collide with obstacle
if (newMouseX > obstacle.x - obstacle.width / 2 - 50 && newMouseX < obstacle.x + obstacle.width / 2 + 50 && newMouseY > obstacle.y - obstacle.height / 2 - 50 && newMouseY < obstacle.y + obstacle.height / 2 + 50) {
collisionDetected = true;
// Find the closest edge to push mouse away
var leftDist = Math.abs(newMouseX - (obstacle.x - obstacle.width / 2 - 50));
var rightDist = Math.abs(newMouseX - (obstacle.x + obstacle.width / 2 + 50));
var topDist = Math.abs(newMouseY - (obstacle.y - obstacle.height / 2 - 50));
var bottomDist = Math.abs(newMouseY - (obstacle.y + obstacle.height / 2 + 50));
var minDist = Math.min(leftDist, rightDist, topDist, bottomDist);
if (minDist === leftDist) {
mouse.x = obstacle.x - obstacle.width / 2 - 50;
} else if (minDist === rightDist) {
mouse.x = obstacle.x + obstacle.width / 2 + 50;
} else if (minDist === topDist) {
mouse.y = obstacle.y - obstacle.height / 2 - 50;
} else {
mouse.y = obstacle.y + obstacle.height / 2 + 50;
}
break;
}
}
}
// Tunnels are mouse traps - if mouse enters, it gets stuck
for (var i = 0; i < tunnels.length; i++) {
var tunnel = tunnels[i];
// Use smaller hitbox for tunnel detection (50% of original size)
var tunnelHitboxSize = 75; // Reduced from 150 to 75
if (mouse.x > tunnel.x - tunnelHitboxSize / 2 && mouse.x < tunnel.x + tunnelHitboxSize / 2 && mouse.y > tunnel.y - tunnelHitboxSize / 2 && mouse.y < tunnel.y + tunnelHitboxSize / 2 && !mouse.isStuck) {
// Mouse gets stuck in tunnel
mouse.isStuck = true;
mouse.stuckInTunnel = tunnel;
mouse.x = tunnel.x;
mouse.y = tunnel.y;
LK.effects.flashObject(mouse, 0xFF0000, 1000);
break;
}
}
// Cats can pass through tunnels freely (no collision detection)
// Check cheese collection
for (var i = cheeses.length - 1; i >= 0; i--) {
var cheese = cheeses[i];
if (!cheese.collected && mouse.intersects(cheese)) {
cheese.collected = true;
cheese.visible = false;
mouse.applySpeedBoost();
LK.getSound('collect').play();
LK.setScore(LK.getScore() + 10);
cheeses.splice(i, 1);
cheese.destroy();
}
}
// Check special cheese collection
for (var i = specialCheeses.length - 1; i >= 0; i--) {
var specialCheese = specialCheeses[i];
if (!specialCheese.collected && mouse.intersects(specialCheese)) {
specialCheese.collected = true;
specialCheese.visible = false;
mouse.activateGhostMode();
LK.getSound('collect').play();
LK.setScore(LK.getScore() + 50);
LK.effects.flashScreen(0x00FFFF, 500);
specialCheeses.splice(i, 1);
specialCheese.destroy();
}
}
// Check if mouse reached exit
if (mouse.intersects(exitZone)) {
LK.getSound('escape').play();
LK.setScore(LK.getScore() + 100 * level);
level++;
if (level > 10) {
LK.showYouWin();
} else {
cat.adaptBehavior();
createLevel();
}
return;
}
// Check if cat caught mouse
if (cat.intersects(mouse)) {
LK.getSound('caught').play();
LK.effects.flashScreen(0xFF0000, 500);
LK.showGameOver();
}
// Keep entities within bounds
mouse.x = Math.max(50, Math.min(1998, mouse.x));
mouse.y = Math.max(50, Math.min(2682, mouse.y));
cat.x = Math.max(50, Math.min(1998, cat.x));
cat.y = Math.max(50, Math.min(2682, cat.y));
};
çizgi film peyniri. In-Game asset. 2d. High contrast. No shadows
çizgi film fare yuvası. In-Game asset. 2d. High contrast. No shadows
çizgi filmdeki fare jerry kaçıyor. In-Game asset. 2d. High contrast. No shadows
çizgi film fare tuzağı. In-Game asset. 2d. High contrast. No shadows
just a green field viewed from above. In-Game asset. 2d. High contrast. No shadows
rainbow cartoon cheese. In-Game asset. 2d. High contrast. No shadows