User prompt
Add animation to the face of the fruits ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Let the grill be black
User prompt
Put the grill in the box
User prompt
Let it be a little more clear, the grill color should not cover the outer edges.
User prompt
Please fix the bug: 'null is not an object (evaluating 't.length')' in or related to this line: 'var lineAsset = LK.getAsset(null, {' Line Number: 348
User prompt
Add a transparent grill in gray among the fruits
User prompt
Let it all be different explosion animation ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Show the explosion effect
User prompt
Please fix the bug: 'TypeError: null is not an object (evaluating 'tile.destroy')' in or related to this line: 'tile.destroy();' Line Number: 505
User prompt
When combined, let the fruits explode ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Let them all have different dance animations ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add dancing animation to fruits ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Remove the names from the fruits
User prompt
Make the background white and make it a little bigger
User prompt
Remove the transparent fruits on the back
User prompt
Make the theme fruits
User prompt
Please fix the bug: 'LK.hasAsset is not a function. (In 'LK.hasAsset(assetId)', 'LK.hasAsset' is undefined)' in or related to this line: 'if (!LK.hasAsset(assetId)) {' Line Number: 43
Code edit (1 edits merged)
Please save this source code
User prompt
Galactic 2048: Space Merge
Initial prompt
Space themed 2048 game
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Tile class for each grid cell
var Tile = Container.expand(function () {
var self = Container.call(this);
// Properties
self.value = 2; // Default value
self.row = 0;
self.col = 0;
self.asset = null;
self.text = null;
// Set tile value and update appearance
self.setValue = function (val) {
self.value = val;
// Remove old asset if exists
if (self.asset) {
self.removeChild(self.asset);
}
// Choose asset by value
var assetId = 'tile' + val;
var supportedAssets = {
'tile2': true,
'tile4': true,
'tile8': true,
'tile16': true,
'tile32': true,
'tile64': true,
'tile128': true,
'tile256': true,
'tile512': true,
'tile1024': true,
'tile2048': true
};
if (!supportedAssets[assetId]) assetId = 'tile2048'; // fallback
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Remove old text if exists
if (self.text) {
self.removeChild(self.text);
}
// Add value text (empty label, no fruit names)
var label = '';
self.text = new Text2(label, {
size: 60,
fill: 0xFFFFFF,
align: "center"
});
self.text.anchor.set(0.5, 0.5);
self.text.y = 0;
self.text.x = 0;
self.addChild(self.text);
// Restart dancing after value change
if (self.startDancing) self.startDancing();
};
// Animate merge
self.animateMerge = function () {
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,
onFinish: function onFinish() {
if (self.startDancing) self.startDancing();
}
});
}
});
};
// Animate spawn
self.animateSpawn = function () {
self.scaleX = 0.2;
self.scaleY = 0.2;
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
if (self.startDancing) self.startDancing();
}
});
};
// Set position on grid
self.setGridPos = function (row, col, cellSize, gridX, gridY) {
self.row = row;
self.col = col;
self.x = gridX + col * cellSize + cellSize / 2;
self.y = gridY + row * cellSize + cellSize / 2;
};
// Add dancing animation (continuous, unique per value)
self.startDancing = function () {
// Cancel any previous tweens on scale
tween.stop(self, {
scaleX: true,
scaleY: true
});
// Unique dance parameters per value
var dances = {
2: {
sx1: 1.10,
sy1: 0.90,
sx2: 0.90,
sy2: 1.10,
dur1: 220,
dur2: 220,
ease1: tween.easeInOut,
ease2: tween.easeInOut
},
4: {
sx1: 1.15,
sy1: 0.85,
sx2: 0.85,
sy2: 1.15,
dur1: 180,
dur2: 180,
ease1: tween.bounceIn,
ease2: tween.bounceOut
},
8: {
sx1: 1.08,
sy1: 1.08,
sx2: 0.92,
sy2: 0.92,
dur1: 260,
dur2: 260,
ease1: tween.elasticIn,
ease2: tween.elasticOut
},
16: {
sx1: 1.20,
sy1: 0.80,
sx2: 0.80,
sy2: 1.20,
dur1: 150,
dur2: 150,
ease1: tween.cubicOut,
ease2: tween.cubicIn
},
32: {
sx1: 1.05,
sy1: 1.15,
sx2: 1.15,
sy2: 1.05,
dur1: 200,
dur2: 200,
ease1: tween.quarticInOut,
ease2: tween.quarticInOut
},
64: {
sx1: 1.18,
sy1: 0.95,
sx2: 0.95,
sy2: 1.18,
dur1: 170,
dur2: 170,
ease1: tween.sineIn,
ease2: tween.sineOut
},
128: {
sx1: 1.12,
sy1: 1.12,
sx2: 0.88,
sy2: 0.88,
dur1: 250,
dur2: 250,
ease1: tween.elasticInOut,
ease2: tween.elasticInOut
},
256: {
sx1: 1.25,
sy1: 0.75,
sx2: 0.75,
sy2: 1.25,
dur1: 140,
dur2: 140,
ease1: tween.bounceOut,
ease2: tween.bounceIn
},
512: {
sx1: 1.10,
sy1: 1.05,
sx2: 1.05,
sy2: 1.10,
dur1: 210,
dur2: 210,
ease1: tween.cubicIn,
ease2: tween.cubicOut
},
1024: {
sx1: 1.22,
sy1: 0.92,
sx2: 0.92,
sy2: 1.22,
dur1: 160,
dur2: 160,
ease1: tween.quinticIn,
ease2: tween.quinticOut
},
2048: {
sx1: 1.30,
sy1: 0.70,
sx2: 0.70,
sy2: 1.30,
dur1: 120,
dur2: 120,
ease1: tween.expoIn,
ease2: tween.expoOut
}
};
var dance = dances[self.value] || dances[2];
function danceUp() {
tween(self, {
scaleX: dance.sx1,
scaleY: dance.sy1
}, {
duration: dance.dur1,
easing: dance.ease1,
onFinish: function onFinish() {
danceDown();
}
});
}
function danceDown() {
tween(self, {
scaleX: dance.sx2,
scaleY: dance.sy2
}, {
duration: dance.dur2,
easing: dance.ease2,
onFinish: function onFinish() {
danceUp();
}
});
}
// Start the loop
danceUp();
};
// Stop dancing animation
self.stopDancing = function () {
tween.stop(self, {
scaleX: true,
scaleY: true
});
self.scaleX = 1;
self.scaleY = 1;
};
// Start dancing by default
self.startDancing();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xffffff
});
/****
* Game Code
****/
// Optionally, a subtle grid background
// 2: Asteroid (gray), 4: Moon (light blue), 8: Planet (blue), 16: Star (yellow), 32: Red Giant (red), 64: Neutron Star (purple), 128: Black Hole (black), 256: Nebula (pink), 512: Galaxy (cyan), 1024: Quasar (orange), 2048: Universe (white)
// Space tile assets: We'll use colored ellipses for different tile values
// --- Grid and Layout ---
var gridSize = 4;
var cellSize = 370; // 370*4=1480, bigger board
var gridPadding = 28;
var gridWidth = cellSize * gridSize + gridPadding * (gridSize + 1);
var gridHeight = cellSize * gridSize + gridPadding * (gridSize + 1);
var gridX = Math.floor((2048 - gridWidth) / 2);
var gridY = Math.floor((2732 - gridHeight) / 2);
// --- Game State ---
var grid = []; // 2D array of tiles or null
var tiles = []; // All tile objects for easy management
var score = 0;
var scoreTxt = null;
var isMoving = false; // Prevent input during animation
// --- GUI: Score ---
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Draw grid background ---
var gridBg = LK.getAsset('gridBg', {
anchorX: 0,
anchorY: 0,
x: gridX,
y: gridY,
width: gridWidth,
height: gridHeight
});
game.addChild(gridBg);
// --- Draw grid cell backgrounds ---
// (Removed transparent fruit tiles on the back)
// --- Initialize grid state ---
function resetGrid() {
grid = [];
for (var r = 0; r < gridSize; r++) {
var row = [];
for (var c = 0; c < gridSize; c++) {
row.push(null);
}
grid.push(row);
}
// Remove all tiles from game
for (var i = 0; i < tiles.length; i++) {
tiles[i].destroy();
}
tiles = [];
score = 0;
scoreTxt.setText(score);
}
// --- Add a new tile (2 or 4) at random empty position ---
function addRandomTile() {
var empties = [];
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
if (!grid[r][c]) empties.push({
r: r,
c: c
});
}
}
if (empties.length === 0) return false;
var idx = Math.floor(Math.random() * empties.length);
var pos = empties[idx];
var val = Math.random() < 0.9 ? 2 : 4;
var tile = new Tile();
tile.setValue(val);
tile.setGridPos(pos.r, pos.c, cellSize, gridX + gridPadding, gridY + gridPadding);
tile.animateSpawn();
grid[pos.r][pos.c] = tile;
tiles.push(tile);
game.addChild(tile);
return true;
}
// --- Move/merge logic ---
function canMove() {
// Check for any empty cell
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
if (!grid[r][c]) return true;
}
}
// Check for any mergeable neighbor
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
var tile = grid[r][c];
if (!tile) continue;
// Right
if (c + 1 < gridSize && grid[r][c + 1] && grid[r][c + 1].value === tile.value) return true;
// Down
if (r + 1 < gridSize && grid[r + 1][c] && grid[r + 1][c].value === tile.value) return true;
}
}
return false;
}
// Returns true if any tile reached 2048
function has2048() {
for (var r = 0; r < gridSize; r++) {
for (var c = 0; c < gridSize; c++) {
if (grid[r][c] && grid[r][c].value === 2048) return true;
}
}
return false;
}
// Move tiles in a direction: 'up', 'down', 'left', 'right'
function moveTiles(dir) {
if (isMoving) return;
isMoving = true;
var moved = false;
var mergedThisMove = [];
// Helper to reset merged flags
function resetMerged() {
for (var i = 0; i < tiles.length; i++) {
tiles[i].merged = false;
}
}
resetMerged();
// For each direction, set up iteration order
var startR = 0,
endR = gridSize,
stepR = 1;
var startC = 0,
endC = gridSize,
stepC = 1;
if (dir === 'up') {
startR = 1;
endR = gridSize;
stepR = 1;
}
if (dir === 'down') {
startR = gridSize - 2;
endR = -1;
stepR = -1;
}
if (dir === 'left') {
startC = 1;
endC = gridSize;
stepC = 1;
}
if (dir === 'right') {
startC = gridSize - 2;
endC = -1;
stepC = -1;
}
// Move/merge logic
var movedTiles = [];
if (dir === 'up' || dir === 'down') {
for (var c = 0; c < gridSize; c++) {
for (var r = startR; r != endR; r += stepR) {
var tile = grid[r][c];
if (!tile) continue;
var tr = r;
while (true) {
var nr = tr + (dir === 'up' ? -1 : 1);
if (nr < 0 || nr >= gridSize) break;
if (!grid[nr][c]) {
// Move
grid[nr][c] = tile;
grid[tr][c] = null;
tr = nr;
moved = true;
} else if (grid[nr][c].value === tile.value && !grid[nr][c].merged && !tile.merged) {
// Merge
grid[nr][c].setValue(tile.value * 2);
grid[nr][c].animateMerge();
grid[nr][c].merged = true;
score += tile.value * 2;
scoreTxt.setText(score);
// Explode animation for merged tile
tile.stopDancing && tile.stopDancing();
tween(tile, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0
}, {
duration: 220,
easing: tween.expoOut,
onFinish: function onFinish() {
if (tile && typeof tile.destroy === "function") {
tile.destroy();
}
}
});
tiles.splice(tiles.indexOf(tile), 1);
grid[tr][c] = null;
moved = true;
break;
} else {
break;
}
}
// Animate move
if (tile && tr !== r) {
tile.setGridPos(tr, c, cellSize, gridX + gridPadding, gridY + gridPadding);
movedTiles.push(tile);
}
}
}
} else {
for (var r = 0; r < gridSize; r++) {
for (var c = startC; c != endC; c += stepC) {
var tile = grid[r][c];
if (!tile) continue;
var tc = c;
while (true) {
var nc = tc + (dir === 'left' ? -1 : 1);
if (nc < 0 || nc >= gridSize) break;
if (!grid[r][nc]) {
// Move
grid[r][nc] = tile;
grid[r][tc] = null;
tc = nc;
moved = true;
} else if (grid[r][nc].value === tile.value && !grid[r][nc].merged && !tile.merged) {
// Merge
grid[r][nc].setValue(tile.value * 2);
grid[r][nc].animateMerge();
grid[r][nc].merged = true;
score += tile.value * 2;
scoreTxt.setText(score);
// Explode animation for merged tile
tile.stopDancing && tile.stopDancing();
tween(tile, {
scaleX: 1.8,
scaleY: 1.8,
alpha: 0
}, {
duration: 220,
easing: tween.expoOut,
onFinish: function onFinish() {
if (tile && typeof tile.destroy === "function") {
tile.destroy();
}
}
});
tiles.splice(tiles.indexOf(tile), 1);
grid[r][tc] = null;
moved = true;
break;
} else {
break;
}
}
// Animate move
if (tile && tc !== c) {
tile.setGridPos(r, tc, cellSize, gridX + gridPadding, gridY + gridPadding);
movedTiles.push(tile);
}
}
}
}
// Animate all moved tiles
var animCount = movedTiles.length;
if (animCount === 0) {
isMoving = false;
afterMove(moved);
} else {
for (var i = 0; i < movedTiles.length; i++) {
var t = movedTiles[i];
tween(t, {
x: t.x,
y: t.y
}, {
duration: 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
animCount--;
if (animCount === 0) {
isMoving = false;
afterMove(moved);
}
}
});
}
}
if (animCount === 0) {
// No animation, call afterMove immediately
afterMove(moved);
}
}
// After move: add new tile, check win/lose
function afterMove(moved) {
if (moved) {
addRandomTile();
}
if (has2048()) {
LK.showYouWin();
return;
}
if (!canMove()) {
LK.showGameOver();
return;
}
}
// --- Input: Swipe detection ---
// We'll use game.down, game.move, game.up to detect swipe direction
var touchStartX = 0,
touchStartY = 0,
touchMoved = false;
game.down = function (x, y, obj) {
if (isMoving) return;
touchStartX = x;
touchStartY = y;
touchMoved = false;
};
game.move = function (x, y, obj) {
if (isMoving) return;
if (touchStartX === undefined) return;
var dx = x - touchStartX;
var dy = y - touchStartY;
if (!touchMoved && (Math.abs(dx) > 40 || Math.abs(dy) > 40)) {
touchMoved = true;
// Determine direction
if (Math.abs(dx) > Math.abs(dy)) {
if (dx > 0) moveTiles('right');else moveTiles('left');
} else {
if (dy > 0) moveTiles('down');else moveTiles('up');
}
// Reset to prevent multiple moves per swipe
touchStartX = undefined;
touchStartY = undefined;
}
};
game.up = function (x, y, obj) {
touchStartX = undefined;
touchStartY = undefined;
touchMoved = false;
};
// --- Game update (not used, but required for tick-based games) ---
game.update = function () {
// No per-frame logic needed
};
// --- Start game ---
function startGame() {
resetGrid();
addRandomTile();
addRandomTile();
scoreTxt.setText(score);
}
startGame(); ===================================================================
--- original.js
+++ change.js
@@ -457,9 +457,11 @@
}, {
duration: 220,
easing: tween.expoOut,
onFinish: function onFinish() {
- tile.destroy();
+ if (tile && typeof tile.destroy === "function") {
+ tile.destroy();
+ }
}
});
tiles.splice(tiles.indexOf(tile), 1);
grid[tr][c] = null;
@@ -507,9 +509,11 @@
}, {
duration: 220,
easing: tween.expoOut,
onFinish: function onFinish() {
- tile.destroy();
+ if (tile && typeof tile.destroy === "function") {
+ tile.destroy();
+ }
}
});
tiles.splice(tiles.indexOf(tile), 1);
grid[r][tc] = null;
Furit King!. In-Game asset. 2d. High contrast. No shadows
Orange with face. In-Game asset. 2d. High contrast. No shadows
Cherry with face. In-Game asset. 2d. High contrast. No shadows
Grape with face. In-Game asset. 2d. High contrast. No shadows
Lemon with face. In-Game asset. 2d. High contrast. No shadows
Pear with face. In-Game asset. 2d. High contrast. No shadows
Mango with face. In-Game asset. 2d. High contrast. No shadows
Apple with face. In-Game asset. 2d. High contrast. No shadows
Watermelon with face. In-Game asset. 2d. High contrast. No shadows
Strawberry with face. In-Game asset. 2d. High contrast. No shadows
Banana with face. In-Game asset. 2d. High contrast. No shadows
Let the clouds in the back move. In-Game asset. 2d. High contrast. No shadows