From 7f9ca66c0ef08270ab6c2cb559d1832cc1e866e5 Mon Sep 17 00:00:00 2001 From: Dennis Postma Date: Tue, 30 Jul 2024 23:31:11 +0200 Subject: [PATCH] Worked on character animations --- src/events/character/Connect.ts | 7 ++-- src/events/character/Move.ts | 28 ++++++++------- src/events/gm/zone/Update.ts | 9 +++++ src/utilities/Player/AStar.ts | 64 ++++++--------------------------- src/utilities/Types.ts | 14 ++++---- 5 files changed, 46 insertions(+), 76 deletions(-) diff --git a/src/events/character/Connect.ts b/src/events/character/Connect.ts index e476d90..2b4f7a7 100644 --- a/src/events/character/Connect.ts +++ b/src/events/character/Connect.ts @@ -1,7 +1,6 @@ -import { Socket, Server } from 'socket.io' -import { TSocket } from '../../utilities/Types' +import { Server } from 'socket.io' +import { TSocket, ExtendedCharacter } from '../../utilities/Types' import CharacterRepository from '../../repositories/CharacterRepository' -import { Character, User } from '@prisma/client' type SocketResponseT = { character_id: number @@ -11,7 +10,7 @@ export default function (socket: TSocket, io: Server) { socket.on('character:connect', async (data: SocketResponseT) => { console.log('character:connect requested', data) try { - socket.character = (await CharacterRepository.getByUserAndId(socket.user?.id as number, data.character_id)) as Character + socket.character = (await CharacterRepository.getByUserAndId(socket.user?.id as number, data.character_id)) as ExtendedCharacter socket.emit('character:connect', socket.character) } catch (error: any) { console.log('character:connect error', error) diff --git a/src/events/character/Move.ts b/src/events/character/Move.ts index d0f8f57..ba955f0 100644 --- a/src/events/character/Move.ts +++ b/src/events/character/Move.ts @@ -2,22 +2,15 @@ import { Server } from 'socket.io' import { TSocket } from '../../utilities/Types' import ZoneManager from '../../managers/ZoneManager' import prisma from '../../utilities/Prisma' -import AStar, { type Node } from '../../utilities/Player/AStar' +import { AStar, type Node } from '../../utilities/Player/AStar' import Rotation from '../../utilities/Player/Rotation' +import { ExtendedCharacter as Character } from '../../utilities/Types' interface SocketResponse { position_x: number position_y: number } -interface Character { - id: number - position_x: number - position_y: number - rotation: number - zoneId: number -} - export default function setupCharacterMove(socket: TSocket, io: Server) { socket.on('character:move', async (data: SocketResponse) => { try { @@ -41,12 +34,23 @@ export default function setupCharacterMove(socket: TSocket, io: Server) { const path = AStar.findPath(start, end, grid) if (path.length > 0) { - await moveAlongPath(socket, io, path, grid) + socket.character.isMoving = true + io.in(socket.character.zoneId.toString()).emit('character:moved', socket.character) + try { + await moveAlongPath(socket, io, path, grid) + } finally { + socket.character.isMoving = false + io.in(socket.character.zoneId.toString()).emit('character:moved', socket.character) + } } else { console.log('character:move error', 'No valid path found') } } catch (error) { console.error('character:move error', error) + if (socket.character) { + socket.character.isMoving = false + io.in(socket.character.zoneId.toString()).emit('character:moved', socket.character) + } } }) } @@ -73,8 +77,6 @@ async function moveAlongPath(socket: TSocket, io: Server, path: Node[], grid: nu ZoneManager.updateCharacterInZone(socket.character.zoneId, socket.character) io.in(socket.character.zoneId.toString()).emit('character:moved', socket.character) - console.log('Character moved to', position) - // Add a small delay between moves to avoid overwhelming the server await new Promise((resolve) => setTimeout(resolve, 100)) } @@ -93,4 +95,4 @@ async function updateCharacterPosition(character: Character, x: number, y: numbe where: { id: character.id }, data: { position_x: x, position_y: y, rotation } }) -} +} \ No newline at end of file diff --git a/src/events/gm/zone/Update.ts b/src/events/gm/zone/Update.ts index 9430ebd..5f3a2bb 100644 --- a/src/events/gm/zone/Update.ts +++ b/src/events/gm/zone/Update.ts @@ -3,6 +3,7 @@ import { TSocket } from '../../../utilities/Types' import ZoneRepository from '../../../repositories/ZoneRepository' import { ZoneEventTile, ZoneObject } from '@prisma/client' import prisma from '../../../utilities/Prisma' +import zoneManager from '../../../managers/ZoneManager' interface IPayload { zoneId: number @@ -82,8 +83,16 @@ export default function (socket: TSocket, io: Server) { zone = await ZoneRepository.getById(data.zoneId) + if (!zone) { + console.log(`---Zone not found.`) + return + } + // send over zone and characters to socket socket.emit('gm:zone_editor:zone:load', zone) + + zoneManager.unloadZone(data.zoneId) + await zoneManager.loadZone(zone) } catch (error: any) { console.log(`---Error updating zone: ${error.message}`) } diff --git a/src/utilities/Player/AStar.ts b/src/utilities/Player/AStar.ts index dc33ec7..4df0e92 100644 --- a/src/utilities/Player/AStar.ts +++ b/src/utilities/Player/AStar.ts @@ -13,19 +13,13 @@ export interface Node extends Position { /** * A* pathfinding algorithm. */ -class AStar { +export class AStar { private static readonly ORTHOGONAL_DIRECTIONS: Position[] = [ - { x: 0, y: -1 }, // up - { x: 0, y: 1 }, // down - { x: -1, y: 0 }, // left - { x: 1, y: 0 } // right + { x: 0, y: -1 }, { x: 0, y: 1 }, { x: -1, y: 0 }, { x: 1, y: 0 } ] private static readonly DIAGONAL_DIRECTIONS: Position[] = [ - { x: -1, y: -1 }, // up-left - { x: -1, y: 1 }, // down-left - { x: 1, y: -1 }, // up-right - { x: 1, y: 1 } // down-right + { x: -1, y: -1 }, { x: -1, y: 1 }, { x: 1, y: -1 }, { x: 1, y: 1 } ] /** @@ -74,40 +68,27 @@ class AStar { return [] // No path found } - /** - * Gets the node with the lowest F score from a list. - */ private static getLowestFScoreNode(nodes: Node[]): Node { return nodes.reduce((min, node) => (node.f < min.f ? node : min)) } - /** - * Checks if the given node is the end node. - */ private static isEndNode(node: Node, end: Position): boolean { return node.x === end.x && node.y === end.y } - /** - * Removes a node from the open list. - */ private static removeNodeFromOpenList(openList: Node[], node: Node): void { const index = openList.findIndex((n) => n.x === node.x && n.y === node.y) if (index !== -1) openList.splice(index, 1) } - /** - * Converts a node to a string representation. - */ private static nodeToString(node: Position): string { return `${node.x},${node.y}` } - /** - * Gets valid neighbors of the given node. - */ private static getValidNeighbors(node: Node, grid: number[][], end: Position, allowDiagonal: boolean): Node[] { - const directions = allowDiagonal ? [...this.ORTHOGONAL_DIRECTIONS, ...this.DIAGONAL_DIRECTIONS] : this.ORTHOGONAL_DIRECTIONS + const directions = allowDiagonal + ? [...this.ORTHOGONAL_DIRECTIONS, ...this.DIAGONAL_DIRECTIONS] + : this.ORTHOGONAL_DIRECTIONS return directions .map((dir) => ({ @@ -117,50 +98,29 @@ class AStar { h: 0, f: 0 })) - .filter((pos) => this.isValidPosition(pos, grid, end)) as Node[] + .filter((pos) => this.isValidPosition(pos, grid, end)) } - /** - * Checks if the given position is valid. - */ private static isValidPosition(pos: Position, grid: number[][], end: Position): boolean { const { x, y } = pos - return x >= 0 && y >= 0 && x < grid.length && y < grid[0].length && (grid[y][x] === 0 || (x === end.x && y === end.y)) + return x >= 0 && y >= 0 && x < grid.length && y < grid[0].length && + (grid[y][x] === 0 || (x === end.x && y === end.y)) } - /** - * Checks if the given node is in the open list. - */ private static isInOpenList(openList: Node[], node: Position): boolean { return openList.some((n) => n.x === node.x && n.y === node.y) } - /** - * Gets the distance between two positions. - */ private static getDistance(a: Position, b: Position): number { const dx = Math.abs(a.x - b.x) const dy = Math.abs(a.y - b.y) - - if (a.x === b.x || a.y === b.y) { - // Orthogonal movement (horizontal/vertical) - return Math.sqrt(dx * dx + dy * dy) - } else { - // Diagonal movement with cost sqrt(2) - return Math.sqrt(dx * dx + dy * dy) - } + return Math.sqrt(dx * dx + dy * dy) } - /** - * Heuristic function estimating the distance from a node to the goal. - */ private static heuristic(node: Position, goal: Position): number { return this.getDistance(node, goal) } - /** - * Reconstructs the path from the end node. - */ private static reconstructPath(endNode: Node): Node[] { const path: Node[] = [] let currentNode: Node | undefined = endNode @@ -172,6 +132,4 @@ class AStar { return path } -} - -export default AStar +} \ No newline at end of file diff --git a/src/utilities/Types.ts b/src/utilities/Types.ts index 92d2534..a254d53 100644 --- a/src/utilities/Types.ts +++ b/src/utilities/Types.ts @@ -3,7 +3,7 @@ import { Character, User } from '@prisma/client' export type TSocket = Socket & { user?: User - character?: Character + character?: ExtendedCharacter handshake?: { query?: { token?: any @@ -16,13 +16,10 @@ export type TSocket = Socket & { } } -export type TCharacter = Socket & { - user?: User - character?: Character +export type ExtendedCharacter = Character & { + isMoving?: boolean } -export type TZoneCharacter = Character & {} - export type TAsset = { key: string url: string @@ -30,3 +27,8 @@ export type TAsset = { frameWidth?: number frameHeight?: number } + +// export type TCharacter = Socket & { +// user?: User +// character?: Character +// } \ No newline at end of file