about summary refs log tree commit diff stats
path: root/html/rogue/js/game.js
blob: f26e59b861c44e637e3b57f414a281130deb7af0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
const FPS = 60;
const FRAME_TIME = 1000 / FPS;
let lastFrameTime = 0;

const state = {
    canvas: null,
    ctx: null
};

function init() {
    state.canvas = document.getElementById('gameCanvas');
    state.ctx = state.canvas.getContext('2d');
    
    player.init();
    
    function resize() {
        state.canvas.width = window.innerWidth;
        state.canvas.height = window.innerHeight;
        Camera.centerOn(player.position);
    }
    
    window.addEventListener('resize', resize);
    resize();
    state.canvas.addEventListener('click', handleClick);
    
    requestAnimationFrame(gameLoop);
    FogOfWar.init();
    Items.init();
}

function drawHex(ctx, x, y, hex) {
    const screen = HexGrid.toScreenCoordinates(hex, Camera);
    
    // Only draw if hex is visible on screen (with padding)
    if (!HexGrid.isInViewport(screen.x, screen.y, state.canvas)) {
        return;
    }
    
    // Skip drawing completely if hex hasn't been revealed
    if (!FogOfWar.isRevealed(hex)) {
        return;
    }
    
    // Draw the hex fill
    HexGrid.drawHexPath(ctx, screen.x, screen.y);
    ctx.fillStyle = Config.colors.HEX_FILL;
    ctx.fill();
    
    // Only draw grid lines for currently visible hexes
    // (fog of war will handle the grid lines for revealed but not visible hexes)
    if (FogOfWar.isVisible(hex)) {
        ctx.strokeStyle = Config.colors.GRID;
        ctx.lineWidth = 1;
        ctx.stroke();
    }
}

function gameLoop(currentTime) {
    requestAnimationFrame(gameLoop);  // Request next frame first
    
    if (currentTime - lastFrameTime < Config.game.FRAME_TIME) {
        return;  // Skip frame if too soon
    }
    
    // Ensure consistent time step
    const deltaTime = Math.min(currentTime - lastFrameTime, Config.game.FRAME_TIME * 2);
    lastFrameTime = currentTime;

    // Clear with background
    state.ctx.fillStyle = Config.colors.BACKGROUND;
    state.ctx.fillRect(0, 0, state.canvas.width, state.canvas.height);
    
    // Round camera position to prevent sub-pixel rendering
    Camera.x = Math.round(Camera.x);
    Camera.y = Math.round(Camera.y);
    
    player.update();
    Camera.smoothFollow(player.getCurrentPosition());
    
    if (player.hasMoved) {
        FogOfWar.updateVisibility(player.position);
        player.hasMoved = false;
    }
    
    // Draw everything in one pass to prevent flicker
    HexGrid.getViewportHexes().forEach(hex => {
        const pixel = HexGrid.toPixel(hex);
        drawHex(state.ctx, Math.round(pixel.x), Math.round(pixel.y), hex);
    });
    
    Items.draw(state.ctx, HexGrid.toPixel.bind(HexGrid), Camera, HexGrid.SIZE);
    player.draw(state.ctx, HexGrid.toPixel.bind(HexGrid), Camera, HexGrid.SIZE);
    FogOfWar.draw(state.ctx);
    InventoryUI.draw(state.ctx);
}

function handleClick(event) {
    if (InventoryUI.isOpen) {
        InventoryUI.toggleInventory();
        return;
    }
    
    const rect = state.canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;
    
    const hexCoord = HexGrid.fromPixel(x + Camera.x, y + Camera.y);
    
    // Check if clicking on player's position
    if (hexCoord.q === player.position.q && hexCoord.r === player.position.r) {
        InventoryUI.toggleInventory();
    } else {
        player.moveTo(hexCoord);
    }
}

init();