summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-06-21 12:39:50 +0200
committermetamuffin <metamuffin@disroot.org>2024-06-23 19:26:47 +0200
commit1ab1fd8cc03678ac180673884eff098821bcecd2 (patch)
treefc4d4668628dd4cd45b7d57c4efe74fec135ecba
parent607b3509f6bfd7d8ca39b12d01a6428689bb3ded (diff)
downloadhurrycurry-1ab1fd8cc03678ac180673884eff098821bcecd2.tar
hurrycurry-1ab1fd8cc03678ac180673884eff098821bcecd2.tar.bz2
hurrycurry-1ab1fd8cc03678ac180673884eff098821bcecd2.tar.zst
refactor movement
-rw-r--r--protocol.md7
-rw-r--r--server/src/customer/movement.rs18
-rw-r--r--test-client/main.ts47
-rw-r--r--test-client/movement.ts62
-rw-r--r--test-client/util.ts13
-rw-r--r--test-client/visual.ts3
6 files changed, 85 insertions, 65 deletions
diff --git a/protocol.md b/protocol.md
index 7f86df7b..093bce58 100644
--- a/protocol.md
+++ b/protocol.md
@@ -19,3 +19,10 @@ The protocol schema is defined in [`protocol.ts`](./test-client/protocol.ts)
Collisions are handled by the clients. Whenever to players collide the player
with the greater PlayerID is responsible for updating their own momentum and
sending a packet to update that of the other player.
+
+## Movement
+
+Movement is handled mostly client-side. Therefore it is implement three times:
+- In the test-client: [movement.ts](./test-client/movement.ts)
+- For customers in the server: [movement.rs](./server/src/customer/movement.rs)
+- In the client: [movement.rs](./client/scripts/player.gd)
diff --git a/server/src/customer/movement.rs b/server/src/customer/movement.rs
index 0ddabd0b..b45c7931 100644
--- a/server/src/customer/movement.rs
+++ b/server/src/customer/movement.rs
@@ -2,6 +2,9 @@ use crate::protocol::PacketS;
use glam::{IVec2, Vec2};
use std::collections::HashSet;
+const PLAYER_SIZE: f32 = 0.4;
+const PLAYER_SPEED: f32 = 25.;
+
pub struct MovementBase {
pub position: Vec2,
pub facing: Vec2,
@@ -15,10 +18,11 @@ impl MovementBase {
self.facing = direction + (self.facing - direction) * (-dt * 10.).exp();
}
let rot = self.facing.x.atan2(self.facing.y);
- self.vel += direction * dt * 0.5;
- self.position += self.vel;
+ self.vel += direction * dt * PLAYER_SPEED;
+ self.position += self.vel * dt;
self.vel = self.vel * (-dt * 5.).exp();
collide_player(self, map);
+
PacketS::Position {
pos: self.position,
rot,
@@ -26,7 +30,6 @@ impl MovementBase {
}
}
-const PLAYER_SIZE: f32 = 0.4;
pub fn collide_player(p: &mut MovementBase, map: &HashSet<IVec2>) {
for xo in -1..=1 {
for yo in -1..=1 {
@@ -35,15 +38,15 @@ pub fn collide_player(p: &mut MovementBase, map: &HashSet<IVec2>) {
continue;
}
let tile = tile.as_vec2();
- let d = aabb_circle_distance(tile, tile + Vec2::ONE, p.position);
+ let d = aabb_point_distance(tile, tile + Vec2::ONE, p.position);
if d > PLAYER_SIZE {
continue;
}
let h = 0.01;
let d_sample_x =
- aabb_circle_distance(tile, tile + Vec2::ONE, p.position + Vec2::new(h, 0.));
+ aabb_point_distance(tile, tile + Vec2::ONE, p.position + Vec2::new(h, 0.));
let d_sample_y =
- aabb_circle_distance(tile, tile + Vec2::ONE, p.position + Vec2::new(0., h));
+ aabb_point_distance(tile, tile + Vec2::ONE, p.position + Vec2::new(0., h));
let grad = (Vec2::new(d_sample_x, d_sample_y) - d) / h;
p.position += (PLAYER_SIZE - d) * grad;
@@ -51,6 +54,7 @@ pub fn collide_player(p: &mut MovementBase, map: &HashSet<IVec2>) {
}
}
}
-pub fn aabb_circle_distance(min: Vec2, max: Vec2, p: Vec2) -> f32 {
+
+pub fn aabb_point_distance(min: Vec2, max: Vec2, p: Vec2) -> f32 {
(p - p.clamp(min, max)).length()
}
diff --git a/test-client/main.ts b/test-client/main.ts
index 84dfd555..1e6168ed 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -1,11 +1,10 @@
/// <reference lib="dom" />
+import { player_movement_update } from "./movement.ts";
import { Gamedata, ItemIndex, Message, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts";
-import { V2, add_v2, length, lerp_exp_v2_mut, normalize, aabb_circle_distance, sub_v2, lerp_exp } from "./util.ts";
+import { V2, add_v2, lerp_exp_v2_mut, normalize, lerp_exp } from "./util.ts";
import { draw_ingame, draw_wait } from "./visual.ts";
-export const PLAYER_SIZE = 0.4;
-
export let ctx: CanvasRenderingContext2D;
export let canvas: HTMLCanvasElement;
let ws: WebSocket;
@@ -205,14 +204,7 @@ function frame_update(dt: number) {
y: (+keys_down.has("KeyS") - +keys_down.has("KeyW"))
})
- if (length(input) > 0.1) lerp_exp_v2_mut(p.facing, input, dt * 10.)
- p.rot = Math.atan2(p.facing.x, p.facing.y)
- p.vel.x += input.x * dt * 0.5
- p.vel.y += input.y * dt * 0.5
- p.x += p.vel.x
- p.y += p.vel.y
- collide_player(p, dt)
- lerp_exp_v2_mut(p.vel, { x: 0, y: 0 }, dt * 5.)
+ player_movement_update(p, dt, input)
const update_item = (item: ItemData) => {
if (item.tracking) lerp_exp_v2_mut(item, item.tracking, dt * 10.)
@@ -260,36 +252,3 @@ function draw() {
else throw new Error(`ws state invalid`);
requestAnimationFrame(draw)
}
-
-function collide_player(p: PlayerData, dt: number) {
- const tiles_ignored = ["floor", "door", "chair"].map(t => data.tile_names.indexOf(t))
- for (const [_, tile] of tiles) {
- if (tiles_ignored.includes(tile.kind)) continue
- const d = aabb_circle_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x, p.y)
- if (d > PLAYER_SIZE) continue
-
- const h = 0.01
- const d_sample_x = aabb_circle_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x + h, p.y)
- const d_sample_y = aabb_circle_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x, p.y + h)
- const grad_x = (d_sample_x - d) / h
- const grad_y = (d_sample_y - d) / h
-
- p.x += (PLAYER_SIZE - d) * grad_x
- p.y += (PLAYER_SIZE - d) * grad_y
-
- const vdotn = (grad_x * p.vel.x) + (grad_y * p.vel.y)
- p.vel.x -= grad_x * vdotn
- p.vel.y -= grad_y * vdotn
- }
-
- for (const [_, player] of players) {
- const diff = sub_v2(p, player)
- const d = length(diff)
- if (d < 0.01) continue
- if (d >= PLAYER_SIZE * 2) continue
- const norm = normalize(diff);
- const f = 1 / (1 + d)
- p.vel.x += norm.x * f * dt
- p.vel.y += norm.y * f * dt
- }
-}
diff --git a/test-client/movement.ts b/test-client/movement.ts
new file mode 100644
index 00000000..883a64ec
--- /dev/null
+++ b/test-client/movement.ts
@@ -0,0 +1,62 @@
+import { data } from "./main.ts";
+import { tiles, players, PlayerData } from "./main.ts";
+import { V2, normalize, length, sub_v2, lerp_exp_v2_mut } from "./util.ts";
+
+export const PLAYER_SIZE = 0.4;
+
+export function player_movement_update(p: PlayerData, dt: number, input: V2) {
+ if (length(input) > 0.1) lerp_exp_v2_mut(p.facing, input, dt * 10.)
+ p.rot = Math.atan2(p.facing.x, p.facing.y)
+ p.vel.x += input.x * dt * 25
+ p.vel.y += input.y * dt * 25
+ p.x += p.vel.x * dt
+ p.y += p.vel.y * dt
+ collide_player(p, dt)
+ lerp_exp_v2_mut(p.vel, { x: 0, y: 0 }, dt * 5.)
+}
+
+function collide_player(p: PlayerData, dt: number) {
+ for (const [_, tile] of tiles) {
+ if (!data.tile_collide[tile.kind]) continue
+
+ const d = aabb_point_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x, p.y)
+ if (d > PLAYER_SIZE) continue
+
+ const h = 0.01
+ const d_sample_x = aabb_point_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x + h, p.y)
+ const d_sample_y = aabb_point_distance(tile.x, tile.y, tile.x + 1, tile.y + 1, p.x, p.y + h)
+ const grad_x = (d_sample_x - d) / h
+ const grad_y = (d_sample_y - d) / h
+
+ p.x += (PLAYER_SIZE - d) * grad_x
+ p.y += (PLAYER_SIZE - d) * grad_y
+
+ const vdotn = (grad_x * p.vel.x) + (grad_y * p.vel.y)
+ p.vel.x -= grad_x * vdotn
+ p.vel.y -= grad_y * vdotn
+ }
+
+ for (const [_, player] of players) {
+ const diff = sub_v2(p, player)
+ const d = length(diff)
+ if (d < 0.01) continue
+ if (d >= PLAYER_SIZE * 2) continue
+ const norm = normalize(diff);
+ const f = 1 / (1 + d)
+ p.vel.x += norm.x * f * dt
+ p.vel.y += norm.y * f * dt
+ }
+}
+
+export function aabb_point_distance(
+ min_x: number,
+ min_y: number,
+ max_x: number,
+ max_y: number,
+ px: number,
+ py: number
+): number {
+ const dx = px - Math.max(min_x, Math.min(max_x, px))
+ const dy = py - Math.max(min_y, Math.min(max_y, py))
+ return Math.sqrt(dx * dx + dy * dy)
+}
diff --git a/test-client/util.ts b/test-client/util.ts
index 1c431411..975a5700 100644
--- a/test-client/util.ts
+++ b/test-client/util.ts
@@ -22,16 +22,3 @@ export function add_v2(p: V2, o: V2 | number) {
else return { x: p.x + o.x, y: p.y + o.y }
}
export function sub_v2(p: V2, o: V2) { return { x: p.x - o.x, y: p.y - o.y } }
-
-export function aabb_circle_distance(
- min_x: number,
- min_y: number,
- max_x: number,
- max_y: number,
- px: number,
- py: number
-): number {
- const dx = px - Math.max(min_x, Math.min(max_x, px))
- const dy = py - Math.max(min_y, Math.min(max_y, py))
- return Math.sqrt(dx * dx + dy * dy)
-}
diff --git a/test-client/visual.ts b/test-client/visual.ts
index 54c979da..cd32b77b 100644
--- a/test-client/visual.ts
+++ b/test-client/visual.ts
@@ -1,4 +1,5 @@
-import { ItemData, PLAYER_SIZE, camera, canvas, ctx, data, get_interact_target, interact_possible_anim, interact_target_anim, items_removed, keys_down, players, tiles } from "./main.ts";
+import { ItemData, camera, canvas, ctx, data, get_interact_target, interact_possible_anim, interact_target_anim, items_removed, keys_down, players, tiles } from "./main.ts";
+import { PLAYER_SIZE } from "./movement.ts";
import { Message } from "./protocol.ts";
import { FALLBACK_TILE, ITEMS, TILES, FALLBACK_ITEM } from "./tiles.ts";
import { V2, ceil_v2, floor_v2 } from "./util.ts";