first commit

This commit is contained in:
Brian Fertig 2025-08-12 19:23:41 -06:00
commit 7d82c10713
5 changed files with 344 additions and 0 deletions

View File

@ -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

33
index.html Normal file
View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Phaser 3 Card Battle Game</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
#game-container {
width: 1600px;
height: 900px;
}
</style>
</head>
<body>
<div id="game-container"></div>
<!-- Load Phaser 3 from CDN -->
<script src="https://cdn.jsdelivr.net/npm/phaser@3.70.0/dist/phaser.min.js"></script>
<!-- Game script -->
<script src="src/main.js" type="module"></script>
</body>
</html>

24
package.json Normal file
View File

@ -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": {
}
}

271
src/main.js Normal file
View File

@ -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 };

8
start_web.bat Normal file
View File

@ -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