First Working Version

This commit is contained in:
Brian Fertig 2025-08-03 10:31:58 -06:00
parent de94402c96
commit fa73b3c44f
8 changed files with 303 additions and 0 deletions

BIN
assets/music/NeonPulse.mp3 Normal file

Binary file not shown.

Binary file not shown.

38
index.html Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Zenith Vector</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #000;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Arial', sans-serif;
}
#game-container {
position: relative;
}
</style>
</head>
<body>
<div id="game-container"></div>
<!-- Load Phaser from local file -->
<script src="phaser.min.js"></script>
<!-- Import game modules using ES6 modules -->
<script type="module">
import { config } from './src/config.js';
import { GameScene } from './src/scenes/GameScene.js';
const game = new Phaser.Game(config);
game.scene.add('GameScene', GameScene, true);
</script>
</body>
</html>

1
phaser.min.js vendored Normal file

File diff suppressed because one or more lines are too long

18
src/config.js Normal file
View File

@ -0,0 +1,18 @@
export const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'game-container',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 0 },
debug: false
}
},
scene: {
preload: function() {},
create: function() {},
update: function() {}
}
};

66
src/objects/Player.js Normal file
View File

@ -0,0 +1,66 @@
class Player extends Phaser.GameObjects.Container {
constructor(scene, x, y) {
super(scene, x, y);
// Create the player sprite
this.sprite = scene.add.sprite(0, 0, 'player');
this.add(this.sprite);
// Set up input controls using A/D keys instead of arrow keys
this.keys = scene.input.keyboard.addKeys({
a: Phaser.Input.Keyboard.KeyCodes.A,
d: Phaser.Input.Keyboard.KeyCodes.D
});
// Player properties
this.speed = 200;
this.health = 100;
this.isAlive = true;
// Set initial position
this.setPosition(x, y);
}
update() {
if (!this.isAlive) return;
// Move with A/D keys instead of arrow keys
if (this.keys.a.isDown) {
this.x -= this.speed * this.scene.game.loop.delta / 1000;
}
if (this.keys.d.isDown) {
this.x += this.speed * this.scene.game.loop.delta / 1000;
}
// Keep player within bounds
this.x = Phaser.Math.Clamp(this.x, 25, 775);
// Update position of the container's child sprite
this.sprite.setPosition(0, 0);
}
aimAt(targetX, targetY) {
// Not used in current implementation but kept for potential future use
}
fire() {
if (!this.isAlive) return;
// Fire bullet from player position
const bullet = new Bullet(this.scene, this.x, this.y - 20);
this.scene.bullets.add(bullet);
// Set bullet velocity
bullet.setVelocityY(-300);
}
hit(damage) {
if (!this.isAlive) return;
this.health -= damage;
if (this.health <= 0) {
this.destroy();
}
}
}

179
src/scenes/GameScene.js Normal file
View File

@ -0,0 +1,179 @@
export class GameScene extends Phaser.Scene {
constructor() {
super({ key: 'GameScene' });
// Game objects references
this.player = null;
this.enemies = null;
this.bullets = null;
this.cursors = null;
// Game state
this.score = 0;
this.gameOver = false;
}
preload() {
// Load assets here (will be implemented in a later step)
console.log('Loading assets...');
// Create simple placeholder graphics for now
this.createPlaceholderGraphics();
}
create() {
// Set background color
this.cameras.main.setBackgroundColor('#0a0a2a');
// Create player ship
this.player = this.physics.add.sprite(400, 500, 'player');
this.player.setCollideWorldBounds(true);
// Create groups for bullets and enemies
this.bullets = this.physics.add.group();
this.enemies = this.physics.add.group();
// Setup controls
this.cursors = this.input.keyboard.createCursorKeys();
// Setup collision detection
this.physics.add.overlap(this.bullets, this.enemies, this.hitEnemy, null, this);
this.physics.add.overlap(this.player, this.enemies, this.hitPlayer, null, this);
// Start enemy spawning
this.time.addEvent({
delay: 1000,
callback: this.spawnEnemy,
callbackScope: this,
loop: true
});
// Create UI elements
this.createUI();
}
update() {
if (this.gameOver) return;
// Player movement
if (this.cursors.left.isDown) {
this.player.setVelocityX(-200);
} else if (this.cursors.right.isDown) {
this.player.setVelocityX(200);
} else {
this.player.setVelocityX(0);
}
// Shooting
if (Phaser.Input.Keyboard.JustDown(this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE))) {
this.shoot();
}
}
createPlaceholderGraphics() {
// Create simple placeholder graphics for player, bullets and enemies
const canvas = document.createElement('canvas');
canvas.width = 32;
canvas.height = 32;
// Player ship (triangle)
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#00ffcc';
ctx.beginPath();
ctx.moveTo(16, 5);
ctx.lineTo(5, 30);
ctx.lineTo(27, 30);
ctx.closePath();
ctx.fill();
this.textures.addCanvas('player', canvas);
// Enemy (square)
const enemyCanvas = document.createElement('canvas');
enemyCanvas.width = 24;
enemyCanvas.height = 24;
const eCtx = enemyCanvas.getContext('2d');
eCtx.fillStyle = '#ff3366';
eCtx.fillRect(0, 0, 24, 24);
this.textures.addCanvas('enemy', enemyCanvas);
// Bullet (small circle)
const bulletCanvas = document.createElement('canvas');
bulletCanvas.width = 8;
bulletCanvas.height = 8;
const bCtx = bulletCanvas.getContext('2d');
bCtx.fillStyle = '#ffff00';
bCtx.beginPath();
bCtx.arc(4, 4, 3, 0, Math.PI * 2);
bCtx.fill();
this.textures.addCanvas('bullet', bulletCanvas);
}
createUI() {
// Create score text
this.scoreText = this.add.text(16, 16, 'Score: 0', {
fontSize: '32px',
fill: '#ffffff',
fontFamily: 'Arial'
});
// Create game title
this.titleText = this.add.text(400, 50, 'Zenith Vector', {
fontSize: '48px',
fill: '#00ffcc',
fontFamily: 'Arial',
align: 'center'
});
this.titleText.setOrigin(0.5);
}
shoot() {
const bullet = this.bullets.create(this.player.x, this.player.y - 20, 'bullet');
bullet.setVelocityY(-300);
bullet.setScale(1.5);
}
spawnEnemy() {
const x = Phaser.Math.Between(20, 780);
const enemy = this.enemies.create(x, 0, 'enemy');
// Randomize enemy speed
const speed = Phaser.Math.Between(50, 150);
enemy.setVelocityY(speed);
// Add some rotation for visual effect
enemy.setRotation(Phaser.Math.FloatBetween(-0.2, 0.2));
}
hitEnemy(bullet, enemy) {
bullet.destroy();
enemy.destroy();
this.score += 10;
this.scoreText.setText('Score: ' + this.score);
}
hitPlayer(player, enemy) {
player.destroy();
enemy.destroy();
this.gameOver = true;
// Show game over text
const gameOverText = this.add.text(400, 300, 'GAME OVER', {
fontSize: '64px',
fill: '#ff3366',
fontFamily: 'Arial'
});
gameOverText.setOrigin(0.5);
// Restart game after delay
this.time.delayedCall(2000, () => {
this.scene.restart();
});
}
}

1
start_web.bat Normal file
View File

@ -0,0 +1 @@
python -m http.server 8000