Code edit (1 edits merged)
Please save this source code
User prompt
Color Match Rush
Initial prompt
yes I want Color Match Rush is a fast-paced puzzle game where players match falling colored blocks with corresponding target zones at the bottom of the screen. As blocks fall from the top, players must swipe them into matching color zones before they reach the bottom. Each successful match adds to the score, while mismatches deduct points. The game increases in difficulty with faster falling blocks, color-changing blocks, and special power-ups that can clear multiple blocks at once. Players race against time to achieve the highest score possible before the difficulty becomes overwhelming.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Block = Container.expand(function (colorType) { var self = Container.call(this); self.colorType = colorType; self.isMatched = false; self.isDragging = false; self.velocity = { x: 0, y: 2 + Math.random() * 2 }; // Random initial falling speed // Colors map var colorMap = { 'red': 'redBlock', 'blue': 'blueBlock', 'green': 'greenBlock', 'yellow': 'yellowBlock' }; // Create and attach the block graphics self.blockGraphics = self.attachAsset(colorMap[colorType], { anchorX: 0.5, anchorY: 0.5 }); // Set initial alpha slightly transparent self.blockGraphics.alpha = 0.9; // Handle touch/mouse events self.down = function (x, y, obj) { self.isDragging = true; // Store initial touch position for swipe calculation self.touchStartX = x; self.touchStartY = y; }; self.up = function (x, y, obj) { if (self.isDragging) { // Calculate swipe direction var deltaX = x - self.touchStartX; var deltaY = y - self.touchStartY; // Apply a velocity based on swipe if (Math.abs(deltaX) > 20) { // Minimum swipe threshold self.velocity.x = deltaX / 10; // Scale down swipe to reasonable velocity } self.isDragging = false; } }; self.update = function () { if (!self.isMatched) { // Apply gravity and movement self.y += self.velocity.y; self.x += self.velocity.x; // Slow down horizontal velocity (drag) self.velocity.x *= 0.95; // Keep block within game boundaries if (self.x < 75) { self.x = 75; self.velocity.x *= -0.5; // Bounce off wall with reduced speed } else if (self.x > 2048 - 75) { self.x = 2048 - 75; self.velocity.x *= -0.5; // Bounce off wall with reduced speed } } }; return self; }); var TargetZone = Container.expand(function (colorType, position) { var self = Container.call(this); self.colorType = colorType; self.position = position; // Create and attach target zone base var zoneBase = self.attachAsset('targetZone', { anchorX: 0.5, anchorY: 0.5 }); // Set alpha for better visibility zoneBase.alpha = 0.5; // Tint the zone to match its color type switch (colorType) { case 'red': zoneBase.tint = 0xff0000; break; case 'blue': zoneBase.tint = 0x0000ff; break; case 'green': zoneBase.tint = 0x00ff00; break; case 'yellow': zoneBase.tint = 0xffff00; break; } // Add label to identify target var label = new Text2(colorType.toUpperCase(), { size: 40, fill: 0xFFFFFF }); label.anchor.set(0.5, 0.5); self.addChild(label); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x333333 }); /**** * Game Code ****/ // Game variables var blocks = []; var targetZones = []; var score = 0; var level = 1; var spawnInterval = 2000; // Time in ms between block spawns var gameOver = false; var colors = ['red', 'blue', 'green', 'yellow']; // Initialize game function initGame() { // Set up score text var scoreTxt = new Text2('Score: 0', { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 50; // Add some padding from the top // Set up level indicator var levelTxt = new Text2('Level: 1', { size: 40, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); LK.gui.topRight.addChild(levelTxt); levelTxt.x = -150; // Offset from right edge levelTxt.y = 30; // Add some padding from the top // Create target zones createTargetZones(); // Start spawning blocks startBlockSpawner(); // Play background music LK.playMusic('gameMusic', { fade: { start: 0, end: 0.7, duration: 1000 } }); } // Create the target zones at the bottom of the screen function createTargetZones() { var zoneWidth = 300; var totalWidth = zoneWidth * colors.length; var startX = (2048 - totalWidth) / 2 + zoneWidth / 2; for (var i = 0; i < colors.length; i++) { var zone = new TargetZone(colors[i], i); zone.x = startX + i * zoneWidth; zone.y = 2732 - 100; // Position near bottom targetZones.push(zone); game.addChild(zone); } } // Start the block spawner timer function startBlockSpawner() { // Spawn a block immediately spawnBlock(); // Set up interval for continued spawning var spawner = LK.setInterval(function () { if (!gameOver) { spawnBlock(); } }, spawnInterval); } // Spawn a new block function spawnBlock() { var colorIndex = Math.floor(Math.random() * colors.length); var newBlock = new Block(colors[colorIndex]); // Position randomly along the top newBlock.x = 200 + Math.random() * (2048 - 400); newBlock.y = -75; // Start above the screen blocks.push(newBlock); game.addChild(newBlock); } // Check for matches between blocks and target zones function checkMatches() { for (var i = blocks.length - 1; i >= 0; i--) { var block = blocks[i]; // Skip if already matched if (block.isMatched) { continue; } // Check if the block is at the bottom of the screen if (block.y >= 2732 - 200) { // Check for matches with target zones var matched = false; for (var j = 0; j < targetZones.length; j++) { var zone = targetZones[j]; if (block.intersects(zone)) { // Check if colors match if (block.colorType === zone.colorType) { // Match! Add score score += 10; matched = true; // Play match sound LK.getSound('match').play(); // Visual feedback for match LK.effects.flashObject(block, 0xFFFFFF, 300); tween(block, { alpha: 0, scaleX: 0.2, scaleY: 0.2 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { block.destroy(); blocks.splice(i, 1); } }); } else { // Mismatch! Subtract score score = Math.max(0, score - 5); matched = true; // Play mismatch sound LK.getSound('mismatch').play(); // Visual feedback for mismatch LK.effects.flashObject(block, 0xFF0000, 300); tween(block, { alpha: 0, rotation: Math.PI * 2 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { block.destroy(); blocks.splice(i, 1); } }); } // Mark as matched so we don't process it again block.isMatched = true; break; } } // If block reached bottom but didn't match any zone if (!matched && block.y >= 2732) { // Penalty for missing score = Math.max(0, score - 3); // Visual feedback tween(block, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { block.destroy(); blocks.splice(i, 1); } }); } } } // Update score display updateScoreAndLevel(); } // Update the score and level display function updateScoreAndLevel() { // Update score text var scoreTxt = LK.gui.top.children[0]; scoreTxt.setText('Score: ' + score); // Check for level up (every 100 points) var newLevel = Math.floor(score / 100) + 1; if (newLevel > level) { level = newLevel; var levelTxt = LK.gui.topRight.children[0]; levelTxt.setText('Level: ' + level); // Increase difficulty spawnInterval = Math.max(500, 2000 - (level - 1) * 200); // Visual feedback for level up LK.effects.flashScreen(0x00FF00, 500); } // Set the official score in LK LK.setScore(score); // Check win condition (level 10 reached) if (level >= 10) { LK.showYouWin(); } } // Check if game is over (too many blocks on screen) function checkGameOver() { // Count active blocks var activeBlocks = 0; for (var i = 0; i < blocks.length; i++) { if (!blocks[i].isMatched) { activeBlocks++; } } // If too many active blocks, game over if (activeBlocks >= 15) { gameOver = true; LK.showGameOver(); } } // Track dragging var draggedBlock = null; // Game event handlers game.down = function (x, y, obj) { // Check if we clicked on a block for (var i = blocks.length - 1; i >= 0; i--) { var block = blocks[i]; var blockPos = { x: block.x, y: block.y }; var localPos = game.toLocal(blockPos); // Check if click is within block bounds if (Math.abs(x - localPos.x) < 75 && Math.abs(y - localPos.y) < 75) { draggedBlock = block; block.down(x, y, obj); break; } } }; game.up = function (x, y, obj) { if (draggedBlock) { draggedBlock.up(x, y, obj); draggedBlock = null; } }; game.move = function (x, y, obj) { if (draggedBlock) { // Calculate movement relative to game var deltaX = x - draggedBlock.touchStartX; // Apply horizontal movement only (vertical falls automatically) draggedBlock.x += deltaX; // Update start position for next move draggedBlock.touchStartX = x; } }; // Main game update loop game.update = function () { if (!gameOver) { // Update all blocks for (var i = 0; i < blocks.length; i++) { blocks[i].update(); } // Check for matches and update score checkMatches(); // Check for game over condition checkGameOver(); // Increase difficulty over time by adjusting block fall speed if (LK.ticks % 600 === 0) { // Every 10 seconds for (var i = 0; i < blocks.length; i++) { blocks[i].velocity.y *= 1.05; // 5% increase in speed } } } }; // Initialize the game initGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Block = Container.expand(function (colorType) {
var self = Container.call(this);
self.colorType = colorType;
self.isMatched = false;
self.isDragging = false;
self.velocity = {
x: 0,
y: 2 + Math.random() * 2
}; // Random initial falling speed
// Colors map
var colorMap = {
'red': 'redBlock',
'blue': 'blueBlock',
'green': 'greenBlock',
'yellow': 'yellowBlock'
};
// Create and attach the block graphics
self.blockGraphics = self.attachAsset(colorMap[colorType], {
anchorX: 0.5,
anchorY: 0.5
});
// Set initial alpha slightly transparent
self.blockGraphics.alpha = 0.9;
// Handle touch/mouse events
self.down = function (x, y, obj) {
self.isDragging = true;
// Store initial touch position for swipe calculation
self.touchStartX = x;
self.touchStartY = y;
};
self.up = function (x, y, obj) {
if (self.isDragging) {
// Calculate swipe direction
var deltaX = x - self.touchStartX;
var deltaY = y - self.touchStartY;
// Apply a velocity based on swipe
if (Math.abs(deltaX) > 20) {
// Minimum swipe threshold
self.velocity.x = deltaX / 10; // Scale down swipe to reasonable velocity
}
self.isDragging = false;
}
};
self.update = function () {
if (!self.isMatched) {
// Apply gravity and movement
self.y += self.velocity.y;
self.x += self.velocity.x;
// Slow down horizontal velocity (drag)
self.velocity.x *= 0.95;
// Keep block within game boundaries
if (self.x < 75) {
self.x = 75;
self.velocity.x *= -0.5; // Bounce off wall with reduced speed
} else if (self.x > 2048 - 75) {
self.x = 2048 - 75;
self.velocity.x *= -0.5; // Bounce off wall with reduced speed
}
}
};
return self;
});
var TargetZone = Container.expand(function (colorType, position) {
var self = Container.call(this);
self.colorType = colorType;
self.position = position;
// Create and attach target zone base
var zoneBase = self.attachAsset('targetZone', {
anchorX: 0.5,
anchorY: 0.5
});
// Set alpha for better visibility
zoneBase.alpha = 0.5;
// Tint the zone to match its color type
switch (colorType) {
case 'red':
zoneBase.tint = 0xff0000;
break;
case 'blue':
zoneBase.tint = 0x0000ff;
break;
case 'green':
zoneBase.tint = 0x00ff00;
break;
case 'yellow':
zoneBase.tint = 0xffff00;
break;
}
// Add label to identify target
var label = new Text2(colorType.toUpperCase(), {
size: 40,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x333333
});
/****
* Game Code
****/
// Game variables
var blocks = [];
var targetZones = [];
var score = 0;
var level = 1;
var spawnInterval = 2000; // Time in ms between block spawns
var gameOver = false;
var colors = ['red', 'blue', 'green', 'yellow'];
// Initialize game
function initGame() {
// Set up score text
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50; // Add some padding from the top
// Set up level indicator
var levelTxt = new Text2('Level: 1', {
size: 40,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topRight.addChild(levelTxt);
levelTxt.x = -150; // Offset from right edge
levelTxt.y = 30; // Add some padding from the top
// Create target zones
createTargetZones();
// Start spawning blocks
startBlockSpawner();
// Play background music
LK.playMusic('gameMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
// Create the target zones at the bottom of the screen
function createTargetZones() {
var zoneWidth = 300;
var totalWidth = zoneWidth * colors.length;
var startX = (2048 - totalWidth) / 2 + zoneWidth / 2;
for (var i = 0; i < colors.length; i++) {
var zone = new TargetZone(colors[i], i);
zone.x = startX + i * zoneWidth;
zone.y = 2732 - 100; // Position near bottom
targetZones.push(zone);
game.addChild(zone);
}
}
// Start the block spawner timer
function startBlockSpawner() {
// Spawn a block immediately
spawnBlock();
// Set up interval for continued spawning
var spawner = LK.setInterval(function () {
if (!gameOver) {
spawnBlock();
}
}, spawnInterval);
}
// Spawn a new block
function spawnBlock() {
var colorIndex = Math.floor(Math.random() * colors.length);
var newBlock = new Block(colors[colorIndex]);
// Position randomly along the top
newBlock.x = 200 + Math.random() * (2048 - 400);
newBlock.y = -75; // Start above the screen
blocks.push(newBlock);
game.addChild(newBlock);
}
// Check for matches between blocks and target zones
function checkMatches() {
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
// Skip if already matched
if (block.isMatched) {
continue;
}
// Check if the block is at the bottom of the screen
if (block.y >= 2732 - 200) {
// Check for matches with target zones
var matched = false;
for (var j = 0; j < targetZones.length; j++) {
var zone = targetZones[j];
if (block.intersects(zone)) {
// Check if colors match
if (block.colorType === zone.colorType) {
// Match! Add score
score += 10;
matched = true;
// Play match sound
LK.getSound('match').play();
// Visual feedback for match
LK.effects.flashObject(block, 0xFFFFFF, 300);
tween(block, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
block.destroy();
blocks.splice(i, 1);
}
});
} else {
// Mismatch! Subtract score
score = Math.max(0, score - 5);
matched = true;
// Play mismatch sound
LK.getSound('mismatch').play();
// Visual feedback for mismatch
LK.effects.flashObject(block, 0xFF0000, 300);
tween(block, {
alpha: 0,
rotation: Math.PI * 2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
block.destroy();
blocks.splice(i, 1);
}
});
}
// Mark as matched so we don't process it again
block.isMatched = true;
break;
}
}
// If block reached bottom but didn't match any zone
if (!matched && block.y >= 2732) {
// Penalty for missing
score = Math.max(0, score - 3);
// Visual feedback
tween(block, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
block.destroy();
blocks.splice(i, 1);
}
});
}
}
}
// Update score display
updateScoreAndLevel();
}
// Update the score and level display
function updateScoreAndLevel() {
// Update score text
var scoreTxt = LK.gui.top.children[0];
scoreTxt.setText('Score: ' + score);
// Check for level up (every 100 points)
var newLevel = Math.floor(score / 100) + 1;
if (newLevel > level) {
level = newLevel;
var levelTxt = LK.gui.topRight.children[0];
levelTxt.setText('Level: ' + level);
// Increase difficulty
spawnInterval = Math.max(500, 2000 - (level - 1) * 200);
// Visual feedback for level up
LK.effects.flashScreen(0x00FF00, 500);
}
// Set the official score in LK
LK.setScore(score);
// Check win condition (level 10 reached)
if (level >= 10) {
LK.showYouWin();
}
}
// Check if game is over (too many blocks on screen)
function checkGameOver() {
// Count active blocks
var activeBlocks = 0;
for (var i = 0; i < blocks.length; i++) {
if (!blocks[i].isMatched) {
activeBlocks++;
}
}
// If too many active blocks, game over
if (activeBlocks >= 15) {
gameOver = true;
LK.showGameOver();
}
}
// Track dragging
var draggedBlock = null;
// Game event handlers
game.down = function (x, y, obj) {
// Check if we clicked on a block
for (var i = blocks.length - 1; i >= 0; i--) {
var block = blocks[i];
var blockPos = {
x: block.x,
y: block.y
};
var localPos = game.toLocal(blockPos);
// Check if click is within block bounds
if (Math.abs(x - localPos.x) < 75 && Math.abs(y - localPos.y) < 75) {
draggedBlock = block;
block.down(x, y, obj);
break;
}
}
};
game.up = function (x, y, obj) {
if (draggedBlock) {
draggedBlock.up(x, y, obj);
draggedBlock = null;
}
};
game.move = function (x, y, obj) {
if (draggedBlock) {
// Calculate movement relative to game
var deltaX = x - draggedBlock.touchStartX;
// Apply horizontal movement only (vertical falls automatically)
draggedBlock.x += deltaX;
// Update start position for next move
draggedBlock.touchStartX = x;
}
};
// Main game update loop
game.update = function () {
if (!gameOver) {
// Update all blocks
for (var i = 0; i < blocks.length; i++) {
blocks[i].update();
}
// Check for matches and update score
checkMatches();
// Check for game over condition
checkGameOver();
// Increase difficulty over time by adjusting block fall speed
if (LK.ticks % 600 === 0) {
// Every 10 seconds
for (var i = 0; i < blocks.length; i++) {
blocks[i].velocity.y *= 1.05; // 5% increase in speed
}
}
}
};
// Initialize the game
initGame();