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.
This commit is contained in:
parent
31c7eaefb6
commit
e9cb2a939d
167
src/GameScene.js
167
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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ const GAME_CONFIG = {
|
|||
physics: {
|
||||
default: 'arcade',
|
||||
arcade: {
|
||||
gravity: { y: 100 },
|
||||
gravity: { y: 0 },
|
||||
debug: false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue