Code edit (1 edits merged)
Please save this source code
User prompt
Sometimes the columns get frozen at a position and the logic works (following pieces detec they are frozen at the right place) but they render on top of the screen. Fix it.
User prompt
Fix an issue when the columns, when frozen, they move to the top of the screen instead of stucking in place. This seems to happen when they stuck / get frozen and you still rotate them.
User prompt
Sometimes if i click on the gems as they change from falling to getting stuck, there is a weird behaviour where then are rendered on the top of the screen / cells instead of on the place where they were stuck. Please fix.
User prompt
Sometimes the gems match and they disappear and everything is ok except that the screen does not flash or the sound is not played. Can you fix?
User prompt
If my click / tap on the screen is not on the falling gems, the falling gems should fall at 10x speed during the duration of the tap.
User prompt
By tapping anywhere else when there is no falling gems (it may be existing stuck / frozen gems, that's fine!) make the falling gems fall at a 10x speed
User prompt
If you click on a falling gems now it rotates the gems. Thats good. But I want another behaviour as well: if you don't release the mouse / untap the screen, it will fall down at a 10x speed instead of rotating gems. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
If you click / tap a falling gem but dont' release the button, it will fall at a 10x speed instead of rotating gems.
Code edit (5 edits merged)
Please save this source code
User prompt
Add a text2 "Next" above the next gems
User prompt
If I click on the bottom part of the screen, like the 10% percent of the bottom, the currently falling gems should fall at a much higher speed, like 10x
User prompt
Right now only 3 equal gems in vertical or horizontal "match". Please make it so that three equal color gems in diagonal also match.
Code edit (1 edits merged)
Please save this source code
Code edit (13 edits merged)
Please save this source code
User prompt
Do it
Code edit (1 edits merged)
Please save this source code
User prompt
No! The other way around, don't destory boardBg! It should be shown still after starting the game
User prompt
Fix: by clickin on titleImage, the boardBg is destroyed?
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: titleImage.Destroy is not a function' in or related to this line: 'titleImage.Destroy();' Line Number: 833
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Column = Container.expand(function (gemTypes) {
var self = Container.call(this);
self.gems = [];
self.isActive = false;
// Create the three gems that form the column
for (var i = 0; i < 3; i++) {
var type = gemTypes && gemTypes[i] ? gemTypes[i] : null;
var gem = new Gem(type);
gem.y = -i * CELL_SIZE;
self.gems.push(gem);
self.addChild(gem);
}
self.rotate = function () {
if (!self.isActive) {
return;
}
// Move the last gem to a temporary position for animation
var lastGem = self.gems.pop();
var firstGem = self.gems[0];
var middleGem = self.gems[1];
// Animate the rotation
LK.getSound('rotate').play();
// Update the gems array with the new order
self.gems = [lastGem, firstGem, middleGem];
// Update positions to match new order
tween(lastGem, {
y: firstGem.y
}, {
duration: 150
});
tween(firstGem, {
y: middleGem.y
}, {
duration: 150
});
tween(middleGem, {
y: lastGem.y + 2 * CELL_SIZE
}, {
duration: 150,
onFinish: function onFinish() {
// Reset positions after animation
for (var i = 0; i < 3; i++) {
self.gems[i].y = -i * CELL_SIZE;
}
}
});
};
self.getTypes = function () {
return self.gems.map(function (gem) {
return gem.type;
});
};
return self;
});
var GameBoard = Container.expand(function () {
var self = Container.call(this);
self.grid = [];
self.cellContainer = self.addChild(new Container());
self.gemContainer = self.addChild(new Container());
// Create background
var boardBg = self.cellContainer.attachAsset('board_bg', {
anchorX: 0.5,
// Center horizontally
anchorY: 0.5 // Center vertically
});
boardBg.x = COLS * CELL_SIZE / 2; // Center the background on the board
boardBg.y = ROWS * CELL_SIZE / 2; // Center the background on the board
// Create grid cells
for (var row = 0; row < ROWS; row++) {
self.grid[row] = [];
for (var col = 0; col < COLS; col++) {
// Create cell background
var cell = LK.getAsset('board_cell', {
anchorX: 0.5,
anchorY: 0.5,
x: col * CELL_SIZE + CELL_SIZE / 2,
y: row * CELL_SIZE + CELL_SIZE / 2,
alpha: 0
});
self.cellContainer.addChild(cell);
self.grid[row][col] = null;
}
}
self.addGemToGrid = function (gem, row, col) {
if (row < 0 || row >= ROWS || col < 0 || col >= COLS) {
return false;
}
if (self.grid[row][col] !== null) {
return false;
}
gem.x = col * CELL_SIZE + CELL_SIZE / 2;
gem.y = row * CELL_SIZE + CELL_SIZE / 2;
self.gemContainer.addChild(gem);
self.grid[row][col] = gem;
return true;
};
self.removeGemFromGrid = function (row, col) {
if (row < 0 || row >= ROWS || col < 0 || col >= COLS) {
return null;
}
var gem = self.grid[row][col];
if (gem) {
self.grid[row][col] = null;
delete frozenGems[row + ',' + col]; // Remove gem from the dictionary
return gem;
}
return null;
};
self.isColumnFull = function (col) {
return self.grid[0][col] !== null;
};
self.canPlaceColumn = function (col) {
// Check if any of the top 3 rows in the column are occupied
for (var row = 0; row < 3; row++) {
if (col < 0 || col >= COLS) {
return false;
}
if (row < ROWS && self.grid[row][col] !== null) {
return false;
}
}
return true;
};
self.findFirstEmptyRow = function (col) {
for (var row = ROWS - 1; row >= 0; row--) {
if (self.grid[row][col] === null) {
return row;
}
}
return -1; // Column is full
};
self.placeColumn = function (column, col, callback) {
var gems = column.gems;
var placedGems = [];
var firstEmptyRow = self.findFirstEmptyRow(col);
if (firstEmptyRow < 0 || firstEmptyRow < gems.length - 1) {
if (callback) {
callback(false);
}
return;
}
// Place gems from bottom to top
for (var i = 0; i < gems.length; i++) {
var row = firstEmptyRow - i;
if (row >= 0) {
// Use the existing gem instead of creating a new one
var gem = gems[i];
placedGems.push({
gem: gem,
row: row,
col: col
});
// Update the gem's position
gem.x = col * CELL_SIZE + CELL_SIZE / 2;
gem.y = row * CELL_SIZE + CELL_SIZE / 2;
// Add the gem to the grid
self.gemContainer.addChild(gem);
self.grid[row][col] = gem;
frozenGems[row + ',' + col] = gem; // Store gem in the dictionary
// If it's the last gem, notify callback
if (i === gems.length - 1) {
LK.getSound('drop').play();
if (callback) {
callback(true, placedGems);
}
}
}
}
};
self.checkMatches = function () {
var matchedCells = [];
// Check horizontal matches
for (var row = 0; row < ROWS; row++) {
var count = 1;
var type = null;
for (var col = 0; col < COLS; col++) {
var gem = self.grid[row][col];
if (gem && type === gem.type) {
count++;
} else {
if (count >= 3) {
for (var i = 0; i < count; i++) {
matchedCells.push({
row: row,
col: col - 1 - i
});
}
}
count = 1;
type = gem ? gem.type : null;
}
}
if (count >= 3) {
for (var i = 0; i < count; i++) {
matchedCells.push({
row: row,
col: COLS - 1 - i
});
}
}
}
// Check vertical matches
for (var col = 0; col < COLS; col++) {
var count = 1;
var type = null;
for (var row = 0; row < ROWS; row++) {
var gem = self.grid[row][col];
if (gem && type === gem.type) {
count++;
} else {
if (count >= 3) {
for (var i = 0; i < count; i++) {
matchedCells.push({
row: row - 1 - i,
col: col
});
}
}
count = 1;
type = gem ? gem.type : null;
}
}
if (count >= 3) {
for (var i = 0; i < count; i++) {
matchedCells.push({
row: ROWS - 1 - i,
col: col
});
}
}
}
// Check diagonal matches (top-left to bottom-right)
for (var startRow = 0; startRow <= ROWS - 3; startRow++) {
for (var startCol = 0; startCol <= COLS - 3; startCol++) {
var count = 1;
var type = null;
// Check diagonal starting at [startRow, startCol]
for (var i = 0; i < Math.min(ROWS - startRow, COLS - startCol); i++) {
var gem = self.grid[startRow + i][startCol + i];
if (gem && type === gem.type) {
count++;
} else {
if (count >= 3) {
// Add matching gems to matchedCells
for (var j = 0; j < count; j++) {
matchedCells.push({
row: startRow + i - 1 - j,
col: startCol + i - 1 - j
});
}
}
count = 1;
type = gem ? gem.type : null;
}
}
// Check if there's a match at the end of the diagonal
if (count >= 3) {
var endI = Math.min(ROWS - startRow, COLS - startCol);
for (var j = 0; j < count; j++) {
matchedCells.push({
row: startRow + endI - 1 - j,
col: startCol + endI - 1 - j
});
}
}
}
}
// Check diagonal matches (top-right to bottom-left)
for (var startRow = 0; startRow <= ROWS - 3; startRow++) {
for (var startCol = COLS - 1; startCol >= 2; startCol--) {
var count = 1;
var type = null;
// Check diagonal starting at [startRow, startCol]
for (var i = 0; i < Math.min(ROWS - startRow, startCol + 1); i++) {
var gem = self.grid[startRow + i][startCol - i];
if (gem && type === gem.type) {
count++;
} else {
if (count >= 3) {
// Add matching gems to matchedCells
for (var j = 0; j < count; j++) {
matchedCells.push({
row: startRow + i - 1 - j,
col: startCol - i + 1 + j
});
}
}
count = 1;
type = gem ? gem.type : null;
}
}
// Check if there's a match at the end of the diagonal
if (count >= 3) {
var endI = Math.min(ROWS - startRow, startCol + 1);
for (var j = 0; j < count; j++) {
matchedCells.push({
row: startRow + endI - 1 - j,
col: startCol - endI + 1 + j
});
}
}
}
}
// Remove duplicates from matchedCells
var uniqueMatches = [];
var matchMap = {};
for (var i = 0; i < matchedCells.length; i++) {
var cell = matchedCells[i];
var key = cell.row + "," + cell.col;
if (!matchMap[key]) {
matchMap[key] = true;
uniqueMatches.push(cell);
}
}
return uniqueMatches;
};
self.removeMatches = function (matches, callback) {
if (matches.length === 0) {
if (callback) {
callback(0);
}
return;
}
var remainingAnimations = matches.length;
var points = matches.length * 10;
// Always play match sound and flash effect when matches are found
// Force sound to play even if it's already playing
LK.getSound('match').stop();
LK.getSound('match').play();
// Flash for any match (3 or more gems)
LK.effects.flashScreen(0xFFFFFF, 300);
matches.forEach(function (match) {
var gem = self.grid[match.row][match.col];
if (gem) {
self.grid[match.row][match.col] = null;
delete frozenGems[match.row + ',' + match.col]; // Remove gem from the dictionary
gem.highlight();
LK.setTimeout(function () {
gem.animateMatch(function () {
self.gemContainer.removeChild(gem);
remainingAnimations--;
if (remainingAnimations === 0) {
if (callback) {
callback(points);
}
}
});
}, 100);
} else {
remainingAnimations--;
if (remainingAnimations === 0 && callback) {
callback(points);
}
}
});
};
self.applyGravity = function (callback) {
var movedGems = false;
var animationsRunning = 0;
// Iterate bottom to top, right to left
for (var col = 0; col < COLS; col++) {
for (var row = ROWS - 1; row > 0; row--) {
if (self.grid[row][col] === null) {
// Find the first non-null gem above this position
for (var checkRow = row - 1; checkRow >= 0; checkRow--) {
if (self.grid[checkRow][col] !== null) {
var gem = self.grid[checkRow][col];
self.grid[checkRow][col] = null;
self.grid[row][col] = gem;
// Update the frozenGems dictionary
delete frozenGems[checkRow + ',' + col];
frozenGems[row + ',' + col] = gem;
movedGems = true;
animationsRunning++;
gem.animateDrop(row * CELL_SIZE + CELL_SIZE / 2, 0, function () {
animationsRunning--;
if (animationsRunning === 0 && callback) {
callback(movedGems);
}
});
break;
}
}
}
}
}
if (animationsRunning === 0 && callback) {
callback(movedGems);
}
};
return self;
});
var Gem = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || getRandomGemType();
var gemSprite = self.attachAsset('gem_' + self.type, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.95,
scaleY: 0.95
});
self.setType = function (newType) {
self.type = newType;
self.removeChildren();
gemSprite = self.attachAsset('gem_' + newType, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.95,
scaleY: 0.95
});
};
self.highlight = function () {
tween(gemSprite, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut
});
};
self.unhighlight = function () {
tween(gemSprite, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 200,
easing: tween.easeOut
});
};
self.animateMatch = function (callback) {
tween(gemSprite, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (callback) {
callback();
}
}
});
};
self.animateDrop = function (targetY, delay, callback) {
tween(self, {
y: targetY
}, {
duration: 300 + delay,
easing: tween.bounceOut,
onFinish: function onFinish() {
if (callback) {
callback();
}
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111122
});
/****
* Game Code
****/
// Constants
var CELL_SIZE = 120;
var COLS = 25;
var ROWS = Math.floor(2732 / CELL_SIZE);
//var ROWS = 25;
var GEM_TYPES = ['red', 'blue', 'green', 'yellow', 'purple'];
var DROP_INTERVAL_START = 60; // ms
var DROP_INTERVAL_MIN = 60; // ms
var DROP_DELTA = 20;
var LEVEL_THRESHOLD = 50; // Points needed to level up
// Game state
var board;
var activeColumn;
var nextColumn;
var dropInterval;
var dropTimer = 0;
var fallSpeed = DROP_INTERVAL_START;
var gameActive = false;
var score = 0;
var level = 1;
var nextColumnPreview;
var columnPositionX = 0;
// Dictionary to track frozen gems
var frozenGems = {};
// UI elements
var scoreText;
var levelText;
var highScoreText;
function getRandomGemType() {
var index = Math.floor(Math.random() * GEM_TYPES.length);
return GEM_TYPES[index];
}
function setupUI() {
// Score text
scoreText = new Text2('SCORE: 0', {
size: 50,
fill: 0x000000 // Changed to black
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 50;
LK.gui.top.addChild(scoreText);
// Level text
levelText = new Text2('LEVEL: 1', {
size: 50,
fill: 0x000000 // Changed to black
});
levelText.anchor.set(0.5, 0);
levelText.y = 100;
LK.gui.top.addChild(levelText);
// High score text
var highScore = storage.highScore || 0;
highScoreText = new Text2('BEST: ' + highScore, {
size: 40,
fill: 0x800080 // Changed to purple
});
highScoreText.anchor.set(0.5, 0);
highScoreText.y = 150;
LK.gui.top.addChild(highScoreText);
}
function updateScore(points) {
score += points;
scoreText.setText('SCORE: ' + score);
// Check if player leveled up
var newLevel = Math.floor(score / LEVEL_THRESHOLD) + 1;
if (newLevel > level) {
level = newLevel;
levelText.setText('LEVEL: ' + level);
// Increase game speed
fallSpeed = Math.max(DROP_INTERVAL_MIN, DROP_INTERVAL_START - (level - 1) * DROP_DELTA); // Adjust fallSpeed based on the current level
// Play level up sound
LK.getSound('levelup').play();
// Flash effect for level up
LK.effects.flashScreen(0x00FFFF, 500);
}
// Update high score if needed
var highScore = storage.highScore || 0;
if (score > highScore) {
storage.highScore = score;
highScoreText.setText('BEST: ' + score);
}
}
function createBoard() {
board = new GameBoard();
board.x = (2048 - COLS * CELL_SIZE) / 2;
board.y = (2732 - ROWS * CELL_SIZE) / 2;
game.addChild(board);
}
function createNextColumnPreview() {
nextColumnPreview = new Container();
nextColumnPreview.x = 2048 - 120;
nextColumnPreview.y = 200;
// Create the "NEXT" label
var previewLabel = new Text2('NEXT', {
size: 80,
fill: 0x000000
});
previewLabel.anchor.set(0.5, 0);
previewLabel.y = -80; // Position at the top of the container
nextColumnPreview.addChild(previewLabel);
game.addChild(nextColumnPreview);
}
function updateNextColumnPreview() {
// Clear previous preview
for (var i = nextColumnPreview.children.length - 1; i > 0; i--) {
nextColumnPreview.removeChild(nextColumnPreview.children[i]);
}
// Add new gems to preview in the correct order
if (nextColumn) {
// Loop through gems in reverse order to match the visual appearance in the game
for (var i = nextColumn.gems.length - 1; i >= 0; i--) {
var previewGem = new Gem(nextColumn.gems[i].type);
previewGem.x = 0;
// Position from top to bottom in the preview
previewGem.y = 80 + (nextColumn.gems.length - 1 - i) * CELL_SIZE;
previewGem.scale.set(0.8);
nextColumnPreview.addChild(previewGem);
}
}
}
function createNewColumn() {
var column = new Column();
column.isActive = true;
column.fastDrop = false; // Initialize fastDrop property for speed control
return column;
}
function startGame() {
// Reset game state
score = 0;
level = 1;
fallSpeed = DROP_INTERVAL_START; // Initialize fallSpeed with the starting drop interval
gameActive = true;
dropTimer = 0;
// Clear frozen gems dictionary
frozenGems = {};
// Create the preview for the next column
if (nextColumnPreview) {
game.removeChild(nextColumnPreview);
}
createNextColumnPreview();
// Set up UI
setupUI();
// Create initial columns
activeColumn = createNewColumn();
nextColumn = createNewColumn();
updateNextColumnPreview();
// Position active column
columnPositionX = Math.floor(COLS / 2);
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
activeColumn.y = 0;
game.addChild(activeColumn);
// Start music
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
}
function processMatches(callback) {
var matches = board.checkMatches();
if (matches.length > 0) {
board.removeMatches(matches, function (points) {
updateScore(points);
board.applyGravity(function (movedGems) {
// Check for chain reactions
if (movedGems) {
processMatches(callback);
} else {
if (callback) {
callback();
}
}
});
});
} else {
if (callback) {
callback();
}
}
}
function spawnNewColumn() {
// If there's already an active column, don't spawn a new one
if (activeColumn && activeColumn.isActive) {
return;
}
activeColumn = nextColumn;
nextColumn = createNewColumn();
updateNextColumnPreview();
columnPositionX = Math.floor(COLS / 2);
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
activeColumn.y = 0;
game.addChild(activeColumn);
// Check if game over
if (!board.canPlaceColumn(columnPositionX)) {
gameActive = false;
LK.showGameOver();
} else {
activeColumn.isActive = true; // Reactivate the new column
}
}
function moveColumnLeft() {
if (!gameActive || !activeColumn || !activeColumn.isActive) {
return;
}
if (columnPositionX > 0) {
// Check if there's a collision in the new position
var canMove = true;
var currentRow = Math.floor(activeColumn.y / CELL_SIZE);
for (var i = 0; i < activeColumn.gems.length; i++) {
var gemRow = currentRow - i;
if (gemRow >= 0 && gemRow < ROWS) {
var gemKey = gemRow + ',' + (columnPositionX - 1);
if (frozenGems[gemKey]) {
canMove = false;
break;
}
}
}
if (canMove) {
columnPositionX--;
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
}
}
}
function moveColumnRight() {
if (!gameActive || !activeColumn || !activeColumn.isActive) {
return;
}
if (columnPositionX < COLS - 1) {
// Check if there's a collision in the new position
var canMove = true;
var currentRow = Math.floor(activeColumn.y / CELL_SIZE);
for (var i = 0; i < activeColumn.gems.length; i++) {
var gemRow = currentRow - i;
if (gemRow >= 0 && gemRow < ROWS) {
var gemKey = gemRow + ',' + (columnPositionX + 1);
if (frozenGems[gemKey]) {
canMove = false;
break;
}
}
}
if (canMove) {
columnPositionX++;
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
}
}
}
function rotateColumn() {
if (!gameActive || !activeColumn) {
return;
}
activeColumn.rotate();
}
function dropColumn() {
if (!gameActive || !activeColumn || !activeColumn.isActive) {
return;
}
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
activeColumn.isActive = false;
board.placeColumn(activeColumn, columnPositionX, function (success, placedGems) {
if (success) {
// Store the positions of the frozen gems
placedGems.forEach(function (placedGem) {
frozenGems[placedGem.row + ',' + placedGem.col] = placedGem.gem;
});
game.removeChild(activeColumn);
processMatches(function () {
spawnNewColumn(); // Spawn a new column after processing matches
});
} else {
// Failed to place column, game over
gameActive = false;
LK.showGameOver();
}
});
}
// Input handlers
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
// Check if touch is in the bottom 10% of the screen
if (y > 2732 * 0.9) {
// If active column exists and is active, apply fast drop (10x speed)
if (activeColumn && activeColumn.isActive) {
// Set a flag for fast dropping
activeColumn.fastDrop = true;
}
return;
}
// Check if no active column is falling - create a new fast-dropping column
if (!activeColumn || !activeColumn.isActive) {
// Only if there's room to place a new column
var newColumnPos = Math.floor(COLS / 2);
if (board.canPlaceColumn(newColumnPos)) {
// Create a new column
activeColumn = createNewColumn();
columnPositionX = newColumnPos;
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
activeColumn.y = 0;
activeColumn.isActive = true;
activeColumn.fastDrop = true; // Make it fast drop immediately
game.addChild(activeColumn);
return;
}
}
// Determine which action to take based on touch position
var boardX = x - board.x;
// If touch is on the board
if (boardX >= 0 && boardX < COLS * CELL_SIZE) {
var touchCol = Math.floor(boardX / CELL_SIZE);
// If touch is on the left side of the active column, move left
if (touchCol < columnPositionX) {
moveColumnLeft();
}
// If touch is on the right side of the active column, move right
else if (touchCol > columnPositionX) {
moveColumnRight();
}
// If touch is on the active column, rotate it
else {
rotateColumn();
}
}
};
game.move = function (x, y, obj) {
// Optional: handle drag for more fluid control
};
game.up = function (x, y, obj) {
// Optional: implement swipe detection for quick drop
if (gameActive && y > game.down.y + 100) {
dropColumn();
}
// Reset fast drop when touch is released
if (activeColumn && activeColumn.isActive) {
activeColumn.fastDrop = false;
}
};
game.update = function () {
if (!gameActive || !activeColumn || !activeColumn.isActive) {
return;
}
// Update column position using rows
var currentRow = Math.floor(activeColumn.y / CELL_SIZE);
// Apply 10x speed multiplier if fast drop is active
var currentFallSpeed = activeColumn.fastDrop ? fallSpeed * 10 : fallSpeed;
// Calculate the next row position based on the current fall speed
dropTimer += currentFallSpeed; // Increment dropTimer by fallSpeed (or fast fallSpeed)
if (dropTimer >= 1000) {
// Check if dropTimer has reached the threshold for a drop
// 1000ms is the base interval for a row drop
dropTimer = 0;
// Check if the column can move down
var canMoveDown = true;
var nextRow = currentRow + 1;
// Check if any gem in the column would collide with a frozen gem
for (var i = 0; i < activeColumn.gems.length; i++) {
var gemRow = nextRow - i;
if (gemRow >= 0 && gemRow < ROWS) {
var gemKey = gemRow + ',' + columnPositionX;
if (frozenGems[gemKey]) {
canMoveDown = false;
break;
}
}
}
// Check if column reached the bottom
// The bottom-most gem in the column is at position nextRow
// So we need to check if this position is beyond the board
if (nextRow >= ROWS) {
canMoveDown = false;
}
if (canMoveDown) {
activeColumn.y = nextRow * CELL_SIZE; // Move down
} else {
// Column has hit something or reached the bottom
dropColumn();
return;
}
}
// Check for immediate collisions (for fast drops or manual movements)
var checkRow = Math.floor(activeColumn.y / CELL_SIZE);
for (var i = 0; i < activeColumn.gems.length; i++) {
var gemRow = checkRow - i;
if (gemRow >= 0 && gemRow < ROWS) {
var gemKey = gemRow + ',' + columnPositionX;
if (frozenGems[gemKey]) {
// Move column back up to avoid overlap
activeColumn.y = (gemRow + i) * CELL_SIZE;
dropColumn();
return;
}
}
}
// Check if column reached the bottom
// Only freeze the column if the bottom-most gem has reached the bottom row
if (checkRow >= ROWS) {
activeColumn.y = (ROWS - 1) * CELL_SIZE;
dropColumn();
return;
}
};
// Initialize the board
if (board) {
game.removeChild(board);
}
createBoard();
// Create and display the title image in the center of the screen
var titleImage = LK.getAsset('title', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
var blackBg = LK.getAsset('blackBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.75
});
game.addChild(blackBg);
game.addChild(titleImage);
startGameText = new Text2('COLUMNI', {
size: 150,
fill: 0xFFFFFF,
align: "center",
font: "Comic Sans MS",
fontWeight: "bold"
});
// Rainbow color array
var rainbowColors = [0xFF0000, 0xFF7F00, 0xFFFF00, 0x00FF00, 0x0000FF, 0x4B0082, 0x8B00FF];
var colorIndex = 0;
// Function to cycle through rainbow colors
function cycleRainbowColors() {
startGameText.tint = rainbowColors[colorIndex];
colorIndex = (colorIndex + 1) % rainbowColors.length;
}
// Set interval to change color every 500ms
LK.setInterval(cycleRainbowColors, 500);
startGameText2 = new Text2('Press on the logo to start...', {
size: 150,
fill: 0xffffff // Changed to black,
});
startGameText.y = 2732 / 2 + 400;
startGameText.x = 2048 / 2 - 400;
startGameText.addChild(startGameText2);
startGameText2.y = 200;
startGameText2.x = -400;
game.addChild(startGameText);
// Function to start the game
// Start the game when the title image is clicked
titleImage.down = function (x, y, obj) {
titleImage.destroy();
startGameText.destroy();
blackBg.destroy();
startGame();
}; ===================================================================
--- original.js
+++ change.js
@@ -626,24 +626,8 @@
columnPositionX = Math.floor(COLS / 2);
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
activeColumn.y = 0;
game.addChild(activeColumn);
- // Set up touch hold detection interval
- game.touchHoldInterval = LK.setInterval(function () {
- if (gameActive && activeColumn && activeColumn.isActive && game.touchStartTime) {
- var now = Date.now();
- var touchDuration = now - game.touchStartTime;
- // If touch is held for more than 300ms on the active column, activate fast drop
- if (touchDuration > 300 && !game.isTouchHeld) {
- var touchCol = game.touchStartCol;
- // Only activate fast drop if touch is on the active column
- if (touchCol === columnPositionX) {
- activeColumn.fastDrop = true;
- game.isTouchHeld = true;
- }
- }
- }
- }, 100);
// Start music
LK.playMusic('bgmusic', {
fade: {
start: 0,
@@ -674,8 +658,12 @@
}
}
}
function spawnNewColumn() {
+ // If there's already an active column, don't spawn a new one
+ if (activeColumn && activeColumn.isActive) {
+ return;
+ }
activeColumn = nextColumn;
nextColumn = createNewColumn();
updateNextColumnPreview();
columnPositionX = Math.floor(COLS / 2);
@@ -684,12 +672,8 @@
game.addChild(activeColumn);
// Check if game over
if (!board.canPlaceColumn(columnPositionX)) {
gameActive = false;
- // Clear touch hold interval when game ends
- if (game.touchHoldInterval) {
- LK.clearInterval(game.touchHoldInterval);
- }
LK.showGameOver();
} else {
activeColumn.isActive = true; // Reactivate the new column
}
@@ -753,10 +737,8 @@
return;
}
activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
activeColumn.isActive = false;
- // Reset any fast drop flags
- activeColumn.fastDrop = false;
board.placeColumn(activeColumn, columnPositionX, function (success, placedGems) {
if (success) {
// Store the positions of the frozen gems
placedGems.forEach(function (placedGem) {
@@ -768,12 +750,8 @@
});
} else {
// Failed to place column, game over
gameActive = false;
- // Clear touch hold interval when game ends
- if (game.touchHoldInterval) {
- LK.clearInterval(game.touchHoldInterval);
- }
LK.showGameOver();
}
});
}
@@ -781,14 +759,8 @@
game.down = function (x, y, obj) {
if (!gameActive) {
return;
}
- // Store touch start time and position for determining tap vs hold
- game.touchStartTime = Date.now();
- game.touchStartX = x;
- game.touchStartY = y;
- game.touchStartCol = Math.floor((x - board.x) / CELL_SIZE);
- game.isTouchHeld = false; // Track if touch is being held
// Check if touch is in the bottom 10% of the screen
if (y > 2732 * 0.9) {
// If active column exists and is active, apply fast drop (10x speed)
if (activeColumn && activeColumn.isActive) {
@@ -796,8 +768,24 @@
activeColumn.fastDrop = true;
}
return;
}
+ // Check if no active column is falling - create a new fast-dropping column
+ if (!activeColumn || !activeColumn.isActive) {
+ // Only if there's room to place a new column
+ var newColumnPos = Math.floor(COLS / 2);
+ if (board.canPlaceColumn(newColumnPos)) {
+ // Create a new column
+ activeColumn = createNewColumn();
+ columnPositionX = newColumnPos;
+ activeColumn.x = board.x + columnPositionX * CELL_SIZE + CELL_SIZE / 2;
+ activeColumn.y = 0;
+ activeColumn.isActive = true;
+ activeColumn.fastDrop = true; // Make it fast drop immediately
+ game.addChild(activeColumn);
+ return;
+ }
+ }
// Determine which action to take based on touch position
var boardX = x - board.x;
// If touch is on the board
if (boardX >= 0 && boardX < COLS * CELL_SIZE) {
@@ -809,61 +797,26 @@
// If touch is on the right side of the active column, move right
else if (touchCol > columnPositionX) {
moveColumnRight();
}
- // For touch on the active column, we'll handle rotation in the up event
- // to differentiate between tap and hold
+ // If touch is on the active column, rotate it
+ else {
+ rotateColumn();
+ }
}
};
game.move = function (x, y, obj) {
- // Check if we're in an active touch/drag sequence
- if (gameActive && game.touchStartTime) {
- var touchDuration = Date.now() - game.touchStartTime;
- var dx = x - game.touchStartX;
- // Allow horizontal drag for movement after holding for a moment
- if (touchDuration > 150 && Math.abs(dx) > 40) {
- // Moved right
- if (dx > 0) {
- moveColumnRight();
- // Update start position to prevent repeated moves
- game.touchStartX = x;
- }
- // Moved left
- else if (dx < 0) {
- moveColumnLeft();
- // Update start position to prevent repeated moves
- game.touchStartX = x;
- }
- }
- // If touch is being held on active column for longer than 300ms
- // keep fastDrop active as they might be dragging around
- if (touchDuration > 300 && game.touchStartCol === columnPositionX) {
- if (activeColumn && activeColumn.isActive) {
- activeColumn.fastDrop = true;
- game.isTouchHeld = true;
- }
- }
- }
+ // Optional: handle drag for more fluid control
};
game.up = function (x, y, obj) {
- // Get the current time to calculate touch duration
- var touchDuration = Date.now() - game.touchStartTime;
- var touchCol = Math.floor((game.touchStartX - board.x) / CELL_SIZE);
+ // Optional: implement swipe detection for quick drop
+ if (gameActive && y > game.down.y + 100) {
+ dropColumn();
+ }
// Reset fast drop when touch is released
if (activeColumn && activeColumn.isActive) {
activeColumn.fastDrop = false;
}
- // Check if this was a tap (not a hold) on the active column
- if (gameActive && touchDuration < 300 && touchCol === columnPositionX) {
- // Short tap on active column - rotate it
- rotateColumn();
- }
- // Implement swipe detection for quick drop
- if (gameActive && y > game.touchStartY + 100) {
- dropColumn();
- }
- // Clear touch tracking variables
- game.isTouchHeld = false;
};
game.update = function () {
if (!gameActive || !activeColumn || !activeColumn.isActive) {
return;