From 3e2b49cb21b66bc84ccc4acb5b39c9415c62c943 Mon Sep 17 00:00:00 2001 From: Mael Kerichard <38262536+Pixselve@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:41:49 +0100 Subject: [PATCH] feat: scoring --- packages/client/src/app/canvas.tsx | 4 +-- packages/server/src/handleFrame.ts | 50 +++++++++++++++++++++++++++--- packages/server/src/index.ts | 1 + packages/shared/src/constants.ts | 21 +++++++++++++ packages/shared/src/types.ts | 1 + 5 files changed, 70 insertions(+), 7 deletions(-) diff --git a/packages/client/src/app/canvas.tsx b/packages/client/src/app/canvas.tsx index d81fd88..5e5e7ca 100644 --- a/packages/client/src/app/canvas.tsx +++ b/packages/client/src/app/canvas.tsx @@ -110,7 +110,7 @@ export function Canvas({ centered }: { centered?: boolean }) { api.scene.food.forEach((food) => { const screenFood = worldToScreen(food.position, camera); c.beginPath(); - c.arc(screenFood.x, screenFood.y, 10, 0, 2 * Math.PI); // Draw a circle for each food + c.arc(screenFood.x, screenFood.y, 7, 0, 2 * Math.PI); // Draw a circle for each food // use green color c.fillStyle = "green"; c.fill(); @@ -120,7 +120,7 @@ export function Canvas({ centered }: { centered?: boolean }) { api.scene.orbs.forEach((orb) => { const screenOrb = worldToScreen(orb.position, camera); c.beginPath(); - c.arc(screenOrb.x, screenOrb.y, 5 * orb.size, 0, 2 * Math.PI); // Draw a circle for each orb + c.arc(screenOrb.x, screenOrb.y, 3 * orb.size, 0, 2 * Math.PI); // Draw a circle for each orb // use blue color c.fillStyle = "blue"; c.fill(); diff --git a/packages/server/src/handleFrame.ts b/packages/server/src/handleFrame.ts index 28e2f97..9692769 100644 --- a/packages/server/src/handleFrame.ts +++ b/packages/server/src/handleFrame.ts @@ -7,6 +7,10 @@ import { SPRINT_SPEED, MAX_ANGLE, ORB_SPRINTING_DROP_RATE, + SCORE_PER_ORB, + MIN_SCORE_TO_SPRINT, + SCORE_PER_FOOD, + SCORE_PER_BODY_PART, } from "@viper-vortex/shared"; function movePlayer(player: Player, gameMap: GameMap) { @@ -14,6 +18,12 @@ function movePlayer(player: Player, gameMap: GameMap) { // start with the head const head = getPlayerHead(player); + + // can the player sprint? + if (player.score < MIN_SCORE_TO_SPRINT) { + player.isSprinting = false; + } + const speed = player.isSprinting ? SPRINT_SPEED : BASE_SPEED; if (player.isSprinting) { @@ -27,6 +37,7 @@ function movePlayer(player: Player, gameMap: GameMap) { position: { x: lastBodyPart.x, y: lastBodyPart.y }, size: 1, }); + player.score -= SCORE_PER_ORB; } } @@ -83,11 +94,8 @@ export default function handleFrame( // collision // remove the food gameMap.food.splice(i, 1); - // add a new body part - player.body.push({ - x: player.body[player.body.length - 1].x, - y: player.body[player.body.length - 1].y, - }); + // add score + player.score += SCORE_PER_FOOD; } } @@ -111,5 +119,37 @@ export default function handleFrame( } } } + + // Check for collisions with orbs + for (let i = 0; i < gameMap.orbs.length; i++) { + const orb = gameMap.orbs[i]; + if ( + Math.abs(orb.position.x - head.x) < FOOD_PICKUP_RADIUS && + Math.abs(orb.position.y - head.y) < FOOD_PICKUP_RADIUS + ) { + // collision + // remove the orb + gameMap.orbs.splice(i, 1); + // add score + player.score += SCORE_PER_ORB; + } + } + + // Update the player's body based on the score + // Minimum length of 1 (the head) + const bodyLength = Math.max( + 1, + Math.floor(player.score / SCORE_PER_BODY_PART), + ); + + while (player.body.length < bodyLength) { + player.body.push({ + x: player.body[player.body.length - 1].x, + y: player.body[player.body.length - 1].y, + }); + } + while (player.body.length > bodyLength) { + player.body.pop(); + } } } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index cb79d97..d993260 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -37,6 +37,7 @@ io.on(SOCKET_EVENTS.CONNECT, (socket) => { angle: 0, desiredAngle: 0, orbToDrop: 0, + score: 0, }; gameMap.players.push(player); diff --git a/packages/shared/src/constants.ts b/packages/shared/src/constants.ts index 0680b02..2df11dc 100644 --- a/packages/shared/src/constants.ts +++ b/packages/shared/src/constants.ts @@ -27,6 +27,27 @@ export const MAX_ANGLE = Math.PI / 20; */ export const ORB_SPRINTING_DROP_RATE = 0.1; +/** + * The amount of score gained/lost per orb. + * You lose orbs when sprinting. + */ +export const SCORE_PER_ORB = 5; + +/** + * The amount of score required for each body part. + */ +export const SCORE_PER_BODY_PART = 10; + +/** + * The amount of score gained per food. + */ +export const SCORE_PER_FOOD = SCORE_PER_BODY_PART; + +/** + * The minimum score required to sprint. + */ +export const MIN_SCORE_TO_SPRINT = SCORE_PER_BODY_PART * 4; + /** * Enum for socket events. * @enum {string} diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts index 8f823fa..1205ec6 100644 --- a/packages/shared/src/types.ts +++ b/packages/shared/src/types.ts @@ -24,6 +24,7 @@ export type Player = { desiredAngle: number; // 0 - 1: will vary based on `ORB_SPRINTING_DROP_RATE` orbToDrop: number; + score: number; }; /**