/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Tile class: represents a single memory tile
var Tile = Container.expand(function () {
var self = Container.call(this);
// Properties
self.isFlipped = false;
self.isMatched = false;
self.animalId = null; // Will be set on creation
// Create the back of the tile (hidden state)
var back = self.attachAsset('tileBack', {
anchorX: 0.5,
anchorY: 0.5
});
// Create the front of the tile (animal/plant)
var front = self.attachAsset('animal0', {
// Placeholder, will be replaced
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
self.back = back;
self.front = front;
// Set animal asset
self.setAnimal = function (animalId) {
self.animalId = animalId;
// Remove old front if exists
if (self.front) {
self.removeChild(self.front);
}
// Attach new front
self.front = self.attachAsset('animal' + animalId, {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
};
// Flip to show animal
self.flipUp = function () {
if (self.isFlipped || self.isMatched) return;
self.isFlipped = true;
// Play flip sound
LK.getSound('flip').play();
// Animate flip
tween(self, {
scaleX: 0
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
self.back.visible = false;
self.front.visible = true;
tween(self, {
scaleX: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
};
// Flip to hide animal
self.flipDown = function () {
if (!self.isFlipped || self.isMatched) return;
self.isFlipped = false;
// Play flip sound
LK.getSound('flip').play();
tween(self, {
scaleX: 0
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
self.front.visible = false;
self.back.visible = true;
tween(self, {
scaleX: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
};
// Mark as matched (permanently face up)
self.setMatched = function () {
self.isMatched = true;
self.isFlipped = true;
self.back.visible = false;
self.front.visible = true;
// Optional: animate a little pop
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
};
// Handle tap
self.down = function (x, y, obj) {
if (self.isFlipped || self.isMatched || !canFlipTiles) return;
onTileFlipped(self);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2f4a01 // Changed to requested color #2f4a01
});
/****
* Game Code
****/
// Animal tile assets: numbers 0-10 for 10 levels (11 unique animals)
// --- Game variables ---
// Sound assets
var animalCount = 11; // Number of unique animals/plants (animal0 ... animal10)
var tileBackColor = 0x8db580; // Light green for tile back
var tileSize = 260; // px, square
var tilePadding = 32; // px
var minBoardMargin = 60; // px, margin from edge
var level = 1;
var hearts = 10;
var score = 0;
var combo = 0;
var maxCombo = 0;
var consecutiveMisses = 0;
var tiles = [];
var flippedTiles = [];
var canFlipTiles = true;
var pairsLeft = 0;
// --- UI elements ---
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var heartsTxt = new Text2('♥ 10', {
size: 90,
fill: 0xFF4D4D
});
heartsTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(heartsTxt);
heartsTxt.y = 120;
heartsTxt.x = 0;
var levelTxt = new Text2('Level 1', {
size: 90,
fill: 0xFFE066
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 220;
levelTxt.x = 0;
// --- Asset initialization (shapes for tile back, animal images) ---
for (var i = 0; i < animalCount; i++) {}
// --- Helper: shuffle array ---
function shuffle(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
return arr;
}
// --- Helper: update UI ---
function updateUI() {
scoreTxt.setText(score);
heartsTxt.setText('♥ ' + hearts);
levelTxt.setText('Level ' + level);
}
// --- Helper: show all tiles for preview ---
function previewTiles(cb) {
canFlipTiles = false;
for (var i = 0; i < tiles.length; i++) {
tiles[i].flipUp();
}
LK.setTimeout(function () {
for (var i = 0; i < tiles.length; i++) {
tiles[i].flipDown();
}
canFlipTiles = true;
if (cb) cb();
}, 1200 + Math.min(600, level * 100));
}
// --- Helper: create board for current level ---
function createBoard() {
// Remove old tiles
for (var i = 0; i < tiles.length; i++) {
tiles[i].destroy();
}
tiles = [];
flippedTiles = [];
canFlipTiles = false;
// Determine number of tiles for this level
// Level 1: 4 tiles (2 pairs), then +2 tiles per level, up to level 10
var maxLevel = 10;
var cappedLevel = Math.min(level, maxLevel);
var tileCount = 4 + (cappedLevel - 1) * 2;
var pairCount = Math.floor(tileCount / 2);
if (pairCount > animalCount) pairCount = animalCount; // Cap to available animal assets
tileCount = pairCount * 2; // Ensure even number
// Find grid size (try to make as square as possible)
var cols = Math.ceil(Math.sqrt(tileCount));
var rows = Math.ceil(tileCount / cols);
// Prepare animal pairs
var animalIds = [];
for (var i = 0; i < pairCount; i++) {
animalIds.push(i);
animalIds.push(i);
}
shuffle(animalIds);
// Board centering
var boardW = cols * tileSize + (cols - 1) * tilePadding;
var boardH = rows * tileSize + (rows - 1) * tilePadding;
var startX = Math.floor((2048 - boardW) / 2) + tileSize / 2;
var startY = Math.floor((2732 - boardH) / 2) + tileSize / 2;
// Create tiles
var idx = 0;
for (var r = 0; r < rows; r++) {
for (var c = 0; c < cols; c++) {
if (idx >= animalIds.length) continue;
var tile = new Tile();
tile.setAnimal(animalIds[idx]);
tile.x = startX + c * (tileSize + tilePadding);
tile.y = startY + r * (tileSize + tilePadding);
tile.scaleX = 1;
tile.scaleY = 1;
game.addChild(tile);
tiles.push(tile);
idx++;
}
}
pairsLeft = pairCount;
updateUI();
previewTiles(function () {
canFlipTiles = true;
});
}
// --- Tile flip handler ---
function onTileFlipped(tile) {
if (!canFlipTiles) return;
if (tile.isFlipped || tile.isMatched) return;
tile.flipUp();
flippedTiles.push(tile);
if (flippedTiles.length === 2) {
canFlipTiles = false;
var t1 = flippedTiles[0];
var t2 = flippedTiles[1];
if (t1.animalId === t2.animalId) {
// Match!
LK.setTimeout(function () {
// Play match sound
LK.getSound('match').play();
t1.setMatched();
t2.setMatched();
pairsLeft--;
combo++;
maxCombo = Math.max(combo, maxCombo);
score += 10 * combo;
updateUI();
flippedTiles = [];
canFlipTiles = true;
consecutiveMisses = 0;
// Animate match
LK.effects.flashObject(t1, 0xFFFF99, 300);
LK.effects.flashObject(t2, 0xFFFF99, 300);
if (pairsLeft === 0) {
// Level complete!
LK.setTimeout(function () {
nextLevel();
}, 800);
}
}, 400);
} else {
// Not a match
LK.setTimeout(function () {
// Play error sound
LK.getSound('error').play();
t1.flipDown();
t2.flipDown();
flippedTiles = [];
canFlipTiles = true;
combo = 0;
consecutiveMisses++;
if (consecutiveMisses >= 3) {
hearts--;
consecutiveMisses = 0;
// Play lose heart sound
LK.getSound('loseHeart').play();
LK.effects.flashScreen(0xff0000, 400);
updateUI();
if (hearts <= 0) {
LK.showGameOver();
return;
}
}
updateUI();
}, 700);
}
}
}
// --- Next level ---
function nextLevel() {
level++;
// If player reaches level 10, they win!
if (level > 10) {
LK.showYouWin();
return;
}
// Reward: extra heart for levels > 3
if (level > 3) {
hearts++;
// Play gain heart sound
LK.getSound('gainHeart').play();
LK.effects.flashScreen(0x66ff66, 400);
}
combo = 0;
consecutiveMisses = 0;
createBoard();
}
// --- Start game ---
function startGame() {
level = 1;
hearts = 10;
score = 0;
combo = 0;
maxCombo = 0;
consecutiveMisses = 0;
createBoard();
}
// --- Game update (not used for logic here) ---
game.update = function () {
// No per-frame logic needed
};
// --- Start screen ---
var startScreen = new Container();
var titleTxt = new Text2('Animal Match', {
size: 180,
fill: "#fff"
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 2048 / 2;
titleTxt.y = 900;
startScreen.addChild(titleTxt);
var startBtn = new Container();
var btnBg = LK.getAsset('tileBack', {
anchorX: 0.5,
anchorY: 0.5
});
btnBg.width = 500;
btnBg.height = 180;
startBtn.addChild(btnBg);
var btnTxt = new Text2('Start', {
size: 110,
fill: 0x2E4D2C
});
btnTxt.anchor.set(0.5, 0.5);
btnTxt.x = 0;
btnTxt.y = 0;
startBtn.addChild(btnTxt);
startBtn.x = 2048 / 2;
startBtn.y = 1400;
startScreen.addChild(startBtn);
game.addChild(startScreen);
startBtn.down = function (x, y, obj) {
// Remove start screen and start the game
startScreen.destroy();
startGame();
};
// Hide UI until game starts
scoreTxt.visible = false;
heartsTxt.visible = false;
levelTxt.visible = false;
// Show UI when game starts
var _origStartGame = startGame;
startGame = function startGame() {
scoreTxt.visible = true;
heartsTxt.visible = true;
levelTxt.visible = true;
_origStartGame();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Tile class: represents a single memory tile
var Tile = Container.expand(function () {
var self = Container.call(this);
// Properties
self.isFlipped = false;
self.isMatched = false;
self.animalId = null; // Will be set on creation
// Create the back of the tile (hidden state)
var back = self.attachAsset('tileBack', {
anchorX: 0.5,
anchorY: 0.5
});
// Create the front of the tile (animal/plant)
var front = self.attachAsset('animal0', {
// Placeholder, will be replaced
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
self.back = back;
self.front = front;
// Set animal asset
self.setAnimal = function (animalId) {
self.animalId = animalId;
// Remove old front if exists
if (self.front) {
self.removeChild(self.front);
}
// Attach new front
self.front = self.attachAsset('animal' + animalId, {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
};
// Flip to show animal
self.flipUp = function () {
if (self.isFlipped || self.isMatched) return;
self.isFlipped = true;
// Play flip sound
LK.getSound('flip').play();
// Animate flip
tween(self, {
scaleX: 0
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
self.back.visible = false;
self.front.visible = true;
tween(self, {
scaleX: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
};
// Flip to hide animal
self.flipDown = function () {
if (!self.isFlipped || self.isMatched) return;
self.isFlipped = false;
// Play flip sound
LK.getSound('flip').play();
tween(self, {
scaleX: 0
}, {
duration: 100,
easing: tween.easeIn,
onFinish: function onFinish() {
self.front.visible = false;
self.back.visible = true;
tween(self, {
scaleX: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
});
};
// Mark as matched (permanently face up)
self.setMatched = function () {
self.isMatched = true;
self.isFlipped = true;
self.back.visible = false;
self.front.visible = true;
// Optional: animate a little pop
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeIn
});
}
});
};
// Handle tap
self.down = function (x, y, obj) {
if (self.isFlipped || self.isMatched || !canFlipTiles) return;
onTileFlipped(self);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2f4a01 // Changed to requested color #2f4a01
});
/****
* Game Code
****/
// Animal tile assets: numbers 0-10 for 10 levels (11 unique animals)
// --- Game variables ---
// Sound assets
var animalCount = 11; // Number of unique animals/plants (animal0 ... animal10)
var tileBackColor = 0x8db580; // Light green for tile back
var tileSize = 260; // px, square
var tilePadding = 32; // px
var minBoardMargin = 60; // px, margin from edge
var level = 1;
var hearts = 10;
var score = 0;
var combo = 0;
var maxCombo = 0;
var consecutiveMisses = 0;
var tiles = [];
var flippedTiles = [];
var canFlipTiles = true;
var pairsLeft = 0;
// --- UI elements ---
var scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var heartsTxt = new Text2('♥ 10', {
size: 90,
fill: 0xFF4D4D
});
heartsTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(heartsTxt);
heartsTxt.y = 120;
heartsTxt.x = 0;
var levelTxt = new Text2('Level 1', {
size: 90,
fill: 0xFFE066
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 220;
levelTxt.x = 0;
// --- Asset initialization (shapes for tile back, animal images) ---
for (var i = 0; i < animalCount; i++) {}
// --- Helper: shuffle array ---
function shuffle(arr) {
for (var i = arr.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
return arr;
}
// --- Helper: update UI ---
function updateUI() {
scoreTxt.setText(score);
heartsTxt.setText('♥ ' + hearts);
levelTxt.setText('Level ' + level);
}
// --- Helper: show all tiles for preview ---
function previewTiles(cb) {
canFlipTiles = false;
for (var i = 0; i < tiles.length; i++) {
tiles[i].flipUp();
}
LK.setTimeout(function () {
for (var i = 0; i < tiles.length; i++) {
tiles[i].flipDown();
}
canFlipTiles = true;
if (cb) cb();
}, 1200 + Math.min(600, level * 100));
}
// --- Helper: create board for current level ---
function createBoard() {
// Remove old tiles
for (var i = 0; i < tiles.length; i++) {
tiles[i].destroy();
}
tiles = [];
flippedTiles = [];
canFlipTiles = false;
// Determine number of tiles for this level
// Level 1: 4 tiles (2 pairs), then +2 tiles per level, up to level 10
var maxLevel = 10;
var cappedLevel = Math.min(level, maxLevel);
var tileCount = 4 + (cappedLevel - 1) * 2;
var pairCount = Math.floor(tileCount / 2);
if (pairCount > animalCount) pairCount = animalCount; // Cap to available animal assets
tileCount = pairCount * 2; // Ensure even number
// Find grid size (try to make as square as possible)
var cols = Math.ceil(Math.sqrt(tileCount));
var rows = Math.ceil(tileCount / cols);
// Prepare animal pairs
var animalIds = [];
for (var i = 0; i < pairCount; i++) {
animalIds.push(i);
animalIds.push(i);
}
shuffle(animalIds);
// Board centering
var boardW = cols * tileSize + (cols - 1) * tilePadding;
var boardH = rows * tileSize + (rows - 1) * tilePadding;
var startX = Math.floor((2048 - boardW) / 2) + tileSize / 2;
var startY = Math.floor((2732 - boardH) / 2) + tileSize / 2;
// Create tiles
var idx = 0;
for (var r = 0; r < rows; r++) {
for (var c = 0; c < cols; c++) {
if (idx >= animalIds.length) continue;
var tile = new Tile();
tile.setAnimal(animalIds[idx]);
tile.x = startX + c * (tileSize + tilePadding);
tile.y = startY + r * (tileSize + tilePadding);
tile.scaleX = 1;
tile.scaleY = 1;
game.addChild(tile);
tiles.push(tile);
idx++;
}
}
pairsLeft = pairCount;
updateUI();
previewTiles(function () {
canFlipTiles = true;
});
}
// --- Tile flip handler ---
function onTileFlipped(tile) {
if (!canFlipTiles) return;
if (tile.isFlipped || tile.isMatched) return;
tile.flipUp();
flippedTiles.push(tile);
if (flippedTiles.length === 2) {
canFlipTiles = false;
var t1 = flippedTiles[0];
var t2 = flippedTiles[1];
if (t1.animalId === t2.animalId) {
// Match!
LK.setTimeout(function () {
// Play match sound
LK.getSound('match').play();
t1.setMatched();
t2.setMatched();
pairsLeft--;
combo++;
maxCombo = Math.max(combo, maxCombo);
score += 10 * combo;
updateUI();
flippedTiles = [];
canFlipTiles = true;
consecutiveMisses = 0;
// Animate match
LK.effects.flashObject(t1, 0xFFFF99, 300);
LK.effects.flashObject(t2, 0xFFFF99, 300);
if (pairsLeft === 0) {
// Level complete!
LK.setTimeout(function () {
nextLevel();
}, 800);
}
}, 400);
} else {
// Not a match
LK.setTimeout(function () {
// Play error sound
LK.getSound('error').play();
t1.flipDown();
t2.flipDown();
flippedTiles = [];
canFlipTiles = true;
combo = 0;
consecutiveMisses++;
if (consecutiveMisses >= 3) {
hearts--;
consecutiveMisses = 0;
// Play lose heart sound
LK.getSound('loseHeart').play();
LK.effects.flashScreen(0xff0000, 400);
updateUI();
if (hearts <= 0) {
LK.showGameOver();
return;
}
}
updateUI();
}, 700);
}
}
}
// --- Next level ---
function nextLevel() {
level++;
// If player reaches level 10, they win!
if (level > 10) {
LK.showYouWin();
return;
}
// Reward: extra heart for levels > 3
if (level > 3) {
hearts++;
// Play gain heart sound
LK.getSound('gainHeart').play();
LK.effects.flashScreen(0x66ff66, 400);
}
combo = 0;
consecutiveMisses = 0;
createBoard();
}
// --- Start game ---
function startGame() {
level = 1;
hearts = 10;
score = 0;
combo = 0;
maxCombo = 0;
consecutiveMisses = 0;
createBoard();
}
// --- Game update (not used for logic here) ---
game.update = function () {
// No per-frame logic needed
};
// --- Start screen ---
var startScreen = new Container();
var titleTxt = new Text2('Animal Match', {
size: 180,
fill: "#fff"
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 2048 / 2;
titleTxt.y = 900;
startScreen.addChild(titleTxt);
var startBtn = new Container();
var btnBg = LK.getAsset('tileBack', {
anchorX: 0.5,
anchorY: 0.5
});
btnBg.width = 500;
btnBg.height = 180;
startBtn.addChild(btnBg);
var btnTxt = new Text2('Start', {
size: 110,
fill: 0x2E4D2C
});
btnTxt.anchor.set(0.5, 0.5);
btnTxt.x = 0;
btnTxt.y = 0;
startBtn.addChild(btnTxt);
startBtn.x = 2048 / 2;
startBtn.y = 1400;
startScreen.addChild(startBtn);
game.addChild(startScreen);
startBtn.down = function (x, y, obj) {
// Remove start screen and start the game
startScreen.destroy();
startGame();
};
// Hide UI until game starts
scoreTxt.visible = false;
heartsTxt.visible = false;
levelTxt.visible = false;
// Show UI when game starts
var _origStartGame = startGame;
startGame = function startGame() {
scoreTxt.visible = true;
heartsTxt.visible = true;
levelTxt.visible = true;
_origStartGame();
};
Put like a wooden background
Put like a wooden background
make the rabbit cartoony
Cartoon deer with plane wooden background. In-Game asset. 2d. High contrast. No shadows
Owl Image with wooden background. In-Game asset. 2d. High contrast. No shadows
A scary lion image with wooden background. In-Game asset. 2d. High contrast. No shadows
A tiger image, with wooden background. In-Game asset. 2d. High contrast. No shadows
A beaver with wooden background. In-Game asset. 2d. High contrast. No shadows
Racoon image with wooden background. In-Game asset. 2d. High contrast. No shadows
Moose pic with wooden background. In-Game asset. 2d. High contrast. No shadows
Bear with wooden background. In-Game asset. 2d. High contrast. No shadows
A Wooden square tile with dark borders. In-Game asset. 2d. High contrast. No shadows