Compare commits

...

2 Commits

Author SHA1 Message Date
Peter Stockings
ff462fb53c Add minimap 2026-01-04 09:53:07 +11:00
Peter Stockings
ad487e766c Use full screen 2026-01-04 09:44:05 +11:00
5 changed files with 172 additions and 14 deletions

View File

@@ -1,13 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/src/style.css" />
<title>rogue</title>
</head>
<body>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</body>
</html>

View File

@@ -6,8 +6,11 @@ import { StartScene } from "./scenes/StartScene";
new Phaser.Game({
type: Phaser.AUTO,
parent: "app",
width: 960,
height: 540,
scale: {
mode: Phaser.Scale.RESIZE,
width: window.innerWidth,
height: window.innerHeight,
},
backgroundColor: "#111",
pixelArt: true,
roundPixels: true,

View File

@@ -17,9 +17,31 @@ export class DungeonRenderer {
// State refs
private world!: World;
// Minimap
private minimapGfx!: Phaser.GameObjects.Graphics;
private minimapContainer!: Phaser.GameObjects.Container;
private minimapBg!: Phaser.GameObjects.Graphics;
private minimapScale = 2; // pixels per tile
private minimapPadding = 8;
constructor(scene: Phaser.Scene) {
this.scene = scene;
this.gfx = this.scene.add.graphics();
// Initialize minimap
this.initMinimap();
}
private initMinimap() {
this.minimapContainer = this.scene.add.container(0, 0);
this.minimapContainer.setScrollFactor(0); // Fixed to camera
this.minimapContainer.setDepth(100);
this.minimapBg = this.scene.add.graphics();
this.minimapGfx = this.scene.add.graphics();
this.minimapContainer.add(this.minimapBg);
this.minimapContainer.add(this.minimapGfx);
}
initializeLevel(world: World) {
@@ -32,6 +54,21 @@ export class DungeonRenderer {
if (!inBounds(this.world, x, y)) return false;
return !isWall(this.world, x, y);
});
// Position minimap
this.positionMinimap();
}
private positionMinimap() {
const cam = this.scene.cameras.main;
const minimapWidth = this.world.width * this.minimapScale + this.minimapPadding * 2;
const minimapHeight = this.world.height * this.minimapScale + this.minimapPadding * 2;
// Position in bottom right corner (accounting for zoom)
const x = cam.width / cam.zoom - minimapWidth - 10;
const y = cam.height / cam.zoom - minimapHeight - 10;
this.minimapContainer.setPosition(x, y);
}
computeFov(playerId: EntityId) {
@@ -135,6 +172,90 @@ export class DungeonRenderer {
this.gfx.fillStyle(color, 1);
this.gfx.fillRect(a.pos.x * TILE_SIZE + 4, a.pos.y * TILE_SIZE + 4, TILE_SIZE - 8, TILE_SIZE - 8);
}
// Render minimap
this.renderMinimap();
}
private renderMinimap() {
this.minimapBg.clear();
this.minimapGfx.clear();
if (!this.world) return;
const minimapWidth = this.world.width * this.minimapScale + this.minimapPadding * 2;
const minimapHeight = this.world.height * this.minimapScale + this.minimapPadding * 2;
// Background
this.minimapBg.fillStyle(0x000000, 0.7);
this.minimapBg.fillRect(0, 0, minimapWidth, minimapHeight);
// Border
this.minimapBg.lineStyle(1, 0x666666, 1);
this.minimapBg.strokeRect(0, 0, minimapWidth, minimapHeight);
// Draw only seen tiles
for (let y = 0; y < this.world.height; y++) {
for (let x = 0; x < this.world.width; x++) {
const i = idx(this.world, x, y);
const isSeen = this.seen[i] === 1;
if (!isSeen) continue;
const wall = isWall(this.world, x, y);
const color = wall ? 0x666666 : 0x333333;
this.minimapGfx.fillStyle(color, 1);
this.minimapGfx.fillRect(
this.minimapPadding + x * this.minimapScale,
this.minimapPadding + y * this.minimapScale,
this.minimapScale,
this.minimapScale
);
}
}
// Draw exit if seen
const ex = this.world.exit.x;
const ey = this.world.exit.y;
const exitIdx = idx(this.world, ex, ey);
if (this.seen[exitIdx] === 1) {
this.minimapGfx.fillStyle(0xffd166, 1);
this.minimapGfx.fillRect(
this.minimapPadding + ex * this.minimapScale,
this.minimapPadding + ey * this.minimapScale,
this.minimapScale,
this.minimapScale
);
}
// Draw player
const player = [...this.world.actors.values()].find(a => a.isPlayer);
if (player) {
this.minimapGfx.fillStyle(0x66ff66, 1);
this.minimapGfx.fillRect(
this.minimapPadding + player.pos.x * this.minimapScale,
this.minimapPadding + player.pos.y * this.minimapScale,
this.minimapScale,
this.minimapScale
);
}
// Draw visible enemies
for (const a of this.world.actors.values()) {
if (a.isPlayer) continue;
const i = idx(this.world, a.pos.x, a.pos.y);
const isVis = this.visible[i] === 1;
if (!isVis) continue;
this.minimapGfx.fillStyle(0xff6666, 1);
this.minimapGfx.fillRect(
this.minimapPadding + a.pos.x * this.minimapScale,
this.minimapPadding + a.pos.y * this.minimapScale,
this.minimapScale,
this.minimapScale
);
}
}
showDamage(x: number, y: number, amount: number) {

View File

@@ -16,7 +16,13 @@ export class SplashScene extends Scene {
// Background (Placeholder for Image)
// If we successfully load the image 'splash', we use it.
if (this.textures.exists('splash')) {
this.add.image(width / 2, height / 2, 'splash').setDisplaySize(width, height);
const splash = this.add.image(width / 2, height / 2, 'splash');
// Scale to cover the screen while maintaining aspect ratio
const scaleX = width / splash.width;
const scaleY = height / splash.height;
const scale = Math.max(scaleX, scaleY);
splash.setScale(scale);
} else {
this.add.rectangle(0, 0, width, height, 0x110022).setOrigin(0);
this.add.text(width/2, height/2, "ROGUE LEGACY", {

24
src/style.css Normal file
View File

@@ -0,0 +1,24 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
width: 100%;
height: 100%;
overflow: hidden;
}
#app {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
background: #111;
}
canvas {
display: block;
}