Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiment/add fish sprite #85

Closed
wants to merge 15 commits into from
74 changes: 63 additions & 11 deletions components/GameScreen.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { Application, Graphics, Text, FillGradient } from "pixi.js";
import { Application, Graphics, Text, FillGradient, Assets, type Texture, Sprite } from "pixi.js";

const refreshIntervalMs = 1000;
const zoomSpeed = 0.05;
Expand All @@ -9,8 +9,22 @@
const { data: gameState, refresh } = await useFetch("/api/state");
const intervalRef = ref<number | null>(null);

const fishTexturesRef = ref<Texture[]>([]);

onMounted(async () => {
intervalRef.value = window.setInterval(refresh, refreshIntervalMs);

fishTexturesRef.value = await Promise.all([
Assets.load("/sprites/FishVer1Short.png"),
Assets.load("/sprites/FishVer2Short.png"),
Assets.load("/sprites/FishVer3Short.png"),
Assets.load("/sprites/FishVer4Short.png"),
Assets.load("/sprites/FishVer5Short.png"),
Assets.load("/sprites/FishVer6Short.png"),
Assets.load("/sprites/FishVer7Short.png"),
Assets.load("/sprites/FishVer8Short.png"),
Assets.load("/sprites/FishVer9Short.png"),
]);
});

onBeforeUnmount(() => {
Expand All @@ -23,8 +37,6 @@
const appRef = ref<Application | null>(null);
const foodRef = ref<{ x: number; y: number; graphics: Graphics }[]>([]);
const botSpawnsRef = ref<Record<string, Graphics>>({});
const gameScreen = ref<HTMLDivElement | null>(null);

const tickFnRef = ref<() => void>();

type DrawBotArgs = {
Expand All @@ -35,16 +47,40 @@
color: string;
username: string;
};
/**
* Bot direction in radians.
*/
botDirection: number;
graphics: Graphics;
};

async function drawBot({ bot, graphics }: DrawBotArgs) {
async function drawBot({ bot, graphics, botDirection }: DrawBotArgs) {
for (const child of graphics.children) {
graphics.removeChild(child);
}
graphics.clear();

// draw bot
graphics.circle(bot.x, bot.y, bot.radius);
graphics.fill(bot.color);
const usernameHash = bot.username.charCodeAt(0) + (bot.username.charCodeAt(1) || 0) + (bot.username.charCodeAt(2) || 0);
const numOfSprite = usernameHash % (fishTexturesRef.value.length);
const fishTexture = fishTexturesRef.value[numOfSprite];

if (!fishTexture) {
throw new Error("Fish sprite is not loaded");
}
const sprite = new Sprite(fishTexture);
sprite.anchor.set(0.5);
sprite.width = bot.radius * 2;
sprite.height = bot.radius * 2;
sprite.x = bot.x;
sprite.y = bot.y;

const shouldFlipBot = botDirection > Math.PI / 2 || botDirection < -Math.PI / 2;
if (shouldFlipBot) {
sprite.scale.x = -Math.abs(sprite.scale.x);
}

graphics.addChild(sprite);
const existingUsername = graphics.children.find(child => child instanceof Text);
if (existingUsername) {
// avoid recreating username if it already exists
Expand Down Expand Up @@ -80,6 +116,13 @@
}
}

function getDirection(
positionA: { x: number; y: number },
positionB: { x: number; y: number },
): number {
return Math.atan2(positionB.y - positionA.y, positionB.x - positionA.x);
}

watch(gameState, async (newState, prevState) => {
if (!canvas.value) {
window.alert("Can't render the game. Please, refresh the page. If the problem persists, report the issue at https://github.com/move-fast-and-break-things/aibyss/issues. Include as many details as possible.");
Expand Down Expand Up @@ -192,9 +235,9 @@
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'.
}
}
});
Expand All @@ -205,7 +248,7 @@

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 };
Expand All @@ -227,12 +270,12 @@
});

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;
});

Expand All @@ -247,9 +290,15 @@

// render bots
for (const bot of Object.values(prevState.bots)) {
const newBotState = newState.bots[bot.spawnId];
if (!newBotState) {
continue;
}

const graphics = new Graphics();
app.stage.addChild(graphics);
drawBot({ bot, graphics });
const botDirection = getDirection(bot, newBotState);
drawBot({ bot, graphics, botDirection });
botSpawnsRef.value[bot.spawnId] = graphics;
}
} else {
Expand Down Expand Up @@ -284,18 +333,20 @@

// move or add bots
for (const bot of Object.values(prevState.bots)) {
if (!newState.bots[bot.spawnId]) {
const newBotState = newState.bots[bot.spawnId];
if (!newBotState) {
continue;
}

const existingBot = botSpawnsRef.value[bot.spawnId];
const botDirection = getDirection(bot, newBotState);

if (existingBot) {
drawBot({ bot, graphics: existingBot });
drawBot({ bot, graphics: existingBot, botDirection });
} else {
const graphics = new Graphics();
appRef.value.stage.addChild(graphics);
drawBot({ bot, graphics });
drawBot({ bot, graphics, botDirection });
botSpawnsRef.value[bot.spawnId] = graphics;
}
}
Expand Down Expand Up @@ -327,8 +378,9 @@
if (existingBot && prevBot) {
const x = prevBot.x + (bot.x - prevBot.x) * progress;
const y = prevBot.y + (bot.y - prevBot.y) * progress;
const botDirection = getDirection(prevBot, bot);

drawBot({ bot: { ...bot, x, y }, graphics: existingBot });
drawBot({ bot: { ...bot, x, y }, graphics: existingBot, botDirection });
}
}
};
Expand Down
Binary file added public/sprites/FishVer1Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer2Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer3Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer4Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer5Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer6Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer7Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer8Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/FishVer9Short.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/sprites/fish.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading