/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Sound for when a meme reaches the bottom // No plugins needed for this version. // Class for the falling meme faces var FallingMeme = Container.expand(function (memeType, speed) { var self = Container.call(this); self.memeType = memeType; // Store the type (e.g., 'meme1', 'meme5') self.speed = speed; // Attach the corresponding meme image asset var memeGraphics = self.attachAsset(memeType, { anchorX: 0.5, anchorY: 0.5 }); self.assetWidth = memeGraphics.width; // Store dimensions for easier access self.assetHeight = memeGraphics.height; // Update function called by LK engine each frame self.update = function () { self.y += self.speed; // Update collision detection considering the current scale self.isOffScreen = function (gameHeight) { // Consider the meme off-screen if its top edge is past the bottom // Account for scaling return self.y - self.assetHeight * self.scale.y / 2 > gameHeight; }; }; // Method to check if the meme is off the bottom of the screen self.isOffScreen = function (gameHeight) { // Consider the meme off-screen if its top edge is past the bottom return self.y - self.assetHeight / 2 > gameHeight; }; return self; }); // Class for the buttons at the bottom var MemeButton = Container.expand(function (memeType) { var self = Container.call(this); self.memeType = memeType; // Store the type (e.g., 'meme1', 'meme5') // Attach the corresponding meme image asset var buttonGraphics = self.attachAsset(memeType, { anchorX: 0.5, anchorY: 0.5 // Removed scaling to make buttons 200x200 }); // Store dimensions for layout (now using full asset size) self.assetWidth = buttonGraphics.width; self.assetHeight = buttonGraphics.height; // Event handler for when the button is pressed // This will be automatically called by the LK engine if the button is attached self.down = function (x, y, obj) { // Find the lowest falling meme of the matching type var matchedMeme = null; var lowestY = -1; for (var i = 0; i < fallingMemes.length; i++) { var meme = fallingMemes[i]; if (meme.memeType === self.memeType && meme.y > lowestY) { lowestY = meme.y; matchedMeme = meme; } } // If a match was found if (matchedMeme) { // Remove the matched meme from the active array immediately so it can't be matched again var index = fallingMemes.indexOf(matchedMeme); if (index > -1) { fallingMemes.splice(index, 1); } // Animate the meme fading out tween(matchedMeme, { alpha: 0 }, { duration: 300, // 300ms fade duration easing: tween.easeOut, // Use an easing function onFinish: function onFinish() { // Destroy the game object *after* the animation completes if (matchedMeme && matchedMeme.destroy) { // Check if it wasn't already destroyed elsewhere matchedMeme.destroy(); } } }); // Increase score and update display var currentScore = LK.getScore() + 1; LK.setScore(currentScore); scoreTxt.setText(currentScore); // Check if a score milestone of 50 has been reached var currentMilestone = Math.floor(currentScore / 50) * 50; if (currentMilestone > lastScoreMilestone && currentMilestone > 0) { gameSpeed += 1; lastScoreMilestone = currentMilestone; console.log("Speed increased to: " + gameSpeed); // Optional: log speed increase } // --- Reveal new buttons based on score --- var targetVisibleButtons = 4 + Math.floor(currentScore / 20); while (visibleButtonCount < targetVisibleButtons && visibleButtonCount < buttons.length) { var nextButton = buttons[visibleButtonCount]; if (nextButton) { // Check if the button exists nextButton.visible = true; // Optional: Add a small visual effect when a button appears // nextButton.alpha = 0; // tween(nextButton, { alpha: 1 }, { duration: 200 }); } // --- Spawn the newly revealed meme immediately --- var newlyRevealedButton = buttons[visibleButtonCount]; if (newlyRevealedButton) { // Create a new falling meme instance for the revealed type var newMeme = new FallingMeme(newlyRevealedButton.memeType, gameSpeed); var assetWidth = newMeme.assetWidth; newMeme.x = Math.random() * (GAME_WIDTH - assetWidth) + assetWidth / 2; newMeme.y = -newMeme.assetHeight / 2; newMeme.lastY = newMeme.y; game.addChild(newMeme); fallingMemes.push(newMeme); } // --- End Immediate Spawn Logic --- visibleButtonCount++; } // --- End Reveal Logic --- // Construct the specific sound ID for this meme type var specificSoundId = self.memeType + 'matchsound1'; // Play the specific match sound LK.getSound(specificSoundId).play(); // Optional: Add a visual feedback like flashing the button LK.effects.flashObject(self, 0x00FF00, 200); // Flash green briefly } else { // Optional: Handle incorrect tap (e.g., small screen flash red, sound) // LK.effects.flashScreen(0xFF0000, 100); // LK.getSound('missSound').play(); // Potentially confusing with game over sound } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x111111 // Dark grey background }); /**** * Game Code ****/ // Game constants and variables // Initialize assets used in this game. Engine will automatically create if not present. // Assuming square meme images. Adjust width/height if needed. // Define 20 meme assets with placeholder shapes and colors // Red // Lime // Blue // Yellow // Magenta // Cyan // Orange // Purple // Green // Maroon // Navy // Olive // Teal // Silver // Gray // Khaki // Lavender // PeachPuff // LightBlue // LightGreen // Import tween plugin for animations var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var MEME_TYPES = ['meme1', 'meme2', 'meme3', 'meme4', 'meme5', 'meme6', 'meme7', 'meme8', 'meme9', 'meme10', 'meme11', 'meme12', 'meme13', 'meme14', 'meme15', 'meme16', 'meme17', 'meme18', 'meme19', 'meme20']; var INITIAL_SPEED = 5; var SPAWN_INTERVAL_TICKS = 90; // How often to spawn a new meme (90 ticks = 1.5 seconds at 60fps) var fallingMemes = []; // Array to hold active FallingMeme instances var scoreTxt; var gameSpeed = INITIAL_SPEED; var spawnCounter = 0; var lastScoreMilestone = 0; // Track the last score milestone for speed increase var visibleButtonCount = 4; // Start with the first 4 buttons visible // --- Background --- var background = game.attachAsset('Background0', { anchorX: 0.5, anchorY: 0.5 }); // Scale the background after it's attached and its dimensions are available background.scaleX = GAME_WIDTH / background.width; background.scaleY = GAME_HEIGHT / background.height; background.x = GAME_WIDTH / 2; background.y = GAME_HEIGHT / 2; // --- Score Display --- scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); // Anchor top-center // Position score text at the top-center using LK.gui LK.gui.top.addChild(scoreTxt); // Offset slightly down to avoid interfering with potential top-bar elements scoreTxt.y = 20; // --- Meme Buttons --- // Generate random size between 200 and 600 for memes function getRandomMemeSize() { return Math.floor(Math.random() * 401) + 200; // Random between 200 and 600 } // --- Helper function to spawn a single meme --- function spawnMeme(availableTypes) { var randomIndex = Math.floor(Math.random() * availableTypes.length); var newMemeType = availableTypes[randomIndex]; // Create a new falling meme instance var newMeme = new FallingMeme(newMemeType, gameSpeed); // Apply random size to the meme var randomSize = getRandomMemeSize(); newMeme.scale.set(randomSize / 200); // Scale based on original 200px size // Position it randomly across the top, avoiding edges slightly var scaledWidth = newMeme.assetWidth * newMeme.scale.x; // Calculate scaled width newMeme.x = Math.random() * (GAME_WIDTH - scaledWidth) + scaledWidth / 2; newMeme.y = -newMeme.assetHeight * newMeme.scale.y / 2; // Start just above the screen // Initialize last state tracking newMeme.lastY = newMeme.y; // Add to game stage and tracking array game.addChild(newMeme); fallingMemes.push(newMeme); } // --- Helper function to spawn two memes of the same type side-by-side --- function spawnDoubleMeme(memeType) { // Create a dummy instance to get dimensions (assuming all memes of a type have same dims) var tempMeme = new FallingMeme(memeType, 0); // Speed doesn't matter here var assetWidth = tempMeme.assetWidth; var assetHeight = tempMeme.assetHeight; tempMeme.destroy(); // Clean up the temporary meme // Generate random sizes for both memes var randomSize1 = getRandomMemeSize(); var randomSize2 = getRandomMemeSize(); var scale1 = randomSize1 / 200; var scale2 = randomSize2 / 200; // Calculate scaled dimensions var scaledWidth1 = assetWidth * scale1; var scaledWidth2 = assetWidth * scale2; var scaledHeight1 = assetHeight * scale1; var scaledHeight2 = assetHeight * scale2; var spacing = Math.max(scaledWidth1, scaledWidth2) + 20; // Width of the wider meme plus a small gap // Calculate the valid range for the center of the *left* meme (x1) var minX1 = scaledWidth1 / 2; var maxX1 = GAME_WIDTH - scaledWidth2 / 2 - spacing; // If the memes + spacing are wider than the screen, this calculation might result in minX1 > maxX1. if (minX1 > maxX1) { minX1 = scaledWidth1 / 2; maxX1 = GAME_WIDTH - scaledWidth2 / 2 - spacing; // Recalculate maxX1 based on the actual space needed // If still invalid, clamp if (minX1 > maxX1) { maxX1 = minX1; } } var x1 = Math.random() * (maxX1 - minX1) + minX1; var x2 = x1 + spacing; // Create the first meme with random size var meme1 = new FallingMeme(memeType, gameSpeed); meme1.scale.set(scale1); meme1.x = x1; meme1.y = -scaledHeight1 / 2; meme1.lastY = meme1.y; game.addChild(meme1); fallingMemes.push(meme1); // Create the second meme with random size var meme2 = new FallingMeme(memeType, gameSpeed); meme2.scale.set(scale2); meme2.x = x2; meme2.y = -scaledHeight2 / 2; // Start at the same height meme2.lastY = meme2.y; game.addChild(meme2); fallingMemes.push(meme2); } var buttons = []; var buttonPadding = 5; // Reduced padding as buttons are larger var buttonsPerRow = 10; var buttonRows = 2; var buttonAssetWidth = 200; // Set directly as we know the asset size var buttonAssetHeight = 200; // Set directly as we know the asset size // Create buttons first for (var i = 0; i < MEME_TYPES.length; i++) { var memeType = MEME_TYPES[i]; var button = new MemeButton(memeType); buttons.push(button); // No need to get dimensions here anymore, set statically above } // Calculate layout based on button dimensions and padding var totalWidthForRow = buttonAssetWidth * buttonsPerRow + buttonPadding * (buttonsPerRow - 1); var startX = (GAME_WIDTH - totalWidthForRow) / 2; var rowSpacing = buttonAssetHeight + 30; // Vertical space between rows var bottomRowY = GAME_HEIGHT - buttonAssetHeight / 2 - 50; // Position bottom row near the screen bottom var topRowY = bottomRowY - rowSpacing; // Position and add buttons in two rows for (var i = 0; i < buttons.length; i++) { var button = buttons[i]; var rowIndex = Math.floor(i / buttonsPerRow); // 0 for first row, 1 for second var colIndex = i % buttonsPerRow; // 0 to 9 for column in the row var currentX = startX + colIndex * (buttonAssetWidth + buttonPadding); button.x = currentX + button.assetWidth / 2; // Position based on center anchor if (rowIndex === 0) { button.y = topRowY; } else { button.y = bottomRowY; } // Hide buttons initially if they are beyond the starting visible count if (i >= visibleButtonCount) { button.visible = false; } game.addChild(button); } // --- Game Update Logic --- game.update = function () { spawnCounter++; // Spawn new memes periodically if (spawnCounter >= SPAWN_INTERVAL_TICKS) { spawnCounter = 0; // --- Select a meme type from the *visible* buttons --- var visibleMemeTypes = []; for (var k = 0; k < visibleButtonCount; k++) { if (buttons[k]) { // Ensure the button exists visibleMemeTypes.push(buttons[k].memeType); } } // Only spawn if there are visible types to choose from if (visibleMemeTypes.length > 0) { if (visibleButtonCount === MEME_TYPES.length) { // All buttons visible: Spawn a pair of the *same* meme type var randomIndex = Math.floor(Math.random() * visibleMemeTypes.length); var chosenMemeType = visibleMemeTypes[randomIndex]; spawnDoubleMeme(chosenMemeType); } else { // Not all buttons visible: Spawn a single random meme from the visible types spawnMeme(visibleMemeTypes); } } // --- End Spawn Logic Modification --- // Gradually increase difficulty (optional) // gameSpeed += 0.05; // SPAWN_INTERVAL_TICKS = Math.max(30, SPAWN_INTERVAL_TICKS * 0.995); // Decrease spawn interval slowly } // Update and check existing falling memes for (var i = fallingMemes.length - 1; i >= 0; i--) { var meme = fallingMemes[i]; // Update last position before moving if (meme.lastY === undefined) { meme.lastY = meme.y; } // Initialize if needed // Check if meme reached the bottom (transition detection) // Check if the bottom edge of the meme crosses the button line // Account for scaling when calculating bottom edge var bottomEdge = meme.y + meme.assetHeight * meme.scale.y / 2; var lastBottomEdge = meme.lastY + meme.assetHeight * meme.scale.y / 2; var boundaryY = bottomRowY - buttonAssetHeight / 2 - 20; // Line slightly above the *lower* row of buttons if (lastBottomEdge <= boundaryY && bottomEdge > boundaryY) { // Meme crossed the line - Game Over LK.getSound('missSound').play(); // Play miss sound LK.showGameOver(); // Trigger game over handled by LK engine // Important: showGameOver stops further execution of this game instance return; // Exit update loop as game is ending } // If it somehow got way past the screen (cleanup, although game over should trigger first) if (meme.isOffScreen(GAME_HEIGHT + 100)) { // This case should ideally not be reached due to game over check above meme.destroy(); fallingMemes.splice(i, 1); } // Update last known states meme.lastY = meme.y; } }; // Note: No need for game.down, game.up, game.move handlers for this specific game mechanic. // Button presses are handled by the MemeButton class's down method.; // Play background music LK.playMusic('Gamemusic1');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Sound for when a meme reaches the bottom
// No plugins needed for this version.
// Class for the falling meme faces
var FallingMeme = Container.expand(function (memeType, speed) {
var self = Container.call(this);
self.memeType = memeType; // Store the type (e.g., 'meme1', 'meme5')
self.speed = speed;
// Attach the corresponding meme image asset
var memeGraphics = self.attachAsset(memeType, {
anchorX: 0.5,
anchorY: 0.5
});
self.assetWidth = memeGraphics.width; // Store dimensions for easier access
self.assetHeight = memeGraphics.height;
// Update function called by LK engine each frame
self.update = function () {
self.y += self.speed;
// Update collision detection considering the current scale
self.isOffScreen = function (gameHeight) {
// Consider the meme off-screen if its top edge is past the bottom
// Account for scaling
return self.y - self.assetHeight * self.scale.y / 2 > gameHeight;
};
};
// Method to check if the meme is off the bottom of the screen
self.isOffScreen = function (gameHeight) {
// Consider the meme off-screen if its top edge is past the bottom
return self.y - self.assetHeight / 2 > gameHeight;
};
return self;
});
// Class for the buttons at the bottom
var MemeButton = Container.expand(function (memeType) {
var self = Container.call(this);
self.memeType = memeType; // Store the type (e.g., 'meme1', 'meme5')
// Attach the corresponding meme image asset
var buttonGraphics = self.attachAsset(memeType, {
anchorX: 0.5,
anchorY: 0.5
// Removed scaling to make buttons 200x200
});
// Store dimensions for layout (now using full asset size)
self.assetWidth = buttonGraphics.width;
self.assetHeight = buttonGraphics.height;
// Event handler for when the button is pressed
// This will be automatically called by the LK engine if the button is attached
self.down = function (x, y, obj) {
// Find the lowest falling meme of the matching type
var matchedMeme = null;
var lowestY = -1;
for (var i = 0; i < fallingMemes.length; i++) {
var meme = fallingMemes[i];
if (meme.memeType === self.memeType && meme.y > lowestY) {
lowestY = meme.y;
matchedMeme = meme;
}
}
// If a match was found
if (matchedMeme) {
// Remove the matched meme from the active array immediately so it can't be matched again
var index = fallingMemes.indexOf(matchedMeme);
if (index > -1) {
fallingMemes.splice(index, 1);
}
// Animate the meme fading out
tween(matchedMeme, {
alpha: 0
}, {
duration: 300,
// 300ms fade duration
easing: tween.easeOut,
// Use an easing function
onFinish: function onFinish() {
// Destroy the game object *after* the animation completes
if (matchedMeme && matchedMeme.destroy) {
// Check if it wasn't already destroyed elsewhere
matchedMeme.destroy();
}
}
});
// Increase score and update display
var currentScore = LK.getScore() + 1;
LK.setScore(currentScore);
scoreTxt.setText(currentScore);
// Check if a score milestone of 50 has been reached
var currentMilestone = Math.floor(currentScore / 50) * 50;
if (currentMilestone > lastScoreMilestone && currentMilestone > 0) {
gameSpeed += 1;
lastScoreMilestone = currentMilestone;
console.log("Speed increased to: " + gameSpeed); // Optional: log speed increase
}
// --- Reveal new buttons based on score ---
var targetVisibleButtons = 4 + Math.floor(currentScore / 20);
while (visibleButtonCount < targetVisibleButtons && visibleButtonCount < buttons.length) {
var nextButton = buttons[visibleButtonCount];
if (nextButton) {
// Check if the button exists
nextButton.visible = true;
// Optional: Add a small visual effect when a button appears
// nextButton.alpha = 0;
// tween(nextButton, { alpha: 1 }, { duration: 200 });
}
// --- Spawn the newly revealed meme immediately ---
var newlyRevealedButton = buttons[visibleButtonCount];
if (newlyRevealedButton) {
// Create a new falling meme instance for the revealed type
var newMeme = new FallingMeme(newlyRevealedButton.memeType, gameSpeed);
var assetWidth = newMeme.assetWidth;
newMeme.x = Math.random() * (GAME_WIDTH - assetWidth) + assetWidth / 2;
newMeme.y = -newMeme.assetHeight / 2;
newMeme.lastY = newMeme.y;
game.addChild(newMeme);
fallingMemes.push(newMeme);
}
// --- End Immediate Spawn Logic ---
visibleButtonCount++;
}
// --- End Reveal Logic ---
// Construct the specific sound ID for this meme type
var specificSoundId = self.memeType + 'matchsound1';
// Play the specific match sound
LK.getSound(specificSoundId).play();
// Optional: Add a visual feedback like flashing the button
LK.effects.flashObject(self, 0x00FF00, 200); // Flash green briefly
} else {
// Optional: Handle incorrect tap (e.g., small screen flash red, sound)
// LK.effects.flashScreen(0xFF0000, 100);
// LK.getSound('missSound').play(); // Potentially confusing with game over sound
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111 // Dark grey background
});
/****
* Game Code
****/
// Game constants and variables
// Initialize assets used in this game. Engine will automatically create if not present.
// Assuming square meme images. Adjust width/height if needed.
// Define 20 meme assets with placeholder shapes and colors
// Red
// Lime
// Blue
// Yellow
// Magenta
// Cyan
// Orange
// Purple
// Green
// Maroon
// Navy
// Olive
// Teal
// Silver
// Gray
// Khaki
// Lavender
// PeachPuff
// LightBlue
// LightGreen
// Import tween plugin for animations
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var MEME_TYPES = ['meme1', 'meme2', 'meme3', 'meme4', 'meme5', 'meme6', 'meme7', 'meme8', 'meme9', 'meme10', 'meme11', 'meme12', 'meme13', 'meme14', 'meme15', 'meme16', 'meme17', 'meme18', 'meme19', 'meme20'];
var INITIAL_SPEED = 5;
var SPAWN_INTERVAL_TICKS = 90; // How often to spawn a new meme (90 ticks = 1.5 seconds at 60fps)
var fallingMemes = []; // Array to hold active FallingMeme instances
var scoreTxt;
var gameSpeed = INITIAL_SPEED;
var spawnCounter = 0;
var lastScoreMilestone = 0; // Track the last score milestone for speed increase
var visibleButtonCount = 4; // Start with the first 4 buttons visible
// --- Background ---
var background = game.attachAsset('Background0', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale the background after it's attached and its dimensions are available
background.scaleX = GAME_WIDTH / background.width;
background.scaleY = GAME_HEIGHT / background.height;
background.x = GAME_WIDTH / 2;
background.y = GAME_HEIGHT / 2;
// --- Score Display ---
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0); // Anchor top-center
// Position score text at the top-center using LK.gui
LK.gui.top.addChild(scoreTxt);
// Offset slightly down to avoid interfering with potential top-bar elements
scoreTxt.y = 20;
// --- Meme Buttons ---
// Generate random size between 200 and 600 for memes
function getRandomMemeSize() {
return Math.floor(Math.random() * 401) + 200; // Random between 200 and 600
}
// --- Helper function to spawn a single meme ---
function spawnMeme(availableTypes) {
var randomIndex = Math.floor(Math.random() * availableTypes.length);
var newMemeType = availableTypes[randomIndex];
// Create a new falling meme instance
var newMeme = new FallingMeme(newMemeType, gameSpeed);
// Apply random size to the meme
var randomSize = getRandomMemeSize();
newMeme.scale.set(randomSize / 200); // Scale based on original 200px size
// Position it randomly across the top, avoiding edges slightly
var scaledWidth = newMeme.assetWidth * newMeme.scale.x; // Calculate scaled width
newMeme.x = Math.random() * (GAME_WIDTH - scaledWidth) + scaledWidth / 2;
newMeme.y = -newMeme.assetHeight * newMeme.scale.y / 2; // Start just above the screen
// Initialize last state tracking
newMeme.lastY = newMeme.y;
// Add to game stage and tracking array
game.addChild(newMeme);
fallingMemes.push(newMeme);
}
// --- Helper function to spawn two memes of the same type side-by-side ---
function spawnDoubleMeme(memeType) {
// Create a dummy instance to get dimensions (assuming all memes of a type have same dims)
var tempMeme = new FallingMeme(memeType, 0); // Speed doesn't matter here
var assetWidth = tempMeme.assetWidth;
var assetHeight = tempMeme.assetHeight;
tempMeme.destroy(); // Clean up the temporary meme
// Generate random sizes for both memes
var randomSize1 = getRandomMemeSize();
var randomSize2 = getRandomMemeSize();
var scale1 = randomSize1 / 200;
var scale2 = randomSize2 / 200;
// Calculate scaled dimensions
var scaledWidth1 = assetWidth * scale1;
var scaledWidth2 = assetWidth * scale2;
var scaledHeight1 = assetHeight * scale1;
var scaledHeight2 = assetHeight * scale2;
var spacing = Math.max(scaledWidth1, scaledWidth2) + 20; // Width of the wider meme plus a small gap
// Calculate the valid range for the center of the *left* meme (x1)
var minX1 = scaledWidth1 / 2;
var maxX1 = GAME_WIDTH - scaledWidth2 / 2 - spacing;
// If the memes + spacing are wider than the screen, this calculation might result in minX1 > maxX1.
if (minX1 > maxX1) {
minX1 = scaledWidth1 / 2;
maxX1 = GAME_WIDTH - scaledWidth2 / 2 - spacing; // Recalculate maxX1 based on the actual space needed
// If still invalid, clamp
if (minX1 > maxX1) {
maxX1 = minX1;
}
}
var x1 = Math.random() * (maxX1 - minX1) + minX1;
var x2 = x1 + spacing;
// Create the first meme with random size
var meme1 = new FallingMeme(memeType, gameSpeed);
meme1.scale.set(scale1);
meme1.x = x1;
meme1.y = -scaledHeight1 / 2;
meme1.lastY = meme1.y;
game.addChild(meme1);
fallingMemes.push(meme1);
// Create the second meme with random size
var meme2 = new FallingMeme(memeType, gameSpeed);
meme2.scale.set(scale2);
meme2.x = x2;
meme2.y = -scaledHeight2 / 2; // Start at the same height
meme2.lastY = meme2.y;
game.addChild(meme2);
fallingMemes.push(meme2);
}
var buttons = [];
var buttonPadding = 5; // Reduced padding as buttons are larger
var buttonsPerRow = 10;
var buttonRows = 2;
var buttonAssetWidth = 200; // Set directly as we know the asset size
var buttonAssetHeight = 200; // Set directly as we know the asset size
// Create buttons first
for (var i = 0; i < MEME_TYPES.length; i++) {
var memeType = MEME_TYPES[i];
var button = new MemeButton(memeType);
buttons.push(button);
// No need to get dimensions here anymore, set statically above
}
// Calculate layout based on button dimensions and padding
var totalWidthForRow = buttonAssetWidth * buttonsPerRow + buttonPadding * (buttonsPerRow - 1);
var startX = (GAME_WIDTH - totalWidthForRow) / 2;
var rowSpacing = buttonAssetHeight + 30; // Vertical space between rows
var bottomRowY = GAME_HEIGHT - buttonAssetHeight / 2 - 50; // Position bottom row near the screen bottom
var topRowY = bottomRowY - rowSpacing;
// Position and add buttons in two rows
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
var rowIndex = Math.floor(i / buttonsPerRow); // 0 for first row, 1 for second
var colIndex = i % buttonsPerRow; // 0 to 9 for column in the row
var currentX = startX + colIndex * (buttonAssetWidth + buttonPadding);
button.x = currentX + button.assetWidth / 2; // Position based on center anchor
if (rowIndex === 0) {
button.y = topRowY;
} else {
button.y = bottomRowY;
}
// Hide buttons initially if they are beyond the starting visible count
if (i >= visibleButtonCount) {
button.visible = false;
}
game.addChild(button);
}
// --- Game Update Logic ---
game.update = function () {
spawnCounter++;
// Spawn new memes periodically
if (spawnCounter >= SPAWN_INTERVAL_TICKS) {
spawnCounter = 0;
// --- Select a meme type from the *visible* buttons ---
var visibleMemeTypes = [];
for (var k = 0; k < visibleButtonCount; k++) {
if (buttons[k]) {
// Ensure the button exists
visibleMemeTypes.push(buttons[k].memeType);
}
}
// Only spawn if there are visible types to choose from
if (visibleMemeTypes.length > 0) {
if (visibleButtonCount === MEME_TYPES.length) {
// All buttons visible: Spawn a pair of the *same* meme type
var randomIndex = Math.floor(Math.random() * visibleMemeTypes.length);
var chosenMemeType = visibleMemeTypes[randomIndex];
spawnDoubleMeme(chosenMemeType);
} else {
// Not all buttons visible: Spawn a single random meme from the visible types
spawnMeme(visibleMemeTypes);
}
}
// --- End Spawn Logic Modification ---
// Gradually increase difficulty (optional)
// gameSpeed += 0.05;
// SPAWN_INTERVAL_TICKS = Math.max(30, SPAWN_INTERVAL_TICKS * 0.995); // Decrease spawn interval slowly
}
// Update and check existing falling memes
for (var i = fallingMemes.length - 1; i >= 0; i--) {
var meme = fallingMemes[i];
// Update last position before moving
if (meme.lastY === undefined) {
meme.lastY = meme.y;
} // Initialize if needed
// Check if meme reached the bottom (transition detection)
// Check if the bottom edge of the meme crosses the button line
// Account for scaling when calculating bottom edge
var bottomEdge = meme.y + meme.assetHeight * meme.scale.y / 2;
var lastBottomEdge = meme.lastY + meme.assetHeight * meme.scale.y / 2;
var boundaryY = bottomRowY - buttonAssetHeight / 2 - 20; // Line slightly above the *lower* row of buttons
if (lastBottomEdge <= boundaryY && bottomEdge > boundaryY) {
// Meme crossed the line - Game Over
LK.getSound('missSound').play(); // Play miss sound
LK.showGameOver(); // Trigger game over handled by LK engine
// Important: showGameOver stops further execution of this game instance
return; // Exit update loop as game is ending
}
// If it somehow got way past the screen (cleanup, although game over should trigger first)
if (meme.isOffScreen(GAME_HEIGHT + 100)) {
// This case should ideally not be reached due to game over check above
meme.destroy();
fallingMemes.splice(i, 1);
}
// Update last known states
meme.lastY = meme.y;
}
};
// Note: No need for game.down, game.up, game.move handlers for this specific game mechanic.
// Button presses are handled by the MemeButton class's down method.;
// Play background music
LK.playMusic('Gamemusic1');
Same face in the image but 3D
3D Scary trollface meme. In-Game asset. 3D. High contrast. No shadows
3D jeff the killer Scary face meme. In-Game asset. 3D. High contrast. No shadows
3D Scary face meme "Terrifier3" from the movie, face only In-Game asset. 3D. High contrast. No shadows. face only
3D Scary but funny annabelle doll face meme. In-Game asset. 3D. High contrast. No shadows
3D Scary face meme samara have green face. only face. normal eyes no so opened. smile In-Game asset. High contrast. 3D. No shadows. only face
3D Scary room with many 3D decorations around, 3D scary masks of memes around it. In-Game asset. 3D. High contrast. No shadows. no jesus cross. no star of 6. no start of 5. no devil. HD colors
3D Scary but funny meme face of momo. face only. different faces look In-Game asset. 3d. High contrast. No shadows
Gamemusic1
Music
meme1matchsound1
Sound effect
meme2matchsound1
Sound effect
meme3matchsound1
Sound effect
meme4matchsound1
Sound effect
meme5matchsound1
Sound effect
meme6matchsound1
Sound effect
meme7matchsound1
Sound effect
meme8matchsound1
Sound effect
meme9matchsound1
Sound effect
meme10matchsound1
Sound effect
meme11matchsound1
Sound effect
meme12matchsound1
Sound effect
meme13matchsound1
Sound effect
meme14matchsound1
Sound effect
meme15matchsound1
Sound effect
meme16matchsound1
Sound effect
meme17matchsound1
Sound effect
meme18matchsound1
Sound effect
meme19matchsound1
Sound effect
meme20matchsound1
Sound effect
missSound
Sound effect