forked from noxious/server
A* and move logic improvements
This commit is contained in:
parent
079d9408a8
commit
acc9eaae9e
@ -40,21 +40,32 @@ async function moveAlongPath(socket: TSocket, io: Server, path: Array<{ x: numbe
|
|||||||
|
|
||||||
for (let i = 0; i < path.length - 1; i++) {
|
for (let i = 0; i < path.length - 1; i++) {
|
||||||
const startTime = Date.now()
|
const startTime = Date.now()
|
||||||
|
const start = path[i]
|
||||||
|
const end = path[i + 1]
|
||||||
|
|
||||||
while (Date.now() - startTime < stepDuration) {
|
while (Date.now() - startTime < stepDuration) {
|
||||||
if (moveTokens.get(character.id) !== moveToken) return
|
if (moveTokens.get(character.id) !== moveToken) return
|
||||||
|
|
||||||
const progress = (Date.now() - startTime) / stepDuration
|
const progress = (Date.now() - startTime) / stepDuration
|
||||||
const current = interpolatePosition(path[i], path[i + 1], progress)
|
const current = interpolatePosition(start, end, progress)
|
||||||
|
|
||||||
if (isObstacle(current, grid)) break
|
if (isObstacle(current, grid)) {
|
||||||
|
// If obstacle encountered, stop at the last valid position
|
||||||
|
await updateCharacter(character, start, Rotation.calculate(start.x, start.y, end.x, end.y))
|
||||||
|
io.in(character.zoneId.toString()).emit('character:moved', character)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await updateCharacter(character, current, Rotation.calculate(path[i].x, path[i].y, path[i + 1].x, path[i + 1].y))
|
await updateCharacter(character, current, Rotation.calculate(start.x, start.y, end.x, end.y))
|
||||||
io.in(character.zoneId.toString()).emit('character:moved', character)
|
io.in(character.zoneId.toString()).emit('character:moved', character)
|
||||||
await new Promise((resolve) => setTimeout(resolve, updateInterval))
|
await new Promise((resolve) => setTimeout(resolve, updateInterval))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the character reaches the exact final position
|
||||||
if (moveTokens.get(character.id) === moveToken) {
|
if (moveTokens.get(character.id) === moveToken) {
|
||||||
|
const finalPosition = path[path.length - 1]
|
||||||
|
await updateCharacter(character, finalPosition, character.rotation)
|
||||||
character.isMoving = false
|
character.isMoving = false
|
||||||
moveTokens.delete(character.id)
|
moveTokens.delete(character.id)
|
||||||
io.in(character.zoneId.toString()).emit('character:moved', character)
|
io.in(character.zoneId.toString()).emit('character:moved', character)
|
||||||
@ -66,7 +77,14 @@ const interpolatePosition = (start: { x: number; y: number }, end: { x: number;
|
|||||||
y: start.y + (end.y - start.y) * progress
|
y: start.y + (end.y - start.y) * progress
|
||||||
})
|
})
|
||||||
|
|
||||||
const isObstacle = ({ x, y }: { x: number; y: number }, grid: number[][]) => grid[Math.floor(y)]?.[Math.floor(x)] === 1
|
const isObstacle = ({ x, y }: { x: number; y: number }, grid: number[][]) => {
|
||||||
|
const gridX = Math.floor(x)
|
||||||
|
const gridY = Math.floor(y)
|
||||||
|
return grid[gridY]?.[gridX] === 1 ||
|
||||||
|
grid[gridY]?.[Math.ceil(x)] === 1 ||
|
||||||
|
grid[Math.ceil(y)]?.[gridX] === 1 ||
|
||||||
|
grid[Math.ceil(y)]?.[Math.ceil(x)] === 1
|
||||||
|
}
|
||||||
|
|
||||||
async function updateCharacter(character: ExtendedCharacter, { x, y }: { x: number; y: number }, rotation: number) {
|
async function updateCharacter(character: ExtendedCharacter, { x, y }: { x: number; y: number }, rotation: number) {
|
||||||
Object.assign(character, { position_x: x, position_y: y, rotation })
|
Object.assign(character, { position_x: x, position_y: y, rotation })
|
||||||
|
@ -19,12 +19,7 @@ export default function (socket: TSocket, io: Server) {
|
|||||||
const character = await CharacterRepository.getByUserAndId(socket.user?.id as number, socket.character?.id as number)
|
const character = await CharacterRepository.getByUserAndId(socket.user?.id as number, socket.character?.id as number)
|
||||||
if (!character) return
|
if (!character) return
|
||||||
|
|
||||||
// When 1 arg is provided, only send message. 2 includes a title
|
io.emit('notification', { title: 'Message from GM', message: args.join(' ') })
|
||||||
if (args.length === 1) {
|
|
||||||
return io.emit('notification', { message: args[0] })
|
|
||||||
}
|
|
||||||
|
|
||||||
io.emit('notification', { title: args[0], message: args.slice(1).join(' ') })
|
|
||||||
callback(true)
|
callback(true)
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log(`---Error sending message: ${error.message}`)
|
console.log(`---Error sending message: ${error.message}`)
|
||||||
|
@ -3,10 +3,10 @@ export type Node = Position & { parent?: Node; g: number; h: number; f: number }
|
|||||||
|
|
||||||
export class AStar {
|
export class AStar {
|
||||||
private static readonly DIRECTIONS = [
|
private static readonly DIRECTIONS = [
|
||||||
{ x: 0, y: -1 },
|
{ x: 0, y: -1 }, // Up
|
||||||
{ x: 0, y: 1 },
|
{ x: 0, y: 1 }, // Down
|
||||||
{ x: -1, y: 0 },
|
{ x: -1, y: 0 }, // Left
|
||||||
{ x: 1, y: 0 },
|
{ x: 1, y: 0 }, // Right
|
||||||
{ x: -1, y: -1 },
|
{ x: -1, y: -1 },
|
||||||
{ x: -1, y: 1 },
|
{ x: -1, y: 1 },
|
||||||
{ x: 1, y: -1 },
|
{ x: 1, y: -1 },
|
||||||
@ -54,7 +54,8 @@ export class AStar {
|
|||||||
private static getDistance(a: Position, b: Position): number {
|
private static getDistance(a: Position, b: Position): number {
|
||||||
const dx = Math.abs(a.x - b.x),
|
const dx = Math.abs(a.x - b.x),
|
||||||
dy = Math.abs(a.y - b.y)
|
dy = Math.abs(a.y - b.y)
|
||||||
return Math.sqrt(dx * dx + dy * dy)
|
// Manhattan distance for straight paths, then Euclidean for diagonals
|
||||||
|
return dx + dy + (Math.sqrt(2) - 2) * Math.min(dx, dy)
|
||||||
}
|
}
|
||||||
|
|
||||||
private static reconstructPath(endNode: Node): Node[] {
|
private static reconstructPath(endNode: Node): Node[] {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user