diff options
| author | metamuffin <metamuffin@disroot.org> | 2024-06-21 12:39:50 +0200 | 
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2024-06-23 19:26:47 +0200 | 
| commit | 1ab1fd8cc03678ac180673884eff098821bcecd2 (patch) | |
| tree | fc4d4668628dd4cd45b7d57c4efe74fec135ecba | |
| parent | 607b3509f6bfd7d8ca39b12d01a6428689bb3ded (diff) | |
| download | hurrycurry-1ab1fd8cc03678ac180673884eff098821bcecd2.tar hurrycurry-1ab1fd8cc03678ac180673884eff098821bcecd2.tar.bz2 hurrycurry-1ab1fd8cc03678ac180673884eff098821bcecd2.tar.zst | |
refactor movement
| -rw-r--r-- | protocol.md | 7 | ||||
| -rw-r--r-- | server/src/customer/movement.rs | 18 | ||||
| -rw-r--r-- | test-client/main.ts | 47 | ||||
| -rw-r--r-- | test-client/movement.ts | 62 | ||||
| -rw-r--r-- | test-client/util.ts | 13 | ||||
| -rw-r--r-- | test-client/visual.ts | 3 | 
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"; | 
