Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
feat: max rotation angle
Browse files Browse the repository at this point in the history
  • Loading branch information
Pixselve committed Jan 24, 2024
1 parent 921b615 commit a9eec0d
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 29 deletions.
65 changes: 46 additions & 19 deletions packages/server/src/handleFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down
3 changes: 2 additions & 1 deletion packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
});
});

Expand Down
16 changes: 15 additions & 1 deletion packages/shared/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
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;

/**
* The radius of the player's head.
*/
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}
Expand Down
15 changes: 8 additions & 7 deletions packages/shared/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export type GameMap = {
width: number;
height: number;
players: Player[];
food: Food[]
}
food: Food[];
};

/**
* Represents a player.
Expand All @@ -17,26 +17,27 @@ export type Player = {
name: string;
color: string;
isSprinting: boolean;
angle: number;
}
angle: number; // in radians
desiredAngle: number; // in radians
};

/**
* Represents a coordinate.
*/
export type Position = {
x: number;
y: number;
}
};

export type Food = {
id: string;
position: Position;
}
};

/**
* Represents a player move.
*/
export type PlayerMove = {
angle: number;
isSprinting: boolean;
}
};
6 changes: 5 additions & 1 deletion packages/shared/src/utils.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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];
}

0 comments on commit a9eec0d

Please sign in to comment.