From a9eec0dfa4973584d37abc16209bafa00828909c Mon Sep 17 00:00:00 2001 From: Mael Kerichard <38262536+Pixselve@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:35:30 +0100 Subject: [PATCH] feat: max rotation angle --- packages/server/src/handleFrame.ts | 65 +++++++++++++++++++++--------- packages/server/src/index.ts | 3 +- packages/shared/src/constants.ts | 16 +++++++- packages/shared/src/types.ts | 15 +++---- packages/shared/src/utils.ts | 6 ++- 5 files changed, 76 insertions(+), 29 deletions(-) diff --git a/packages/server/src/handleFrame.ts b/packages/server/src/handleFrame.ts index 5204bc4..2750c5c 100644 --- a/packages/server/src/handleFrame.ts +++ b/packages/server/src/handleFrame.ts @@ -2,34 +2,61 @@ import { BASE_SPEED, FOOD_PICKUP_RADIUS, GameMap, + getPlayerHead, + Player, SPRINT_SPEED, + MAX_ANGLE, } from "@viper-vortex/shared"; +function movePlayer(player: Player, gameMap: GameMap) { + // move the player + // start with the head + + const head = getPlayerHead(player); + const speed = player.isSprinting ? SPRINT_SPEED : BASE_SPEED; + + const currentAngle = player.angle; + const targetAngle = player.desiredAngle; + + // calculate the angle to turn + let angleDiff = targetAngle - currentAngle; + if (angleDiff > Math.PI) angleDiff -= Math.PI * 2; + if (angleDiff < -Math.PI) angleDiff += Math.PI * 2; + + // limit the angle to turn + if (angleDiff > MAX_ANGLE) angleDiff = MAX_ANGLE; + if (angleDiff < -MAX_ANGLE) angleDiff = -MAX_ANGLE; + + // apply the angle + player.angle += angleDiff; + + head.x += Math.cos(player.angle) * speed; + head.y += Math.sin(player.angle) * speed; + + // if the player reaches the edge of the map, slides along the edge + if (head.x < 0) head.x = 0; + if (head.y < 0) head.y = 0; + if (head.x > gameMap.width) head.x = gameMap.width; + if (head.y > gameMap.height) head.y = gameMap.height; + + // then all the other body parts follow by moving to the position of the previous body part + for (let i = player.body.length - 1; i > 0; i--) { + const currentPart = player.body[i]; + const previousPart = player.body[i - 1]; + currentPart.x = previousPart.x; + currentPart.y = previousPart.y; + } + return head; +} + export default function handleFrame( gameMap: GameMap, onPlayerDeath: (playerId: string) => void, ) { for (let player of gameMap.players) { - // move the player - // start with the head - const head = player.body[0]; - const speed = player.isSprinting ? SPRINT_SPEED : BASE_SPEED; - head.x += Math.cos(player.angle) * speed; - head.y += Math.sin(player.angle) * speed; - - // if the player reaches the edge of the map, slides along the edge - if (head.x < 0) head.x = 0; - if (head.y < 0) head.y = 0; - if (head.x > gameMap.width) head.x = gameMap.width; - if (head.y > gameMap.height) head.y = gameMap.height; + movePlayer(player, gameMap); - // then all the other body parts follow by moving to the position of the previous body part - for (let i = player.body.length - 1; i > 0; i--) { - const currentPart = player.body[i]; - const previousPart = player.body[i - 1]; - currentPart.x = previousPart.x; - currentPart.y = previousPart.y; - } + const head = getPlayerHead(player); // check for collisions with food. Radius of 10 for (let i = 0; i < gameMap.food.length; i++) { diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 3d5dfbb..618a196 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -35,6 +35,7 @@ io.on(SOCKET_EVENTS.CONNECT, (socket) => { body: [{ x: 0, y: 0 }], isSprinting: false, angle: 0, + desiredAngle: 0, }; gameMap.players.push(player); @@ -51,7 +52,7 @@ io.on(SOCKET_EVENTS.CONNECT, (socket) => { socket.on(SOCKET_EVENTS.MOVE, (move) => { // we rely on the reference to the player object player.isSprinting = move.isSprinting; - player.angle = move.angle; + player.desiredAngle = move.angle; }); }); diff --git a/packages/shared/src/constants.ts b/packages/shared/src/constants.ts index 91a2bcd..e937a68 100644 --- a/packages/shared/src/constants.ts +++ b/packages/shared/src/constants.ts @@ -1,6 +1,15 @@ -export const TPS = 60; // ticks per second +/** + * The number of ticks per second. + */ +export const TPS = 60; +/** + * The speed at which the player moves when walking. + */ export const BASE_SPEED = 2; +/** + * The speed at which the player moves when sprinting. + */ export const SPRINT_SPEED = 5; /** @@ -8,6 +17,11 @@ export const SPRINT_SPEED = 5; */ export const FOOD_PICKUP_RADIUS = 20; +/** + * The maximum angle the player can turn in one tick. + */ +export const MAX_ANGLE = Math.PI / 20; + /** * Enum for socket events. * @enum {string} diff --git a/packages/shared/src/types.ts b/packages/shared/src/types.ts index 4544e3b..38b02e0 100644 --- a/packages/shared/src/types.ts +++ b/packages/shared/src/types.ts @@ -5,8 +5,8 @@ export type GameMap = { width: number; height: number; players: Player[]; - food: Food[] -} + food: Food[]; +}; /** * Represents a player. @@ -17,8 +17,9 @@ export type Player = { name: string; color: string; isSprinting: boolean; - angle: number; -} + angle: number; // in radians + desiredAngle: number; // in radians +}; /** * Represents a coordinate. @@ -26,12 +27,12 @@ export type Player = { export type Position = { x: number; y: number; -} +}; export type Food = { id: string; position: Position; -} +}; /** * Represents a player move. @@ -39,4 +40,4 @@ export type Food = { export type PlayerMove = { angle: number; isSprinting: boolean; -} +}; diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index a2c2a52..35c966b 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -1,5 +1,5 @@ import { v4 as uuidv4 } from "uuid"; -import { Food, GameMap } from "./types"; +import { Food, GameMap, Player } from "./types"; /** * Create a new game map. @@ -34,3 +34,7 @@ export function randomDarkColor() { const randomColor = Math.floor(Math.random() * 16777215).toString(16); return "#" + randomColor; } + +export function getPlayerHead(player: Player) { + return player.body[0]; +}