Skip to content

Commit

Permalink
Merge branch 'main' into experiment/add-fish-sprite
Browse files Browse the repository at this point in the history
  • Loading branch information
Bee133 authored Nov 27, 2024
2 parents 920a9a2 + 01455cd commit 805742b
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 4 deletions.
130 changes: 130 additions & 0 deletions components/GameScreen.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import { Application, Graphics, Text, FillGradient, Assets, type Texture, Sprite } from "pixi.js";
const refreshIntervalMs = 1000;
const zoomSpeed = 0.05;
const minZoom = 1;
const maxZoom = 3;
const { data: gameState, refresh } = await useFetch("/api/state");
const intervalRef = ref<number | null>(null);
Expand Down Expand Up @@ -150,6 +153,132 @@ watch(gameState, async (newState, prevState) => {
autoDensity: true,
});
let isZoomingOut = false;
const zoomDuration = 500; // Duration of the zoom-out effect in milliseconds
let startZoomTime: number | null = null;
let startMousePos = { x: 0, y: 0 };
// Functions to handle smooth zoom out
function smoothZoomOut(mousePos: { x: number; y: number }) {
if (!appRef.value) {
return;
}
isZoomingOut = true;
startZoomTime = performance.now();
startMousePos = mousePos;
requestAnimationFrame(animateZoomOut);
}
function animateZoomOut(currentTime: number) {
if (!appRef.value || !startZoomTime) {
return;
};
const elapsedTime = currentTime - startZoomTime;
const progress = Math.min(elapsedTime / zoomDuration, 1);
const newScale = minZoom + (appRef.value.stage.scale.x - minZoom) * (1 - progress);
const worldPos = {
x: (startMousePos.x - appRef.value.stage.position.x) / appRef.value.stage.scale.x,
y: (startMousePos.y - appRef.value.stage.position.y) / appRef.value.stage.scale.y,
};
appRef.value.stage.scale.set(newScale);
const newScreenPos = {
x: worldPos.x * newScale + appRef.value.stage.position.x,
y: worldPos.y * newScale + appRef.value.stage.position.y,
};
appRef.value.stage.position.set(
Math.min(0, Math.max(appRef.value.stage.position.x - (newScreenPos.x - startMousePos.x), appRef.value.screen.width - appRef.value.screen.width * newScale)),
Math.min(0, Math.max(appRef.value.stage.position.y - (newScreenPos.y - startMousePos.y), appRef.value.screen.height - appRef.value.screen.height * newScale)),
);
if (progress < 1) {
requestAnimationFrame(animateZoomOut);
} else {
isZoomingOut = false;
}
}
// Mouse wheel event listener
// Event listeners can be potentially called multiple times.
// TODO: add .removeEventListener later for refactoring.
canvas.value?.addEventListener("wheel", (event) => {
event.preventDefault();
const mousePos = { x: event.offsetX, y: event.offsetY };
if (event.deltaY > 0) {
// Zoom out when scrolling down
if (!isZoomingOut) {
smoothZoomOut(mousePos);
}
} else {
// Existing zoom-in functionality
const zoomFactor = event.deltaY * -zoomSpeed;
const newScale = Math.max(minZoom, Math.min(maxZoom, app.stage.scale.x + zoomFactor));
const worldPos = {
x: (mousePos.x - app.stage.position.x) / app.stage.scale.x,
y: (mousePos.y - app.stage.position.y) / app.stage.scale.y,
};
app.stage.scale.set(newScale);
const newScreenPos = {
x: worldPos.x * newScale + app.stage.position.x,
y: worldPos.y * newScale + app.stage.position.y,
};
app.stage.position.set(
Math.min(0, Math.max(app.stage.position.x - (newScreenPos.x - mousePos.x), app.screen.width - app.screen.width * newScale)),
Math.min(0, Math.max(app.stage.position.y - (newScreenPos.y - mousePos.y), app.screen.height - app.screen.height * newScale)),
);
if (newScale > 1) {
gameScreen.value?.classList.add("cursor-grab");

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 238 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.
} else {
gameScreen.value?.classList.remove("cursor-grab");

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 240 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.
}
}
});
// Panning functionality
let isDragging = false;
let startDragPos = { x: 0, y: 0 };
canvas.value?.addEventListener("mousedown", (event) => {
if (app.stage.scale.x > 1) {
gameScreen.value?.classList.add("cursor-grabbing");

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 251 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.
}
isDragging = true;
startDragPos = { x: event.offsetX, y: event.offsetY };
});
canvas.value?.addEventListener("mousemove", (event) => {
if (isDragging && canvas.value) {
const dx = event.offsetX - startDragPos.x;
const dy = event.offsetY - startDragPos.y;
const newPosX = app.stage.position.x + dx;
const newPosY = app.stage.position.y + dy;
// Constrain the new position to within map boundaries
app.stage.position.x = Math.min(0, Math.max(newPosX, app.screen.width - app.screen.width * app.stage.scale.x));
app.stage.position.y = Math.min(0, Math.max(newPosY, app.screen.height - app.screen.height * app.stage.scale.y));
startDragPos = { x: event.offsetX, y: event.offsetY };
}
});
canvas.value?.addEventListener("mouseup", () => {
gameScreen.value?.classList.remove("cursor-grabbing");

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 273 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.
isDragging = false;
});
canvas.value?.addEventListener("mouseleave", () => {
gameScreen.value?.classList.remove("cursor-grabbing");

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / lint

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.

Check failure on line 278 in components/GameScreen.vue

View workflow job for this annotation

GitHub Actions / test

Cannot find name 'gameScreen'.
isDragging = false;
});
// render food
for (const food of prevState.food) {
const graphics = new Graphics();
Expand Down Expand Up @@ -265,6 +394,7 @@ watch(gameState, async (newState, prevState) => {
data-testid="game-screen"
>
<div
ref="gameScreen"
class="flex flex-col shadow ml-2"
:style="{ maxWidth: gameState?.width + 'px' }"
>
Expand Down
17 changes: 13 additions & 4 deletions components/RatingTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,23 @@ const isModalOpen = ref(false);
scope="col"
class="px-6 py-3 bg-gray-50 dark:bg-gray-800"
>
food eaten
k/d
</th>
<th
scope="col"
class="px-6 py-3"
>
max endgame size
food eaten
</th>
<th
scope="col"
class="px-6 py-3 bg-gray-50 dark:bg-gray-800"
>
max endgame size
</th>
<th
scope="col"
class="px-6 py-3"
>
avg endgame size
</th>
Expand Down Expand Up @@ -137,12 +143,15 @@ const isModalOpen = ref(false);
{{ userRating.deaths }}
</td>
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
{{ userRating.foodEaten }}
{{ userRating.deaths ? (userRating.kills / userRating.deaths).toFixed(2) : "n/a" }}
</td>
<td class="px-6 py-4">
{{ userRating.maxEndgameSize }}
{{ userRating.foodEaten }}
</td>
<td class="px-6 py-4 bg-gray-50 dark:bg-gray-800">
{{ userRating.maxEndgameSize }}
</td>
<td class="px-6 py-4">
{{ userRating.avgEndgameSize.toFixed(2) }}
</td>
</tr>
Expand Down

0 comments on commit 805742b

Please sign in to comment.