From e9cb2a939dc930dadb4f6595abee2a114b0c60c5 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Sat, 23 Aug 2025 13:44:24 -0600 Subject: [PATCH] feat: Implement jewel selection and swapping mechanics with visual feedback - Increased starting rows from 2 to 5 for larger initial grid - Added selectedJewel and swapWithJewel properties for tracking selections - Enhanced world bounds to provide better collision detection area - Implemented click handling for jewels with selection/deselection logic - Added adjacent jewel checking and swapping functionality with animations - Included visual feedback through scaling tweens when selecting jewels - Implemented isSwapping flag to prevent concurrent interactions during swaps - Disabled interactivity during swap animations and re-enabled afterward - Removed gravity from arcade physics for puzzle game behavior The changes implement core gameplay mechanics for a match-three style puzzle game where players can select jewels, check adjacency, and swap positions with visual feedback. --- src/GameScene.js | 167 +++++++++++++++++++++++++++++++++++++++++++++-- src/main.js | 2 +- 2 files changed, 161 insertions(+), 8 deletions(-) diff --git a/src/GameScene.js b/src/GameScene.js index a7e14ac..89de80c 100644 --- a/src/GameScene.js +++ b/src/GameScene.js @@ -12,9 +12,13 @@ export class GameScene extends Phaser.Scene { }; this.numberOfJewels = 5; - this.startRows = 2; + this.startRows = 5; this.level = 1; this.levelTime = 60; + + // Add selectedJewel property + this.selectedJewel = null; + this.swapWithJewel = null; } preload() { @@ -26,23 +30,18 @@ export class GameScene extends Phaser.Scene { create() { this.makeGrid(); - this.physics.world.setBounds(this.grid.getBounds().x, this.grid.getBounds().y, this.grid.getBounds().width, this.grid.getBounds().height); + this.physics.world.setBounds(this.grid.getBounds().x - 50, this.grid.getBounds().y - 50, this.grid.getBounds().width + 100, this.grid.getBounds().height + 100); this.jewels = this.physics.add.group({ collideWorldBounds: true, }); this.physics.add.collider(this.jewels, this.jewels); this.createStart(); - this.createJewel(this.getJewelAtPosition(1, 7), 3, 3); } update(time, delta) { } - selectJewel(x, y) { - - } - makeGrid() { this.grid = this.add.rectangle( this.gridConfig.leftPadding + this.gridConfig.allPadding, @@ -62,9 +61,18 @@ export class GameScene extends Phaser.Scene { 'jewels', type ); + jewel.setOrigin(0.5); jewel.setDisplaySize(this.gridConfig.jewelWidth, this.gridConfig.jewelHeight); jewel.jewelType = type; this.jewels.add(jewel); + + // Add click event to the jewel + jewel.setInteractive(); + jewel.on('pointerdown', () => { + this.handleJewelClick(jewel.x, jewel.y); + }); + + return jewel; } createStart() { @@ -119,4 +127,149 @@ export class GameScene extends Phaser.Scene { // Return the jewel type or null if not found return jewelAtPosition ? jewelAtPosition.jewelType : null; } + + // New function to handle jewel clicks + handleJewelClick(x, y) { + // Find which jewel was clicked + const clickedJewel = this.getJewelAtWorldPosition(x, y); + + if (!clickedJewel || this.isSwapping) { + return; + } + + // If no jewel is currently selected + if (!this.selectedJewel) { + this.selectJewel(clickedJewel); + return; + } + + // If clicking on the already selected jewel, deselect it + if (clickedJewel === this.selectedJewel) { + this.deselectJewel(); + return; + } + + // Check if clicked jewel is adjacent to selected jewel + const isAdjacent = this.isAdjacent(this.selectedJewel, clickedJewel); + + if (isAdjacent) { + // Mark for swap + this.selectJewelForSwap(clickedJewel); + } else { + // Deselect current and select new jewel + this.deselectJewel(); + this.selectJewel(clickedJewel); + } + } + + // Helper function to get jewel at world position + getJewelAtWorldPosition(x, y) { + let closestJewel = null; + let minDistance = Infinity; + + this.jewels.children.iterate((jewel) => { + if (jewel) { + const distance = Phaser.Math.Distance.Between(jewel.x, jewel.y, x, y); + if (distance < minDistance && distance < 50) { // 50 is half of jewel width/height + minDistance = distance; + closestJewel = jewel; + } + } + }); + + return closestJewel; + } + + // Helper function to check if two jewels are adjacent (horizontally or vertically) + isAdjacent(jewel1, jewel2) { + const col1 = Math.floor((jewel1.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth); + const row1 = Math.floor(jewel1.y / this.gridConfig.jewelHeight); + + const col2 = Math.floor((jewel2.x - this.gridConfig.leftPadding) / this.gridConfig.jewelWidth); + const row2 = Math.floor(jewel2.y / this.gridConfig.jewelHeight); + + // Check if jewels are adjacent (same row and adjacent columns, or same column and adjacent rows) + return (row1 === row2 && Math.abs(col1 - col2) === 1) || (col1 === col2 && Math.abs(row1 - row2) === 1); + } + + // Helper function to select a jewel for swap + selectJewelForSwap(jewel) { + this.swapWithJewel = jewel; + this.tweens.add({ + targets: this.selectedJewel, + scale: 1, + duration: 200 + }); + this.swapJewel(); + } + + // Helper function to select a jewel for swap + selectJewel(jewel) { + this.selectedJewel = jewel; + this.tweens.add({ + targets: jewel, + scale: 1.2, + duration: 200 + }); + } + + // Helper function to deselect a jewel + deselectJewel() { + if (this.selectedJewel) { + this.tweens.add({ + targets: this.selectedJewel, + scale: 1, + duration: 200 + }); + this.selectedJewel = null; + } + } + + // Modified swap function to disable clicks during execution + swapJewel() { + // Set swapping flag to prevent new clicks from being processed + this.isSwapping = true; + + // Disable all jewel interactivity temporarily + this.jewels.children.iterate((jewel) => { + if (jewel) { + jewel.disableInteractive(); + } + }); + + // Perform the swap animation here - currently empty + const fromX = this.selectedJewel.x; + const fromY = this.selectedJewel.y; + const toX = this.swapWithJewel.x; + const toY = this.swapWithJewel.y; + this.tweens.add({ + targets: this.selectedJewel, + x: toX, + y: toY, + duration: 300 + }); + this.tweens.add({ + targets: this.swapWithJewel, + x: fromX, + y: fromY, + duration: 300 + }); + this.selectedJewel = null; + this.swapWithJewel = null; + + + // After swap completes, re-enable interactivity and reset flag + this.time.delayedCall(500, () => { // Adjust delay as needed for animation duration + this.jewels.children.iterate((jewel) => { + if (jewel) { + jewel.setInteractive(); + } + }); + + this.isSwapping = false; + }); + + // Check for Matches + + } } \ No newline at end of file diff --git a/src/main.js b/src/main.js index 8e4dd62..f8b5a9c 100644 --- a/src/main.js +++ b/src/main.js @@ -17,7 +17,7 @@ const GAME_CONFIG = { physics: { default: 'arcade', arcade: { - gravity: { y: 100 }, + gravity: { y: 0 }, debug: false } }