From 7d82c1071310b18510448a2ff29d09bdb59f2c22 Mon Sep 17 00:00:00 2001 From: Brian Fertig Date: Tue, 12 Aug 2025 19:23:41 -0600 Subject: [PATCH] first commit --- .continue/rules/framework.md | 8 ++ index.html | 33 +++++ package.json | 24 ++++ src/main.js | 271 +++++++++++++++++++++++++++++++++++ start_web.bat | 8 ++ 5 files changed, 344 insertions(+) create mode 100644 .continue/rules/framework.md create mode 100644 index.html create mode 100644 package.json create mode 100644 src/main.js create mode 100644 start_web.bat diff --git a/.continue/rules/framework.md b/.continue/rules/framework.md new file mode 100644 index 0000000..19857b0 --- /dev/null +++ b/.continue/rules/framework.md @@ -0,0 +1,8 @@ +--- +name: Phaser 3.90 Framework +--- + +- Follow best practices for Phaser 3.90 +- Follow best ES6 practices +- Write class imports using full .js paths, NPM package manager or any other web packager is not installed +- Break things out into classes when it makes sense \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..5a07ee4 --- /dev/null +++ b/index.html @@ -0,0 +1,33 @@ + + + + + + Phaser 3 Card Battle Game + + + +
+ + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..bf93a48 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "phaser3-card-battle-game", + "version": "1.0.0", + "description": "A deck building card battle game using Phaser 3 with ES6 best practices", + "main": "src/main.js", + "scripts": { + "start": "python -m http.server 8080", + "dev": "npm run start" + }, + "keywords": [ + "phaser3", + "card-game", + "deck-building", + "es6" + ], + "author": "Developer", + "license": "MIT", + "dependencies": { + "phaser": "^3.70.0" + }, + "devDependencies": { + + } +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..042c9a7 --- /dev/null +++ b/src/main.js @@ -0,0 +1,271 @@ +// Phaser is loaded from CDN, so we don't need to import it as a module + +/** + * Main game configuration and initialization + */ +const config = { + type: Phaser.AUTO, + width: 1600, + height: 900, + parent: 'game-container', + scene: { + preload: preload, + create: create, + update: update + }, + scale: { + mode: Phaser.Scale.FIT, + autoCenter: Phaser.Scale.CENTER_BOTH + }, + physics: { + default: 'arcade', + arcade: { + gravity: { y: 0 }, + debug: false + } + } +}; + +/** + * Game instance + */ +let game; + +/** + * Preload function - load all assets before the game starts + */ +function preload() { + console.log('Preloading game assets...'); + + // Create a simple loading bar + const progressBar = this.add.graphics(); + const progressBox = this.add.graphics(); + progressBox.fillStyle(0x242424, 0.8); + progressBox.fillRect(700, 430, 200, 50); + + const width = this.cameras.main.width; + const height = this.cameras.main.height; + const loadingText = this.make.text({ + x: width / 2, + y: height / 2 - 50, + text: 'Loading...', + style: { + font: '20px monospace', + fill: '#ffffff' + } + }); + loadingText.setOrigin(0.5, 0.5); + + const percentText = this.make.text({ + x: width / 2, + y: height / 2 - 5, + text: '0%', + style: { + font: '18px monospace', + fill: '#ffffff' + } + }); + percentText.setOrigin(0.5, 0.5); + + const assetText = this.make.text({ + x: width / 2, + y: height / 2 + 50, + text: '', + style: { + font: '18px monospace', + fill: '#ffffff' + } + }); + assetText.setOrigin(0.5, 0.5); + + // Update loading progress + this.load.on('progress', (value) => { + percentText.setText(parseInt(value * 100) + '%'); + progressBar.clear(); + progressBar.fillStyle(0xffffff, 1); + progressBar.fillRect(700, 430, 200 * value, 50); + }); + + this.load.on('fileprogress', (file) => { + assetText.setText('Loading asset: ' + file.key); + }); + + this.load.on('complete', () => { + progressBar.destroy(); + progressBox.destroy(); + loadingText.destroy(); + percentText.destroy(); + assetText.destroy(); + }); +} + +/** + * Create function - setup the game world and initial state + */ +function create() { + console.log('Creating game scene...'); + + // Set background color + this.cameras.main.setBackgroundColor('#2d5a8c'); + + // Add a simple title text + const title = this.add.text(800, 100, 'Deck Building Card Battle', { + fontSize: '32px', + fill: '#ffffff', + align: 'center' + }); + title.setOrigin(0.5); + + // Create a basic game area + const gameArea = this.add.rectangle(800, 450, 1400, 700, 0x3a7c2d); + gameArea.setOrigin(0.5); + + // Add some instructions + const instructions = this.add.text(800, 850, 'Use mouse to play cards and build your deck', { + fontSize: '16px', + fill: '#ffffff', + align: 'center' + }); + instructions.setOrigin(0.5); + + // Initialize game state + this.gameState = { + playerDeck: [], + opponentDeck: [], + playerHand: [], + opponentHand: [], + playerField: [], + opponentField: [], + selectedCard: null, + turnPhase: 'draw', + currentPlayer: 'player' + }; + + // Create a 10-card deck with numbers 1-10 + this.gameState.playerDeck = []; + for (let i = 1; i <= 10; i++) { + this.gameState.playerDeck.push({ + id: i, + number: i, + type: 'creature', // placeholder type + attack: Math.floor(Math.random() * 5) + 1, // random attack value + health: Math.floor(Math.random() * 5) + 1 // random health value + }); + } + + // Shuffle the deck using Fisher-Yates algorithm (using Phaser's scope) + shuffleDeck(this.gameState.playerDeck); + + // Deal 3 cards to player's hand + this.gameState.playerHand = this.gameState.playerDeck.splice(0, 3); + + // Display the player's hand at the bottom of the screen + displayPlayerHand.call(this); + + console.log('Game scene created successfully'); +} + +/** + * Shuffle an array using Fisher-Yates algorithm + */ +function shuffleDeck(deck) { + for (let i = deck.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [deck[i], deck[j]] = [deck[j], deck[i]]; + } +} + +/** + * Display the player's hand at the bottom of the screen + */ +function displayPlayerHand() { + const cardWidth = 100; + const cardHeight = 140; + const spacing = 20; + + // Calculate total width needed for all cards + const totalWidth = (this.gameState.playerHand.length * cardWidth) + ((this.gameState.playerHand.length - 1) * spacing); + + // Starting x position to center the hand + const startX = (1600 - totalWidth) / 2; + + // Position cards at the bottom of the screen + const yPosition = 850; + + this.gameState.playerHand.forEach((card, index) => { + const xPosition = startX + (index * (cardWidth + spacing)); + + // Create a simple card placeholder with number + const cardSprite = this.add.rectangle(xPosition, yPosition, cardWidth, cardHeight, 0x8B4513); + cardSprite.setOrigin(0.5); + + // Add the number to the card + const numberText = this.add.text(xPosition, yPosition - 20, `${card.number}`, { + fontSize: '24px', + fill: '#ffffff' + }); + numberText.setOrigin(0.5); + + // Store card data with sprite reference + card.sprite = cardSprite; + card.text = numberText; + + // Add hover events for the card + addInteractiveCard.call(this, card, xPosition, yPosition, cardWidth, cardHeight); + }); +} + +/** + * Make a single card interactive with hover effects + */ +function addInteractiveCard(card, xPosition, yPosition, width, height) { + const originalY = yPosition; + + // Create a transparent hit area for the card that matches its dimensions + const hitArea = this.add.rectangle(xPosition, yPosition + 70, width - 10, height - 10); + hitArea.setOrigin(0.5); + hitArea.setInteractive(); + + // Add event listeners for hover effects + hitArea.on('pointerover', () => { + // Raise the card up to full view (move it up by 30 pixels) + if (card.sprite) { + card.sprite.setY(originalY - 30); + } + if (card.text) { + card.text.setY(originalY - 50); + } + }); + + hitArea.on('pointerout', () => { + // Return the card to its original position + if (card.sprite) { + card.sprite.setY(originalY); + } + if (card.text) { + card.text.setY(originalY - 20); + } + }); +} + +/** + * Update function - called every frame + */ +function update() { + // Game logic updates go here +} + +/** + * Initialize the game when the page loads + */ +document.addEventListener('DOMContentLoaded', () => { + console.log('Initializing Phaser 3 card battle game...'); + + // Create the game instance + game = new Phaser.Game(config); + + console.log('Phaser 3 card battle game initialized'); +}); + +// Export for potential module usage (not needed when using CDN) +// export { config, game }; diff --git a/start_web.bat b/start_web.bat new file mode 100644 index 0000000..d85b0be --- /dev/null +++ b/start_web.bat @@ -0,0 +1,8 @@ +@echo off +echo Starting local web server for Phaser 3 card battle game... +echo. +echo Open your browser and navigate to http://localhost:8080 +echo. +echo Press Ctrl+C to stop the server. + +python -m http.server 8080