Compare commits
3 Commits
8e8bc514ad
...
a4931d491a
| Author | SHA1 | Date |
|---|---|---|
|
|
a4931d491a | |
|
|
a07d64e9b1 | |
|
|
c6a1d928a6 |
315
src/main.js
315
src/main.js
|
|
@ -116,9 +116,14 @@ function create() {
|
||||||
});
|
});
|
||||||
title.setOrigin(0.5);
|
title.setOrigin(0.5);
|
||||||
|
|
||||||
// Create a basic game area
|
// Add player and opponent rows for cards in center of screen
|
||||||
const gameArea = this.add.rectangle(800, 450, 1400, 700, 0x3a7c2d);
|
// Player row at bottom (closest to player)
|
||||||
gameArea.setOrigin(0.5);
|
const playerRow = this.add.rectangle(800, 600, 1400, 120, 0x3a7c2d);
|
||||||
|
playerRow.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Opponent row at top (closest to opponent)
|
||||||
|
const opponentRow = this.add.rectangle(800, 300, 1400, 120, 0x3a7c2d);
|
||||||
|
opponentRow.setOrigin(0.5);
|
||||||
|
|
||||||
// Add some instructions
|
// Add some instructions
|
||||||
const instructions = this.add.text(800, 850, 'Use mouse to play cards and build your deck', {
|
const instructions = this.add.text(800, 850, 'Use mouse to play cards and build your deck', {
|
||||||
|
|
@ -144,15 +149,25 @@ function create() {
|
||||||
// Assign the first deck (deck1) to the player
|
// Assign the first deck (deck1) to the player
|
||||||
this.gameState.playerDeck = [...window.deck1];
|
this.gameState.playerDeck = [...window.deck1];
|
||||||
|
|
||||||
// Shuffle the deck using Fisher-Yates algorithm (using Phaser's scope)
|
// Assign deck2 to the opponent
|
||||||
|
this.gameState.opponentDeck = [...window.deck2];
|
||||||
|
|
||||||
|
// Shuffle both decks using Fisher-Yates algorithm (using Phaser's scope)
|
||||||
shuffleDeck(this.gameState.playerDeck);
|
shuffleDeck(this.gameState.playerDeck);
|
||||||
|
shuffleDeck(this.gameState.opponentDeck);
|
||||||
|
|
||||||
// Deal 3 cards to player's hand
|
// Deal 3 cards to player's hand
|
||||||
this.gameState.playerHand = this.gameState.playerDeck.splice(0, 3);
|
this.gameState.playerHand = this.gameState.playerDeck.splice(0, 3);
|
||||||
|
|
||||||
|
// Deal 3 cards to opponent's hand
|
||||||
|
this.gameState.opponentHand = this.gameState.opponentDeck.splice(0, 3);
|
||||||
|
|
||||||
// Display the player's hand at the bottom of the screen
|
// Display the player's hand at the bottom of the screen
|
||||||
displayPlayerHand.call(this);
|
displayPlayerHand.call(this);
|
||||||
|
|
||||||
|
// Display the opponent's hand at the top of the screen (face down)
|
||||||
|
displayOpponentHand.call(this);
|
||||||
|
|
||||||
console.log('Game scene created successfully');
|
console.log('Game scene created successfully');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,6 +212,32 @@ function displayPlayerHand() {
|
||||||
});
|
});
|
||||||
numberText.setOrigin(0.5);
|
numberText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Display attack in upper left corner
|
||||||
|
const attackText = this.add.text(xPosition - 40, yPosition - 50, `A:${card.attack}`, {
|
||||||
|
fontSize: '16px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
attackText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Display shield in lower left corner
|
||||||
|
const shieldText = this.add.text(xPosition - 40, yPosition + 50, `S:${card.shield}`, {
|
||||||
|
fontSize: '16px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
shieldText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Display health in lower right corner
|
||||||
|
const healthText = this.add.text(xPosition + 40, yPosition + 50, `H:${card.health}`, {
|
||||||
|
fontSize: '16px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
healthText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Store references to stat texts with sprite reference
|
||||||
|
card.attackText = attackText;
|
||||||
|
card.shieldText = shieldText;
|
||||||
|
card.healthText = healthText;
|
||||||
|
|
||||||
// Store card data with sprite reference
|
// Store card data with sprite reference
|
||||||
card.sprite = cardSprite;
|
card.sprite = cardSprite;
|
||||||
card.text = numberText;
|
card.text = numberText;
|
||||||
|
|
@ -206,6 +247,44 @@ function displayPlayerHand() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the opponent's hand at the top of the screen (face down)
|
||||||
|
*/
|
||||||
|
function displayOpponentHand() {
|
||||||
|
const cardWidth = 100;
|
||||||
|
const cardHeight = 140;
|
||||||
|
const spacing = 20;
|
||||||
|
|
||||||
|
// Calculate total width needed for all cards
|
||||||
|
const totalWidth = (this.gameState.opponentHand.length * cardWidth) + ((this.gameState.opponentHand.length - 1) * spacing);
|
||||||
|
|
||||||
|
// Starting x position to center the hand
|
||||||
|
const startX = (1600 - totalWidth) / 2;
|
||||||
|
|
||||||
|
// Position cards at the top of the screen (opponent's row)
|
||||||
|
const yPosition = 350; // Slightly below opponentRow rectangle (which is at y=300)
|
||||||
|
|
||||||
|
this.gameState.opponentHand.forEach((card, index) => {
|
||||||
|
const xPosition = startX + (index * (cardWidth + spacing));
|
||||||
|
|
||||||
|
// Create a simple card placeholder - face down (gray color)
|
||||||
|
const cardSprite = this.add.rectangle(xPosition, yPosition, cardWidth, cardHeight, 0x808080); // Gray color for face-down cards
|
||||||
|
cardSprite.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Add the number to the card (face down - show only number)
|
||||||
|
const numberText = this.add.text(xPosition, yPosition - 20, `${card.number}`, {
|
||||||
|
fontSize: '24px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
numberText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// For face-down cards, we don't display attack/shield/health values
|
||||||
|
// Store references to sprite with no stat texts for opponent's hand
|
||||||
|
card.sprite = cardSprite;
|
||||||
|
card.text = numberText;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a single card interactive with hover effects
|
* Make a single card interactive with hover effects
|
||||||
*/
|
*/
|
||||||
|
|
@ -219,40 +298,72 @@ function addInteractiveCard(card, xPosition, yPosition, width, height) {
|
||||||
|
|
||||||
// Add event listeners for hover effects
|
// Add event listeners for hover effects
|
||||||
hitArea.on('pointerover', () => {
|
hitArea.on('pointerover', () => {
|
||||||
// Raise the card up to full view (move it up by 30 pixels)
|
// Only allow hover effects if the card is in hand (not already on field)
|
||||||
if (card.sprite) {
|
const isInHand = this.gameState.playerHand.includes(card);
|
||||||
card.sprite.setY(originalY - 30);
|
if (isInHand && !card.isLocked) {
|
||||||
}
|
// Raise the card up to full view (move it up by 30 pixels)
|
||||||
if (card.text) {
|
if (card.sprite) {
|
||||||
card.text.setY(originalY - 50);
|
card.sprite.setY(originalY - 30);
|
||||||
|
}
|
||||||
|
if (card.text) {
|
||||||
|
card.text.setY(originalY - 50);
|
||||||
|
}
|
||||||
|
// Move stat texts with the card
|
||||||
|
if (card.attackText) {
|
||||||
|
card.attackText.setY(originalY - 80);
|
||||||
|
}
|
||||||
|
if (card.shieldText) {
|
||||||
|
card.shieldText.setY(originalY + 20);
|
||||||
|
}
|
||||||
|
if (card.healthText) {
|
||||||
|
card.healthText.setY(originalY + 20);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
hitArea.on('pointerout', () => {
|
hitArea.on('pointerout', () => {
|
||||||
// Return the card to its original position
|
// Only allow hover effects if the card is in hand (not already on field)
|
||||||
if (card.sprite && !card.isLocked) {
|
const isInHand = this.gameState.playerHand.includes(card);
|
||||||
card.sprite.setY(originalY);
|
if (isInHand && !card.isLocked) {
|
||||||
}
|
// Return the card to its original position
|
||||||
if (card.text && !card.isLocked) {
|
if (card.sprite) {
|
||||||
card.text.setY(originalY - 20);
|
card.sprite.setY(originalY);
|
||||||
|
}
|
||||||
|
if (card.text) {
|
||||||
|
card.text.setY(originalY - 20);
|
||||||
|
}
|
||||||
|
// Return stat texts to original positions
|
||||||
|
if (card.attackText) {
|
||||||
|
card.attackText.setY(originalY - 50);
|
||||||
|
}
|
||||||
|
if (card.shieldText) {
|
||||||
|
card.shieldText.setY(originalY + 50);
|
||||||
|
}
|
||||||
|
if (card.healthText) {
|
||||||
|
card.healthText.setY(originalY + 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add click event to lock the card in place
|
// Add click event to lock the card in place
|
||||||
hitArea.on('pointerdown', () => {
|
hitArea.on('pointerdown', () => {
|
||||||
// Lock the card in its current position
|
// Only allow clicking if the card is in hand (not already on field)
|
||||||
card.isLocked = true;
|
const isInHand = this.gameState.playerHand.includes(card);
|
||||||
|
if (isInHand) {
|
||||||
// Remove hover effects while locked
|
// Lock the card in its current position
|
||||||
if (card.sprite) {
|
card.isLocked = true;
|
||||||
card.sprite.setY(originalY - 30); // Keep it raised up when locked
|
|
||||||
|
// Remove hover effects while locked
|
||||||
|
if (card.sprite) {
|
||||||
|
card.sprite.setY(originalY - 30); // Keep it raised up when locked
|
||||||
|
}
|
||||||
|
if (card.text) {
|
||||||
|
card.text.setY(originalY - 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Play and Cancel buttons above the card
|
||||||
|
createCardButtons.call(this, card, xPosition, originalY - 30);
|
||||||
}
|
}
|
||||||
if (card.text) {
|
|
||||||
card.text.setY(originalY - 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Play and Cancel buttons above the card
|
|
||||||
createCardButtons.call(this, card, xPosition, originalY - 30);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,38 +436,59 @@ function createCardButtons(card, xPosition, yPosition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move a card to the player's field (center of screen)
|
* Move a card to the player's field (player row on far right)
|
||||||
*/
|
*/
|
||||||
function moveCardToField(card) {
|
function moveCardToField(card) {
|
||||||
// For now, we'll just remove it from hand and add it to field
|
// Remove it from hand and add it to field
|
||||||
// In a real implementation this would involve more complex logic
|
|
||||||
const index = this.gameState.playerHand.indexOf(card);
|
const index = this.gameState.playerHand.indexOf(card);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.gameState.playerHand.splice(index, 1);
|
this.gameState.playerHand.splice(index, 1);
|
||||||
this.gameState.playerField.push(card);
|
this.gameState.playerField.push(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the card from display
|
// Calculate starting position for the animation (right side of screen)
|
||||||
if (card.sprite) {
|
const startX = 1600 + 50; // Start just off-screen to the right
|
||||||
card.sprite.destroy();
|
const startY = 600; // Player field y-position (bottom row)
|
||||||
}
|
|
||||||
if (card.text) {
|
|
||||||
card.text.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-display the player's hand to update positions of remaining cards
|
// Calculate target x position based on how many cards are already in the field
|
||||||
// Clear existing hand display first by removing all sprites and texts
|
// Cards stack from right to left with each card being 120px wide + 20px spacing
|
||||||
this.gameState.playerHand.forEach(handCard => {
|
const cardWidth = 100;
|
||||||
if (handCard.sprite) {
|
const spacing = 20;
|
||||||
handCard.sprite.destroy();
|
const currentFieldCount = this.gameState.playerField.length - 1; // -1 because we just added the new card
|
||||||
}
|
const targetX = 1600 - (cardWidth + spacing) * currentFieldCount - (cardWidth / 2); // Position from right edge
|
||||||
if (handCard.text) {
|
|
||||||
handCard.text.destroy();
|
// Animate the card moving from right to left towards its final position in player field
|
||||||
}
|
this.tweens.add({
|
||||||
|
targets: [card.sprite, card.text, card.attackText, card.shieldText, card.healthText],
|
||||||
|
x: targetX,
|
||||||
|
y: startY,
|
||||||
|
duration: 500, // 500ms animation time
|
||||||
|
ease: 'Power2'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redisplay the updated player's hand at the bottom of the screen
|
// Set the current player to CPU after playing a card
|
||||||
displayPlayerHand.call(this);
|
this.gameState.currentPlayer = 'cpu';
|
||||||
|
|
||||||
|
// Re-display the player's hand to update positions of remaining cards after animation completes
|
||||||
|
setTimeout(() => {
|
||||||
|
// Clear existing hand display first by removing all sprites and texts
|
||||||
|
this.gameState.playerHand.forEach(handCard => {
|
||||||
|
if (handCard.sprite) {
|
||||||
|
handCard.sprite.destroy();
|
||||||
|
}
|
||||||
|
if (handCard.text) {
|
||||||
|
handCard.text.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Redisplay the updated player's hand at the bottom of the screen
|
||||||
|
displayPlayerHand.call(this);
|
||||||
|
}, 500); // Wait for animation to complete before updating hand
|
||||||
|
|
||||||
|
// After a short delay, have CPU play a card automatically (if available)
|
||||||
|
setTimeout(() => {
|
||||||
|
cpuPlayCard.call(this);
|
||||||
|
}, 1000); // Small delay before CPU plays card
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -410,6 +542,91 @@ function removeCardButtons(card) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CPU plays a random card from its hand
|
||||||
|
*/
|
||||||
|
function cpuPlayCard() {
|
||||||
|
// Only play a card if it's the CPU's turn and they have cards in hand
|
||||||
|
if (this.gameState.currentPlayer !== 'cpu' || this.gameState.opponentHand.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select a random card from opponent's hand
|
||||||
|
const randomIndex = Math.floor(Math.random() * this.gameState.opponentHand.length);
|
||||||
|
const card = this.gameState.opponentHand[randomIndex];
|
||||||
|
|
||||||
|
// Remove it from hand and add it to field
|
||||||
|
this.gameState.opponentHand.splice(randomIndex, 1);
|
||||||
|
this.gameState.opponentField.push(card);
|
||||||
|
|
||||||
|
// Calculate starting position for the animation (left side of screen)
|
||||||
|
const startX = -50; // Start just off-screen to the left
|
||||||
|
const startY = 300; // Opponent field y-position (top row)
|
||||||
|
|
||||||
|
// Calculate target x position based on how many cards are already in the field
|
||||||
|
// Cards stack from left to right with each card being 120px wide + 20px spacing
|
||||||
|
const cardWidth = 100;
|
||||||
|
const spacing = 20;
|
||||||
|
const currentFieldCount = this.gameState.opponentField.length - 1; // -1 because we just added the new card
|
||||||
|
const targetX = (cardWidth + spacing) * currentFieldCount + (cardWidth / 2); // Position from left edge
|
||||||
|
|
||||||
|
// For CPU cards in field, show full stats (not face-down)
|
||||||
|
const cpuCardSprite = this.add.rectangle(targetX, startY, cardWidth, 140, 0x8B4513); // Brown color for card background
|
||||||
|
cpuCardSprite.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Add the number to the CPU's played card (showing full stats)
|
||||||
|
const numberText = this.add.text(targetX, startY - 20, `${card.number}`, {
|
||||||
|
fontSize: '24px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
numberText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Display attack in upper left corner for CPU card
|
||||||
|
const attackText = this.add.text(targetX - 40, startY - 50, `A:${card.attack}`, {
|
||||||
|
fontSize: '16px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
attackText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Display shield in lower left corner for CPU card
|
||||||
|
const shieldText = this.add.text(targetX - 40, startY + 50, `S:${card.shield}`, {
|
||||||
|
fontSize: '16px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
shieldText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Display health in lower right corner for CPU card
|
||||||
|
const healthText = this.add.text(targetX + 40, startY + 50, `H:${card.health}`, {
|
||||||
|
fontSize: '16px',
|
||||||
|
fill: '#ffffff'
|
||||||
|
});
|
||||||
|
healthText.setOrigin(0.5);
|
||||||
|
|
||||||
|
// Animate the card moving from left to right towards its final position in opponent field
|
||||||
|
this.tweens.add({
|
||||||
|
targets: [cpuCardSprite, numberText, attackText, shieldText, healthText],
|
||||||
|
x: targetX,
|
||||||
|
y: startY,
|
||||||
|
duration: 500, // 500ms animation time
|
||||||
|
ease: 'Power2'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the card's sprite and text references to point to the new elements for CPU field display
|
||||||
|
card.sprite = cpuCardSprite;
|
||||||
|
card.text = numberText;
|
||||||
|
card.attackText = attackText;
|
||||||
|
card.shieldText = shieldText;
|
||||||
|
card.healthText = healthText;
|
||||||
|
|
||||||
|
// After a short delay, return to player's turn (or end game if needed)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.gameState.currentPlayer = 'player';
|
||||||
|
|
||||||
|
// Redisplay the opponent's hand at the top of the screen - now only cards that remain in hand
|
||||||
|
displayOpponentHand.call(this);
|
||||||
|
}, 1000); // Wait for animation to complete before returning to player turn
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the game when the page loads
|
* Initialize the game when the page loads
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue