|
| 1 | +/** |
| 2 | + * Ship Game - A 2D Phaser game |
| 3 | + * |
| 4 | + * Entry point for the ship game accessible at /ship |
| 5 | + */ |
| 6 | + |
| 7 | +import Phaser from 'phaser'; |
| 8 | + |
| 9 | +/** |
| 10 | + * Main game scene for the ship game |
| 11 | + */ |
| 12 | +class ShipScene extends Phaser.Scene { |
| 13 | + private ship: Phaser.GameObjects.Sprite | null = null; |
| 14 | + private cursors: Phaser.Types.Input.Keyboard.CursorKeys | null = null; |
| 15 | + private wasdKeys: Record<string, Phaser.Input.Keyboard.Key> | null = null; |
| 16 | + private readonly shipSpeed = 200; |
| 17 | + |
| 18 | + constructor() { |
| 19 | + super({ key: 'ShipScene' }); |
| 20 | + } |
| 21 | + |
| 22 | + create(): void { |
| 23 | + // Set background color |
| 24 | + this.cameras.main.setBackgroundColor('#1a1a2e'); |
| 25 | + |
| 26 | + // Create a simple ship sprite (using a rectangle for now) |
| 27 | + // In a real game, you'd load an image asset |
| 28 | + const graphics = this.add.graphics(); |
| 29 | + graphics.fillStyle(0x00ff00); |
| 30 | + graphics.fillTriangle(0, -20, -15, 15, 15, 15); |
| 31 | + graphics.generateTexture('ship', 30, 30); |
| 32 | + graphics.destroy(); |
| 33 | + |
| 34 | + // Create ship sprite at center |
| 35 | + this.ship = this.add.sprite(400, 300, 'ship'); |
| 36 | + this.ship.setOrigin(0.5, 0.5); |
| 37 | + |
| 38 | + // Set up keyboard input |
| 39 | + this.cursors = this.input.keyboard?.createCursorKeys() || null; |
| 40 | + |
| 41 | + // Add WASD keys as alternative |
| 42 | + if (this.input.keyboard) { |
| 43 | + this.wasdKeys = this.input.keyboard.addKeys('W,S,A,D') as Record<string, Phaser.Input.Keyboard.Key>; |
| 44 | + } |
| 45 | + |
| 46 | + // Add instructions text |
| 47 | + const instructions = this.add.text(10, 10, 'Ship Game\nArrow Keys or WASD to move', { |
| 48 | + fontSize: '16px', |
| 49 | + color: '#ffffff', |
| 50 | + backgroundColor: '#000000', |
| 51 | + padding: { x: 10, y: 5 } |
| 52 | + }); |
| 53 | + instructions.setScrollFactor(0); |
| 54 | + } |
| 55 | + |
| 56 | + update(): void { |
| 57 | + if (!this.ship || !this.cursors) { |
| 58 | + return; |
| 59 | + } |
| 60 | + |
| 61 | + const delta = this.game.loop.delta; |
| 62 | + |
| 63 | + // Calculate movement |
| 64 | + let velocityX = 0; |
| 65 | + let velocityY = 0; |
| 66 | + |
| 67 | + // Check arrow keys or WASD |
| 68 | + const left = this.cursors.left?.isDown || this.wasdKeys?.A?.isDown || false; |
| 69 | + const right = this.cursors.right?.isDown || this.wasdKeys?.D?.isDown || false; |
| 70 | + const up = this.cursors.up?.isDown || this.wasdKeys?.W?.isDown || false; |
| 71 | + const down = this.cursors.down?.isDown || this.wasdKeys?.S?.isDown || false; |
| 72 | + |
| 73 | + if (left) { |
| 74 | + velocityX = -this.shipSpeed; |
| 75 | + } else if (right) { |
| 76 | + velocityX = this.shipSpeed; |
| 77 | + } |
| 78 | + |
| 79 | + if (up) { |
| 80 | + velocityY = -this.shipSpeed; |
| 81 | + } else if (down) { |
| 82 | + velocityY = this.shipSpeed; |
| 83 | + } |
| 84 | + |
| 85 | + // Normalize diagonal movement |
| 86 | + if (velocityX !== 0 && velocityY !== 0) { |
| 87 | + const length = Math.sqrt(velocityX * velocityX + velocityY * velocityY); |
| 88 | + velocityX = (velocityX / length) * this.shipSpeed; |
| 89 | + velocityY = (velocityY / length) * this.shipSpeed; |
| 90 | + } |
| 91 | + |
| 92 | + // Update ship position |
| 93 | + const deltaSeconds = delta / 1000; |
| 94 | + this.ship.x += velocityX * deltaSeconds; |
| 95 | + this.ship.y += velocityY * deltaSeconds; |
| 96 | + |
| 97 | + // Rotate ship to face movement direction |
| 98 | + if (velocityX !== 0 || velocityY !== 0) { |
| 99 | + const angle = Math.atan2(velocityY, velocityX) * (180 / Math.PI) + 90; |
| 100 | + this.ship.rotation = Phaser.Math.DegToRad(angle); |
| 101 | + } |
| 102 | + |
| 103 | + // Keep ship within bounds |
| 104 | + const width = this.cameras.main.width; |
| 105 | + const height = this.cameras.main.height; |
| 106 | + this.ship.x = Phaser.Math.Clamp(this.ship.x, 0, width); |
| 107 | + this.ship.y = Phaser.Math.Clamp(this.ship.y, 0, height); |
| 108 | + } |
| 109 | +} |
| 110 | + |
| 111 | +/** |
| 112 | + * Phaser game configuration |
| 113 | + */ |
| 114 | +const config: Phaser.Types.Core.GameConfig = { |
| 115 | + type: Phaser.AUTO, |
| 116 | + width: 800, |
| 117 | + height: 600, |
| 118 | + parent: 'ship-game-container', |
| 119 | + backgroundColor: '#1a1a2e', |
| 120 | + scene: ShipScene, |
| 121 | + physics: { |
| 122 | + default: 'arcade', |
| 123 | + arcade: { |
| 124 | + gravity: { x: 0, y: 0 }, |
| 125 | + debug: false |
| 126 | + } |
| 127 | + } |
| 128 | +}; |
| 129 | + |
| 130 | +// Initialize the game |
| 131 | +new Phaser.Game(config); |
| 132 | + |
| 133 | + |
0 commit comments