first commit
This commit is contained in:
commit
7d82c10713
|
|
@ -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
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -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": {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 };
|
||||||
|
|
@ -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
|
||||||
Loading…
Reference in New Issue