|
1 | 1 | <script lang="ts"> |
2 | | - import { onDestroy, onMount } from 'svelte'; |
| 2 | + import { onMount } from 'svelte'; |
3 | 3 | import { Application, Container, Graphics, Point, Assets, FederatedPointerEvent } from 'pixi.js'; |
4 | 4 | import { gameState, bindToWorld, sendAction } from '$lib/stores/game.svelte.ts'; |
5 | 5 | import { |
|
40 | 40 | let container: HTMLDivElement | undefined; |
41 | 41 | let parentElement: HTMLElement | null = null; |
42 | 42 |
|
| 43 | + const currentPlayer: Player | undefined = $derived( |
| 44 | + gameState.world?.players.find((player: Player) => player.name === gameState.playerName) |
| 45 | + ); |
| 46 | +
|
43 | 47 | const hexSize = 200; |
44 | 48 | const tileHeight = 348; |
45 | 49 | const tileWidth = 400; |
46 | 50 | const lineWidth = 14; |
47 | 51 | const tilePath = '/img/tilesets/'; |
48 | 52 | const tileStyle = 'realistic'; |
49 | 53 | const assetsToLoad = [ |
50 | | - // Tiles |
51 | 54 | `${tilePath}${tileStyle}/clay.png`, |
52 | 55 | `${tilePath}${tileStyle}/desert.png`, |
53 | 56 | `${tilePath}${tileStyle}/grain.png`, |
54 | 57 | `${tilePath}${tileStyle}/wood.png`, |
55 | 58 | `${tilePath}${tileStyle}/stone.png`, |
56 | 59 | `${tilePath}${tileStyle}/wool.png`, |
57 | 60 | `${tilePath}${tileStyle}/ocean.png`, |
58 | | - // Pieces |
59 | 61 | '/img/pieces/house.png', |
60 | 62 | '/img/pieces/city.png', |
61 | 63 | '/img/pieces/thief.png', |
62 | | - // Special |
63 | 64 | `${tilePath}shared/scorch-with-thief.png`, |
64 | | - // Harbors |
65 | 65 | `${tilePath}${tileStyle}/woodharbor.png`, |
66 | 66 | `${tilePath}${tileStyle}/woolharbor.png`, |
67 | 67 | `${tilePath}${tileStyle}/grainharbor.png`, |
68 | 68 | `${tilePath}${tileStyle}/clayharbor.png`, |
69 | 69 | `${tilePath}${tileStyle}/stoneharbor.png`, |
70 | 70 | `${tilePath}${tileStyle}/threetooneharbor.png`, |
71 | | - // Numbers |
72 | 71 | '/img/numbers/2.png', |
73 | 72 | '/img/numbers/3.png', |
74 | 73 | '/img/numbers/4.png', |
|
120 | 119 | let latestWorld: World | undefined; |
121 | 120 | let loadingPromise: Promise<void> | undefined; |
122 | 121 |
|
123 | | - const currentPlayer: Player | undefined = $derived( |
124 | | - gameState.world?.players.find((player: Player) => player.name === gameState.playerName) |
125 | | - ); |
126 | | -
|
127 | 122 | $effect(() => { |
128 | 123 | updateMap(gameState.world); |
129 | 124 | }); |
|
135 | 130 | isPlayingRoadBuilding = uiState.isPlayingRoadBuilding; |
136 | 131 | }); |
137 | 132 |
|
138 | | - // Convert screen coordinates to world coordinates |
139 | 133 | const toWorld = (screenPoint: { x: number; y: number }): { x: number; y: number } => { |
140 | 134 | return { |
141 | 135 | x: (screenPoint.x - panX) / scale, |
142 | 136 | y: (screenPoint.y - panY) / scale |
143 | 137 | }; |
144 | 138 | }; |
145 | 139 |
|
146 | | - // Update world container transform |
147 | 140 | const updateWorldTransform = () => { |
148 | 141 | if (!worldContainer) return; |
149 | 142 | worldContainer.scale.set(scale); |
|
155 | 148 | return; |
156 | 149 | } |
157 | 150 |
|
| 151 | + const prevCenterWorld = toWorld({ x: width / 2, y: height / 2 }); |
| 152 | +
|
158 | 153 | const target = parentElement ?? container; |
159 | | - const ratio = window.devicePixelRatio || 1; |
160 | | - height = target.clientHeight / ratio; |
161 | | - width = target.clientWidth / ratio; |
162 | | - container.style.width = `${target.clientWidth}px`; |
163 | | - container.style.height = `${target.clientHeight}px`; |
| 154 | + width = target.clientWidth; |
| 155 | + height = target.clientHeight; |
| 156 | + container.style.width = `${width}px`; |
| 157 | + container.style.height = `${height}px`; |
| 158 | +
|
164 | 159 | app.renderer.resize(width, height); |
| 160 | + app.stage.hitArea = app.screen; |
| 161 | + worldContainer.hitArea = app.screen; |
| 162 | +
|
| 163 | + panX = width / 2 - prevCenterWorld.x * scale; |
| 164 | + panY = height / 2 - prevCenterWorld.y * scale; |
| 165 | + updateWorldTransform(); |
165 | 166 | }; |
166 | 167 |
|
167 | 168 | const dispatchActionClearCursor = async (action: GameAction) => { |
|
233 | 234 | }; |
234 | 235 |
|
235 | 236 | const handleClick = (event: FederatedPointerEvent) => { |
236 | | - if (isBuilding !== 'None') { |
| 237 | + if (isBuilding !== 'None' || isPlayingRoadBuilding) { |
237 | 238 | handleBuildClick(event); |
238 | 239 | } else if (isMovingThief) { |
239 | 240 | handleThiefClick(event); |
240 | 241 | } else if (isPlayingKnight) { |
241 | 242 | handleIsPlayingKnightClick(event); |
242 | | - } else if (isPlayingRoadBuilding) { |
243 | | - handleBuildClick(event); |
244 | 243 | } |
245 | 244 | }; |
246 | 245 |
|
|
255 | 254 | piece.width = dimensions.x; |
256 | 255 | piece.height = dimensions.y; |
257 | 256 | piece.tint = tint; |
258 | | - piece.position.x = coord.x; |
259 | | - piece.position.y = coord.y; |
| 257 | + piece.position.set(coord.x, coord.y); |
260 | 258 | piece.anchor.set(0.5); |
261 | 259 | return piece; |
262 | 260 | }; |
|
465 | 463 |
|
466 | 464 | parentElement = container.parentElement; |
467 | 465 | const target = parentElement ?? container; |
468 | | - const ratio = window.devicePixelRatio || 1; |
469 | | - height = target.clientHeight / ratio; |
470 | | - width = target.clientWidth / ratio; |
| 466 | + // Use raw client sizes (renderer resolution will scale for DPR) |
| 467 | + height = target.clientHeight; |
| 468 | + width = target.clientWidth; |
471 | 469 | container.style.width = `${target.clientWidth}px`; |
472 | 470 | container.style.height = `${target.clientHeight}px`; |
473 | 471 |
|
|
498 | 496 | stage.addChild(worldContainerInstance); |
499 | 497 | container?.appendChild(appInstance.canvas); |
500 | 498 |
|
501 | | - worldContainerInstance.addChild(tileGraphics); |
502 | | - worldContainerInstance.addChild(lineGraphics); |
503 | | - worldContainerInstance.addChild(pieceGraphics); |
504 | | - worldContainerInstance.addChild(cursorGraphics); |
| 499 | + worldContainerInstance.addChild(tileGraphics, lineGraphics, pieceGraphics, cursorGraphics); |
505 | 500 |
|
506 | 501 | // Set initial position (center the view) |
507 | 502 | panX = width / 2; |
|
562 | 557 | const delta = -event.deltaY; |
563 | 558 | const zoomIntensity = 0.0005; |
564 | 559 | const zoomFactor = Math.exp(delta * zoomIntensity); |
565 | | - const minScale = 0.1; |
566 | | - const maxScale = 5; |
| 560 | + const minScale = 0.08; |
| 561 | + const maxScale = 2; |
567 | 562 | const targetScale = scale * zoomFactor; |
568 | 563 | const newScale = Math.min(maxScale, Math.max(minScale, targetScale)); |
569 | 564 |
|
|
0 commit comments