User prompt
Make effects more visible ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Gem Crusher: Epic Match 3 Mayhem
Initial prompt
Make a matc 3 game with screen shakes and massive effects.make the game fit the canvas
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Gem = Container.expand(function () {
var self = Container.call(this);
self.init = function (type, row, col) {
self.gemType = type;
self.row = row;
self.col = col;
self.isMatched = false;
self.isAnimating = false;
var gemAssets = ['gem_red', 'gem_blue', 'gem_green', 'gem_yellow', 'gem_purple', 'gem_orange'];
var gemGraphics = self.attachAsset(gemAssets[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.x = col * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_X;
self.y = row * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_Y;
};
self.animateTo = function (targetX, targetY, duration, onComplete) {
self.isAnimating = true;
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration || 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isAnimating = false;
if (onComplete) onComplete();
}
});
};
self.explode = function () {
for (var i = 0; i < 8; i++) {
var particle = new Particle();
particle.x = self.x;
particle.y = self.y;
particle.explode(Math.random() * Math.PI * 2, 100 + Math.random() * 100);
game.addChild(particle);
particles.push(particle);
}
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.life = 60;
self.maxLife = 60;
self.explode = function (angle, speed) {
self.velocityX = Math.cos(angle) * speed;
self.velocityY = Math.sin(angle) * speed;
};
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityX *= 0.95;
self.velocityY *= 0.95;
self.velocityY += 2; // gravity
self.life--;
self.alpha = self.life / self.maxLife;
if (self.life <= 0) {
self.destroy();
for (var i = particles.length - 1; i >= 0; i--) {
if (particles[i] === self) {
particles.splice(i, 1);
break;
}
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var GRID_ROWS = 10;
var GRID_COLS = 8;
var GEM_SIZE = 256;
var BOARD_OFFSET_X = (2048 - GRID_COLS * GEM_SIZE) / 2;
var BOARD_OFFSET_Y = 100;
var grid = [];
var selectedGem = null;
var isProcessing = false;
var particles = [];
var comboMultiplier = 1;
var shakeIntensity = 0;
var shakeDecay = 0.9;
// Initialize score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// Initialize combo display
var comboTxt = new Text2('', {
size: 80,
fill: 0xFFFF00
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.y = 180;
function initializeGrid() {
for (var row = 0; row < GRID_ROWS; row++) {
grid[row] = [];
for (var col = 0; col < GRID_COLS; col++) {
var gemType;
do {
gemType = Math.floor(Math.random() * 4); // Start with 4 gem types
} while (wouldCreateMatch(row, col, gemType));
var gem = new Gem();
gem.init(gemType, row, col);
grid[row][col] = gem;
game.addChild(gem);
}
}
}
function wouldCreateMatch(row, col, gemType) {
// Check horizontal match
var horizontalCount = 1;
if (col >= 2 && grid[row][col - 1] && grid[row][col - 2] && grid[row][col - 1].gemType === gemType && grid[row][col - 2].gemType === gemType) {
return true;
}
// Check vertical match
if (row >= 2 && grid[row - 1][col] && grid[row - 2][col] && grid[row - 1][col].gemType === gemType && grid[row - 2][col].gemType === gemType) {
return true;
}
return false;
}
function getGemAt(x, y) {
var col = Math.floor((x - BOARD_OFFSET_X) / GEM_SIZE);
var row = Math.floor((y - BOARD_OFFSET_Y) / GEM_SIZE);
if (row >= 0 && row < GRID_ROWS && col >= 0 && col < GRID_COLS) {
return grid[row][col];
}
return null;
}
function areAdjacent(gem1, gem2) {
var rowDiff = Math.abs(gem1.row - gem2.row);
var colDiff = Math.abs(gem1.col - gem2.col);
return rowDiff === 1 && colDiff === 0 || rowDiff === 0 && colDiff === 1;
}
function swapGems(gem1, gem2) {
var tempRow = gem1.row;
var tempCol = gem1.col;
var tempX = gem1.x;
var tempY = gem1.y;
gem1.row = gem2.row;
gem1.col = gem2.col;
gem2.row = tempRow;
gem2.col = tempCol;
grid[gem1.row][gem1.col] = gem1;
grid[gem2.row][gem2.col] = gem2;
gem1.animateTo(gem2.x, gem2.y, 200);
gem2.animateTo(tempX, tempY, 200);
}
function findMatches() {
var matches = [];
// Check horizontal matches
for (var row = 0; row < GRID_ROWS; row++) {
var count = 1;
var currentType = grid[row][0].gemType;
for (var col = 1; col < GRID_COLS; col++) {
if (grid[row][col].gemType === currentType) {
count++;
} else {
if (count >= 3) {
for (var i = col - count; i < col; i++) {
matches.push(grid[row][i]);
}
}
count = 1;
currentType = grid[row][col].gemType;
}
}
if (count >= 3) {
for (var i = col - count; i < col; i++) {
matches.push(grid[row][i]);
}
}
}
// Check vertical matches
for (var col = 0; col < GRID_COLS; col++) {
var count = 1;
var currentType = grid[0][col].gemType;
for (var row = 1; row < GRID_ROWS; row++) {
if (grid[row][col].gemType === currentType) {
count++;
} else {
if (count >= 3) {
for (var i = row - count; i < row; i++) {
if (matches.indexOf(grid[i][col]) === -1) {
matches.push(grid[i][col]);
}
}
}
count = 1;
currentType = grid[row][col].gemType;
}
}
if (count >= 3) {
for (var i = row - count; i < row; i++) {
if (matches.indexOf(grid[i][col]) === -1) {
matches.push(grid[i][col]);
}
}
}
}
return matches;
}
function removeMatches(matches) {
var points = matches.length * 10 * comboMultiplier;
LK.setScore(LK.getScore() + points);
scoreTxt.setText(LK.getScore());
// Update combo display
if (comboMultiplier > 1) {
comboTxt.setText('COMBO x' + comboMultiplier);
tween(comboTxt, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
comboTxt.setText('');
comboTxt.alpha = 1;
}
});
}
// Screen shake based on match size
shakeIntensity = Math.min(matches.length * 2, 20);
// Play sound
if (comboMultiplier > 1) {
LK.getSound('combo').play();
} else {
LK.getSound('match').play();
}
for (var i = 0; i < matches.length; i++) {
var gem = matches[i];
gem.explode();
gem.isMatched = true;
LK.setTimeout(function (gemToRemove) {
return function () {
gemToRemove.destroy();
grid[gemToRemove.row][gemToRemove.col] = null;
};
}(gem), 200);
}
comboMultiplier++;
}
function applyGravity() {
var hasMoved = false;
for (var col = 0; col < GRID_COLS; col++) {
for (var row = GRID_ROWS - 2; row >= 0; row--) {
if (grid[row][col] && !grid[row][col].isMatched) {
var fallDistance = 0;
for (var checkRow = row + 1; checkRow < GRID_ROWS; checkRow++) {
if (grid[checkRow][col] === null) {
fallDistance++;
} else {
break;
}
}
if (fallDistance > 0) {
var gem = grid[row][col];
grid[row][col] = null;
gem.row = row + fallDistance;
grid[gem.row][col] = gem;
var targetY = gem.row * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_Y;
gem.animateTo(gem.x, targetY, 300);
hasMoved = true;
}
}
}
}
return hasMoved;
}
function fillEmptySpaces() {
for (var col = 0; col < GRID_COLS; col++) {
for (var row = 0; row < GRID_ROWS; row++) {
if (grid[row][col] === null) {
var gemTypes = Math.min(4 + Math.floor(LK.getScore() / 500), 6); // Progressive difficulty
var gemType = Math.floor(Math.random() * gemTypes);
var gem = new Gem();
gem.init(gemType, row, col);
gem.y = -GEM_SIZE;
grid[row][col] = gem;
game.addChild(gem);
var targetY = row * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_Y;
gem.animateTo(gem.x, targetY, 400);
}
}
}
}
function processMatches() {
if (isProcessing) return;
isProcessing = true;
LK.setTimeout(function () {
var matches = findMatches();
if (matches.length > 0) {
removeMatches(matches);
LK.setTimeout(function () {
var moved = applyGravity();
fillEmptySpaces();
LK.setTimeout(function () {
isProcessing = false;
processMatches(); // Check for new matches
}, 500);
}, 300);
} else {
comboMultiplier = 1;
isProcessing = false;
}
}, 100);
}
game.down = function (x, y, obj) {
if (isProcessing) return;
var gem = getGemAt(x, y);
if (gem && !gem.isAnimating) {
if (selectedGem === null) {
selectedGem = gem;
tween(gem, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut
});
} else if (selectedGem === gem) {
tween(gem, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
selectedGem = null;
} else if (areAdjacent(selectedGem, gem)) {
var firstGem = selectedGem;
tween(firstGem, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
swapGems(firstGem, gem);
selectedGem = null;
LK.setTimeout(function () {
var matches = findMatches();
if (matches.length === 0) {
// Invalid move, swap back
swapGems(firstGem, gem);
} else {
processMatches();
}
}, 250);
} else {
tween(selectedGem, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
selectedGem = gem;
tween(gem, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut
});
}
}
};
game.update = function () {
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].update();
}
// Apply screen shake
if (shakeIntensity > 0.1) {
var shakeX = (Math.random() - 0.5) * shakeIntensity;
var shakeY = (Math.random() - 0.5) * shakeIntensity;
game.x = shakeX;
game.y = shakeY;
shakeIntensity *= shakeDecay;
} else {
game.x = 0;
game.y = 0;
shakeIntensity = 0;
}
};
// Initialize the game
initializeGrid(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,423 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+var Gem = Container.expand(function () {
+ var self = Container.call(this);
+ self.init = function (type, row, col) {
+ self.gemType = type;
+ self.row = row;
+ self.col = col;
+ self.isMatched = false;
+ self.isAnimating = false;
+ var gemAssets = ['gem_red', 'gem_blue', 'gem_green', 'gem_yellow', 'gem_purple', 'gem_orange'];
+ var gemGraphics = self.attachAsset(gemAssets[type], {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.x = col * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_X;
+ self.y = row * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_Y;
+ };
+ self.animateTo = function (targetX, targetY, duration, onComplete) {
+ self.isAnimating = true;
+ tween(self, {
+ x: targetX,
+ y: targetY
+ }, {
+ duration: duration || 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ self.isAnimating = false;
+ if (onComplete) onComplete();
+ }
+ });
+ };
+ self.explode = function () {
+ for (var i = 0; i < 8; i++) {
+ var particle = new Particle();
+ particle.x = self.x;
+ particle.y = self.y;
+ particle.explode(Math.random() * Math.PI * 2, 100 + Math.random() * 100);
+ game.addChild(particle);
+ particles.push(particle);
+ }
+ tween(self, {
+ scaleX: 1.5,
+ scaleY: 1.5,
+ alpha: 0
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ };
+ return self;
+});
+var Particle = Container.expand(function () {
+ var self = Container.call(this);
+ var particleGraphics = self.attachAsset('particle', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.velocityX = 0;
+ self.velocityY = 0;
+ self.life = 60;
+ self.maxLife = 60;
+ self.explode = function (angle, speed) {
+ self.velocityX = Math.cos(angle) * speed;
+ self.velocityY = Math.sin(angle) * speed;
+ };
+ self.update = function () {
+ self.x += self.velocityX;
+ self.y += self.velocityY;
+ self.velocityX *= 0.95;
+ self.velocityY *= 0.95;
+ self.velocityY += 2; // gravity
+ self.life--;
+ self.alpha = self.life / self.maxLife;
+ if (self.life <= 0) {
+ self.destroy();
+ for (var i = particles.length - 1; i >= 0; i--) {
+ if (particles[i] === self) {
+ particles.splice(i, 1);
+ break;
+ }
+ }
+ }
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x1a1a2e
+});
+
+/****
+* Game Code
+****/
+var GRID_ROWS = 10;
+var GRID_COLS = 8;
+var GEM_SIZE = 256;
+var BOARD_OFFSET_X = (2048 - GRID_COLS * GEM_SIZE) / 2;
+var BOARD_OFFSET_Y = 100;
+var grid = [];
+var selectedGem = null;
+var isProcessing = false;
+var particles = [];
+var comboMultiplier = 1;
+var shakeIntensity = 0;
+var shakeDecay = 0.9;
+// Initialize score display
+var scoreTxt = new Text2('0', {
+ size: 120,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+scoreTxt.y = 50;
+// Initialize combo display
+var comboTxt = new Text2('', {
+ size: 80,
+ fill: 0xFFFF00
+});
+comboTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(comboTxt);
+comboTxt.y = 180;
+function initializeGrid() {
+ for (var row = 0; row < GRID_ROWS; row++) {
+ grid[row] = [];
+ for (var col = 0; col < GRID_COLS; col++) {
+ var gemType;
+ do {
+ gemType = Math.floor(Math.random() * 4); // Start with 4 gem types
+ } while (wouldCreateMatch(row, col, gemType));
+ var gem = new Gem();
+ gem.init(gemType, row, col);
+ grid[row][col] = gem;
+ game.addChild(gem);
+ }
+ }
+}
+function wouldCreateMatch(row, col, gemType) {
+ // Check horizontal match
+ var horizontalCount = 1;
+ if (col >= 2 && grid[row][col - 1] && grid[row][col - 2] && grid[row][col - 1].gemType === gemType && grid[row][col - 2].gemType === gemType) {
+ return true;
+ }
+ // Check vertical match
+ if (row >= 2 && grid[row - 1][col] && grid[row - 2][col] && grid[row - 1][col].gemType === gemType && grid[row - 2][col].gemType === gemType) {
+ return true;
+ }
+ return false;
+}
+function getGemAt(x, y) {
+ var col = Math.floor((x - BOARD_OFFSET_X) / GEM_SIZE);
+ var row = Math.floor((y - BOARD_OFFSET_Y) / GEM_SIZE);
+ if (row >= 0 && row < GRID_ROWS && col >= 0 && col < GRID_COLS) {
+ return grid[row][col];
+ }
+ return null;
+}
+function areAdjacent(gem1, gem2) {
+ var rowDiff = Math.abs(gem1.row - gem2.row);
+ var colDiff = Math.abs(gem1.col - gem2.col);
+ return rowDiff === 1 && colDiff === 0 || rowDiff === 0 && colDiff === 1;
+}
+function swapGems(gem1, gem2) {
+ var tempRow = gem1.row;
+ var tempCol = gem1.col;
+ var tempX = gem1.x;
+ var tempY = gem1.y;
+ gem1.row = gem2.row;
+ gem1.col = gem2.col;
+ gem2.row = tempRow;
+ gem2.col = tempCol;
+ grid[gem1.row][gem1.col] = gem1;
+ grid[gem2.row][gem2.col] = gem2;
+ gem1.animateTo(gem2.x, gem2.y, 200);
+ gem2.animateTo(tempX, tempY, 200);
+}
+function findMatches() {
+ var matches = [];
+ // Check horizontal matches
+ for (var row = 0; row < GRID_ROWS; row++) {
+ var count = 1;
+ var currentType = grid[row][0].gemType;
+ for (var col = 1; col < GRID_COLS; col++) {
+ if (grid[row][col].gemType === currentType) {
+ count++;
+ } else {
+ if (count >= 3) {
+ for (var i = col - count; i < col; i++) {
+ matches.push(grid[row][i]);
+ }
+ }
+ count = 1;
+ currentType = grid[row][col].gemType;
+ }
+ }
+ if (count >= 3) {
+ for (var i = col - count; i < col; i++) {
+ matches.push(grid[row][i]);
+ }
+ }
+ }
+ // Check vertical matches
+ for (var col = 0; col < GRID_COLS; col++) {
+ var count = 1;
+ var currentType = grid[0][col].gemType;
+ for (var row = 1; row < GRID_ROWS; row++) {
+ if (grid[row][col].gemType === currentType) {
+ count++;
+ } else {
+ if (count >= 3) {
+ for (var i = row - count; i < row; i++) {
+ if (matches.indexOf(grid[i][col]) === -1) {
+ matches.push(grid[i][col]);
+ }
+ }
+ }
+ count = 1;
+ currentType = grid[row][col].gemType;
+ }
+ }
+ if (count >= 3) {
+ for (var i = row - count; i < row; i++) {
+ if (matches.indexOf(grid[i][col]) === -1) {
+ matches.push(grid[i][col]);
+ }
+ }
+ }
+ }
+ return matches;
+}
+function removeMatches(matches) {
+ var points = matches.length * 10 * comboMultiplier;
+ LK.setScore(LK.getScore() + points);
+ scoreTxt.setText(LK.getScore());
+ // Update combo display
+ if (comboMultiplier > 1) {
+ comboTxt.setText('COMBO x' + comboMultiplier);
+ tween(comboTxt, {
+ alpha: 0
+ }, {
+ duration: 1000,
+ onFinish: function onFinish() {
+ comboTxt.setText('');
+ comboTxt.alpha = 1;
+ }
+ });
+ }
+ // Screen shake based on match size
+ shakeIntensity = Math.min(matches.length * 2, 20);
+ // Play sound
+ if (comboMultiplier > 1) {
+ LK.getSound('combo').play();
+ } else {
+ LK.getSound('match').play();
+ }
+ for (var i = 0; i < matches.length; i++) {
+ var gem = matches[i];
+ gem.explode();
+ gem.isMatched = true;
+ LK.setTimeout(function (gemToRemove) {
+ return function () {
+ gemToRemove.destroy();
+ grid[gemToRemove.row][gemToRemove.col] = null;
+ };
+ }(gem), 200);
+ }
+ comboMultiplier++;
+}
+function applyGravity() {
+ var hasMoved = false;
+ for (var col = 0; col < GRID_COLS; col++) {
+ for (var row = GRID_ROWS - 2; row >= 0; row--) {
+ if (grid[row][col] && !grid[row][col].isMatched) {
+ var fallDistance = 0;
+ for (var checkRow = row + 1; checkRow < GRID_ROWS; checkRow++) {
+ if (grid[checkRow][col] === null) {
+ fallDistance++;
+ } else {
+ break;
+ }
+ }
+ if (fallDistance > 0) {
+ var gem = grid[row][col];
+ grid[row][col] = null;
+ gem.row = row + fallDistance;
+ grid[gem.row][col] = gem;
+ var targetY = gem.row * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_Y;
+ gem.animateTo(gem.x, targetY, 300);
+ hasMoved = true;
+ }
+ }
+ }
+ }
+ return hasMoved;
+}
+function fillEmptySpaces() {
+ for (var col = 0; col < GRID_COLS; col++) {
+ for (var row = 0; row < GRID_ROWS; row++) {
+ if (grid[row][col] === null) {
+ var gemTypes = Math.min(4 + Math.floor(LK.getScore() / 500), 6); // Progressive difficulty
+ var gemType = Math.floor(Math.random() * gemTypes);
+ var gem = new Gem();
+ gem.init(gemType, row, col);
+ gem.y = -GEM_SIZE;
+ grid[row][col] = gem;
+ game.addChild(gem);
+ var targetY = row * GEM_SIZE + GEM_SIZE / 2 + BOARD_OFFSET_Y;
+ gem.animateTo(gem.x, targetY, 400);
+ }
+ }
+ }
+}
+function processMatches() {
+ if (isProcessing) return;
+ isProcessing = true;
+ LK.setTimeout(function () {
+ var matches = findMatches();
+ if (matches.length > 0) {
+ removeMatches(matches);
+ LK.setTimeout(function () {
+ var moved = applyGravity();
+ fillEmptySpaces();
+ LK.setTimeout(function () {
+ isProcessing = false;
+ processMatches(); // Check for new matches
+ }, 500);
+ }, 300);
+ } else {
+ comboMultiplier = 1;
+ isProcessing = false;
+ }
+ }, 100);
+}
+game.down = function (x, y, obj) {
+ if (isProcessing) return;
+ var gem = getGemAt(x, y);
+ if (gem && !gem.isAnimating) {
+ if (selectedGem === null) {
+ selectedGem = gem;
+ tween(gem, {
+ scaleX: 1.1,
+ scaleY: 1.1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ } else if (selectedGem === gem) {
+ tween(gem, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ selectedGem = null;
+ } else if (areAdjacent(selectedGem, gem)) {
+ var firstGem = selectedGem;
+ tween(firstGem, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ swapGems(firstGem, gem);
+ selectedGem = null;
+ LK.setTimeout(function () {
+ var matches = findMatches();
+ if (matches.length === 0) {
+ // Invalid move, swap back
+ swapGems(firstGem, gem);
+ } else {
+ processMatches();
+ }
+ }, 250);
+ } else {
+ tween(selectedGem, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ selectedGem = gem;
+ tween(gem, {
+ scaleX: 1.1,
+ scaleY: 1.1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ }
+ }
+};
+game.update = function () {
+ // Update particles
+ for (var i = particles.length - 1; i >= 0; i--) {
+ particles[i].update();
+ }
+ // Apply screen shake
+ if (shakeIntensity > 0.1) {
+ var shakeX = (Math.random() - 0.5) * shakeIntensity;
+ var shakeY = (Math.random() - 0.5) * shakeIntensity;
+ game.x = shakeX;
+ game.y = shakeY;
+ shakeIntensity *= shakeDecay;
+ } else {
+ game.x = 0;
+ game.y = 0;
+ shakeIntensity = 0;
+ }
+};
+// Initialize the game
+initializeGrid();
\ No newline at end of file