/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function (level) {
var self = Container.call(this);
self.level = level || 1;
self.merging = false;
self.settled = false;
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.5;
self.bounce = 0.3;
self.friction = 0.98;
self.lastY = undefined;
var graphics = self.attachAsset('character' + self.level, {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = graphics.width / 2;
// Add character labels for visual feedback
var levelText = new Text2(self.level.toString(), {
size: 40,
fill: 0x000000
});
levelText.anchor.set(0.5, 0.5);
self.addChild(levelText);
self.update = function () {
if (self.merging) return;
// Apply gravity
self.velocityY += self.gravity;
// Apply velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction
self.velocityX *= self.friction;
// Check if character crosses game over boundary (only when settled and completely outside)
if (self.settled && self.y - self.radius <= 1400 && !gameOver) {
gameOver = true;
LK.showGameOver();
return;
}
// Check collision with walls
if (self.x - self.radius <= leftWall.x + leftWall.width / 2) {
self.x = leftWall.x + leftWall.width / 2 + self.radius;
self.velocityX = 0;
}
if (self.x + self.radius >= rightWall.x - rightWall.width / 2) {
self.x = rightWall.x - rightWall.width / 2 - self.radius;
self.velocityX = 0;
}
// Check collision with floor
if (self.y + self.radius >= floor.y - floor.height / 2) {
self.y = floor.y - floor.height / 2 - self.radius;
self.velocityY = 0;
self.settled = true;
}
// Check for collisions with other characters
for (var i = 0; i < characters.length; i++) {
var other = characters[i];
if (other !== self && !other.merging && !self.merging) {
var distance = Math.sqrt(Math.pow(self.x - other.x, 2) + Math.pow(self.y - other.y, 2));
var minDistance = self.radius + other.radius;
// Check for collision
if (distance < minDistance && distance > 0) {
// Calculate collision normal
var normalX = (other.x - self.x) / distance;
var normalY = (other.y - self.y) / distance;
// Separate objects
var overlap = minDistance - distance;
var separationX = normalX * overlap * 0.5;
var separationY = normalY * overlap * 0.5;
self.x -= separationX;
self.y -= separationY;
other.x += separationX;
other.y += separationY;
// Stop movement on collision to prevent bouncing
self.velocityX *= 0.5;
self.velocityY *= 0.5;
other.velocityX *= 0.5;
other.velocityY *= 0.5;
// Check for merging only if same level and touching
if (other.level === self.level && distance < minDistance) {
self.mergeWith(other);
break;
}
}
}
}
// Update lastY for boundary detection
self.lastY = self.y;
};
self.mergeWith = function (other) {
if (self.merging || other.merging) return;
if (self.level >= 11) return; // Max level reached
self.merging = true;
other.merging = true;
// Calculate merge position
var mergeX = (self.x + other.x) / 2;
var mergeY = (self.y + other.y) / 2;
// Play merge sound
LK.getSound('merge').play();
// Create merge effect
tween(self, {
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut
});
tween(other, {
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove old characters
var selfIndex = characters.indexOf(self);
var otherIndex = characters.indexOf(other);
if (selfIndex > -1) characters.splice(selfIndex, 1);
if (otherIndex > -1) characters.splice(otherIndex, 1);
self.destroy();
other.destroy();
// Create new character
var newCharacter = new Character(self.level + 1);
newCharacter.x = mergeX;
newCharacter.y = mergeY;
newCharacter.velocityY = -5; // Small upward bounce
characters.push(newCharacter);
gameContainer.addChild(newCharacter);
// Update score
LK.setScore(LK.getScore() + self.level * 10);
scoreText.setText(LK.getScore());
// Spawn effect
tween(newCharacter, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
newCharacter.scaleX = 0.5;
newCharacter.scaleY = 0.5;
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Sound effects
// Drop zone indicator
// Container walls
// Pink circle - ultimate
// Orange circle - capybara with hat
// Purple circle - capybara
// Yellow circle - giant duck
// Green circle - duck
// Blue circle - cat with glasses
// Teal circle - cat
// Red circle - basic
// Character assets - progression from simple to complex
// Game variables
var characters = [];
var nextCharacterLevel = 1;
var dropPosition = 1024; // Center of screen
var gameOver = false;
var dropCooldown = 0;
// Create game container
var gameContainer = new Container();
game.addChild(gameContainer);
// Create container walls and floor
var leftWall = gameContainer.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: 624,
y: 1866
});
var rightWall = gameContainer.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: 1424,
y: 1866
});
var floor = gameContainer.attachAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2166
});
// Create drop zone indicator
var dropZone = gameContainer.attachAsset('dropZone', {
anchorX: 0.5,
anchorY: 0.5,
x: dropPosition,
y: 1400,
alpha: 0.3
});
// Create UI elements
var scoreText = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 100;
var nextCharacterText = new Text2('Next: Level 1', {
size: 60,
fill: 0xFFFFFF
});
nextCharacterText.anchor.set(0.5, 0);
LK.gui.top.addChild(nextCharacterText);
nextCharacterText.y = 200;
// Game over line
var gameOverLine = new Container();
var lineGraphics = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
width: 800,
height: 5
});
lineGraphics.tint = 0xFF0000;
lineGraphics.alpha = 0.5;
gameOverLine.addChild(lineGraphics);
gameOverLine.x = 1024;
gameOverLine.y = 1450;
gameContainer.addChild(gameOverLine);
// Check if there are any matching characters for the given level
function hasMatchingCharacters(level) {
var count = 0;
for (var i = 0; i < characters.length; i++) {
if (characters[i].level === level && !characters[i].merging) {
count++;
if (count >= 2) return true;
}
}
return false;
}
// Generate next character level (weighted towards lower levels)
function generateNextCharacter() {
var rand = Math.random();
if (rand < 0.35) return 1;
if (rand < 0.6) return 2;
if (rand < 0.75) return 3;
if (rand < 0.85) return 4;
if (rand < 0.92) return 5;
if (rand < 0.97) return 6;
return 7;
}
// Check if game is over - disabled for infinite gameplay
function checkGameOver() {
// Game over functionality removed - infinite game
return false;
}
// Drop character
function dropCharacter() {
if (dropCooldown > 0) return;
var character = new Character(nextCharacterLevel);
character.x = dropPosition;
character.y = 1300;
character.velocityY = 2;
characters.push(character);
gameContainer.addChild(character);
// Play drop sound
LK.getSound('drop').play();
// Generate next character
nextCharacterLevel = generateNextCharacter();
nextCharacterText.setText('Next: Level ' + nextCharacterLevel);
updatePreviewCharacter();
// Set cooldown
dropCooldown = 30; // 0.5 seconds at 60fps
}
// Handle mouse/touch input
game.move = function (x, y, obj) {
// Update drop position
dropPosition = Math.max(leftWall.x + leftWall.width / 2 + 60, Math.min(rightWall.x - rightWall.width / 2 - 60, x));
dropZone.x = dropPosition;
};
game.down = function (x, y, obj) {
// Update drop position and drop character
dropPosition = Math.max(leftWall.x + leftWall.width / 2 + 60, Math.min(rightWall.x - rightWall.width / 2 - 60, x));
dropZone.x = dropPosition;
dropCharacter();
};
// Main game loop
game.update = function () {
// Update cooldown
if (dropCooldown > 0) {
dropCooldown--;
}
// Update drop zone alpha based on cooldown
dropZone.alpha = dropCooldown > 0 ? 0.1 : 0.3;
// Clean up destroyed characters
for (var i = characters.length - 1; i >= 0; i--) {
if (characters[i].destroyed) {
characters.splice(i, 1);
}
}
};
// Create preview container for next character
var previewContainer = new Container();
previewContainer.x = 1800; // Top-right corner
previewContainer.y = 200;
LK.gui.addChild(previewContainer);
// Create preview character display
var previewCharacter = null;
// Function to update preview character
function updatePreviewCharacter() {
// Remove existing preview
if (previewCharacter) {
previewCharacter.destroy();
}
// Create new preview character
previewCharacter = previewContainer.attachAsset('character' + nextCharacterLevel, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Add preview label
var previewLabel = new Text2('Next', {
size: 40,
fill: 0xFFFFFF
});
previewLabel.anchor.set(0.5, 0.5);
previewLabel.y = -80;
previewContainer.addChild(previewLabel);
}
// Initialize first character level
nextCharacterLevel = generateNextCharacter();
nextCharacterText.setText('Next: Level ' + nextCharacterLevel);
updatePreviewCharacter(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Character = Container.expand(function (level) {
var self = Container.call(this);
self.level = level || 1;
self.merging = false;
self.settled = false;
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.5;
self.bounce = 0.3;
self.friction = 0.98;
self.lastY = undefined;
var graphics = self.attachAsset('character' + self.level, {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = graphics.width / 2;
// Add character labels for visual feedback
var levelText = new Text2(self.level.toString(), {
size: 40,
fill: 0x000000
});
levelText.anchor.set(0.5, 0.5);
self.addChild(levelText);
self.update = function () {
if (self.merging) return;
// Apply gravity
self.velocityY += self.gravity;
// Apply velocity
self.x += self.velocityX;
self.y += self.velocityY;
// Apply friction
self.velocityX *= self.friction;
// Check if character crosses game over boundary (only when settled and completely outside)
if (self.settled && self.y - self.radius <= 1400 && !gameOver) {
gameOver = true;
LK.showGameOver();
return;
}
// Check collision with walls
if (self.x - self.radius <= leftWall.x + leftWall.width / 2) {
self.x = leftWall.x + leftWall.width / 2 + self.radius;
self.velocityX = 0;
}
if (self.x + self.radius >= rightWall.x - rightWall.width / 2) {
self.x = rightWall.x - rightWall.width / 2 - self.radius;
self.velocityX = 0;
}
// Check collision with floor
if (self.y + self.radius >= floor.y - floor.height / 2) {
self.y = floor.y - floor.height / 2 - self.radius;
self.velocityY = 0;
self.settled = true;
}
// Check for collisions with other characters
for (var i = 0; i < characters.length; i++) {
var other = characters[i];
if (other !== self && !other.merging && !self.merging) {
var distance = Math.sqrt(Math.pow(self.x - other.x, 2) + Math.pow(self.y - other.y, 2));
var minDistance = self.radius + other.radius;
// Check for collision
if (distance < minDistance && distance > 0) {
// Calculate collision normal
var normalX = (other.x - self.x) / distance;
var normalY = (other.y - self.y) / distance;
// Separate objects
var overlap = minDistance - distance;
var separationX = normalX * overlap * 0.5;
var separationY = normalY * overlap * 0.5;
self.x -= separationX;
self.y -= separationY;
other.x += separationX;
other.y += separationY;
// Stop movement on collision to prevent bouncing
self.velocityX *= 0.5;
self.velocityY *= 0.5;
other.velocityX *= 0.5;
other.velocityY *= 0.5;
// Check for merging only if same level and touching
if (other.level === self.level && distance < minDistance) {
self.mergeWith(other);
break;
}
}
}
}
// Update lastY for boundary detection
self.lastY = self.y;
};
self.mergeWith = function (other) {
if (self.merging || other.merging) return;
if (self.level >= 11) return; // Max level reached
self.merging = true;
other.merging = true;
// Calculate merge position
var mergeX = (self.x + other.x) / 2;
var mergeY = (self.y + other.y) / 2;
// Play merge sound
LK.getSound('merge').play();
// Create merge effect
tween(self, {
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut
});
tween(other, {
alpha: 0,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove old characters
var selfIndex = characters.indexOf(self);
var otherIndex = characters.indexOf(other);
if (selfIndex > -1) characters.splice(selfIndex, 1);
if (otherIndex > -1) characters.splice(otherIndex, 1);
self.destroy();
other.destroy();
// Create new character
var newCharacter = new Character(self.level + 1);
newCharacter.x = mergeX;
newCharacter.y = mergeY;
newCharacter.velocityY = -5; // Small upward bounce
characters.push(newCharacter);
gameContainer.addChild(newCharacter);
// Update score
LK.setScore(LK.getScore() + self.level * 10);
scoreText.setText(LK.getScore());
// Spawn effect
tween(newCharacter, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.bounceOut
});
newCharacter.scaleX = 0.5;
newCharacter.scaleY = 0.5;
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Sound effects
// Drop zone indicator
// Container walls
// Pink circle - ultimate
// Orange circle - capybara with hat
// Purple circle - capybara
// Yellow circle - giant duck
// Green circle - duck
// Blue circle - cat with glasses
// Teal circle - cat
// Red circle - basic
// Character assets - progression from simple to complex
// Game variables
var characters = [];
var nextCharacterLevel = 1;
var dropPosition = 1024; // Center of screen
var gameOver = false;
var dropCooldown = 0;
// Create game container
var gameContainer = new Container();
game.addChild(gameContainer);
// Create container walls and floor
var leftWall = gameContainer.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: 624,
y: 1866
});
var rightWall = gameContainer.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
x: 1424,
y: 1866
});
var floor = gameContainer.attachAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2166
});
// Create drop zone indicator
var dropZone = gameContainer.attachAsset('dropZone', {
anchorX: 0.5,
anchorY: 0.5,
x: dropPosition,
y: 1400,
alpha: 0.3
});
// Create UI elements
var scoreText = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 100;
var nextCharacterText = new Text2('Next: Level 1', {
size: 60,
fill: 0xFFFFFF
});
nextCharacterText.anchor.set(0.5, 0);
LK.gui.top.addChild(nextCharacterText);
nextCharacterText.y = 200;
// Game over line
var gameOverLine = new Container();
var lineGraphics = LK.getAsset('floor', {
anchorX: 0.5,
anchorY: 0.5,
width: 800,
height: 5
});
lineGraphics.tint = 0xFF0000;
lineGraphics.alpha = 0.5;
gameOverLine.addChild(lineGraphics);
gameOverLine.x = 1024;
gameOverLine.y = 1450;
gameContainer.addChild(gameOverLine);
// Check if there are any matching characters for the given level
function hasMatchingCharacters(level) {
var count = 0;
for (var i = 0; i < characters.length; i++) {
if (characters[i].level === level && !characters[i].merging) {
count++;
if (count >= 2) return true;
}
}
return false;
}
// Generate next character level (weighted towards lower levels)
function generateNextCharacter() {
var rand = Math.random();
if (rand < 0.35) return 1;
if (rand < 0.6) return 2;
if (rand < 0.75) return 3;
if (rand < 0.85) return 4;
if (rand < 0.92) return 5;
if (rand < 0.97) return 6;
return 7;
}
// Check if game is over - disabled for infinite gameplay
function checkGameOver() {
// Game over functionality removed - infinite game
return false;
}
// Drop character
function dropCharacter() {
if (dropCooldown > 0) return;
var character = new Character(nextCharacterLevel);
character.x = dropPosition;
character.y = 1300;
character.velocityY = 2;
characters.push(character);
gameContainer.addChild(character);
// Play drop sound
LK.getSound('drop').play();
// Generate next character
nextCharacterLevel = generateNextCharacter();
nextCharacterText.setText('Next: Level ' + nextCharacterLevel);
updatePreviewCharacter();
// Set cooldown
dropCooldown = 30; // 0.5 seconds at 60fps
}
// Handle mouse/touch input
game.move = function (x, y, obj) {
// Update drop position
dropPosition = Math.max(leftWall.x + leftWall.width / 2 + 60, Math.min(rightWall.x - rightWall.width / 2 - 60, x));
dropZone.x = dropPosition;
};
game.down = function (x, y, obj) {
// Update drop position and drop character
dropPosition = Math.max(leftWall.x + leftWall.width / 2 + 60, Math.min(rightWall.x - rightWall.width / 2 - 60, x));
dropZone.x = dropPosition;
dropCharacter();
};
// Main game loop
game.update = function () {
// Update cooldown
if (dropCooldown > 0) {
dropCooldown--;
}
// Update drop zone alpha based on cooldown
dropZone.alpha = dropCooldown > 0 ? 0.1 : 0.3;
// Clean up destroyed characters
for (var i = characters.length - 1; i >= 0; i--) {
if (characters[i].destroyed) {
characters.splice(i, 1);
}
}
};
// Create preview container for next character
var previewContainer = new Container();
previewContainer.x = 1800; // Top-right corner
previewContainer.y = 200;
LK.gui.addChild(previewContainer);
// Create preview character display
var previewCharacter = null;
// Function to update preview character
function updatePreviewCharacter() {
// Remove existing preview
if (previewCharacter) {
previewCharacter.destroy();
}
// Create new preview character
previewCharacter = previewContainer.attachAsset('character' + nextCharacterLevel, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
// Add preview label
var previewLabel = new Text2('Next', {
size: 40,
fill: 0xFFFFFF
});
previewLabel.anchor.set(0.5, 0.5);
previewLabel.y = -80;
previewContainer.addChild(previewLabel);
}
// Initialize first character level
nextCharacterLevel = generateNextCharacter();
nextCharacterText.setText('Next: Level ' + nextCharacterLevel);
updatePreviewCharacter();
make an ant. In-Game asset. High contrast. No shadows
make a bee. In-Game asset. High contrast. No shadows
make a butterfly. In-Game asset. High contrast. No shadows
make a bird. In-Game asset. High contrast. No shadows
create a cat. In-Game asset. High contrast. No shadows
Create a dog. In-Game asset. High contrast. No shadows
Create a tigre. In-Game asset. High contrast. No shadows
Create a oso. In-Game asset. High contrast. No shadows
make a hippopotamus. In-Game asset. High contrast. No shadows
make an elephant. In-Game asset. High contrast. No shadows
make a giraffe. In-Game asset. High contrast. No shadows
make a whale. In-Game asset. High contrast. No shadows