aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pixel-client/src/game.rs5
-rw-r--r--pixel-client/src/main.rs34
-rw-r--r--pixel-client/src/menu.rs7
-rw-r--r--pixel-client/src/render/mod.rs11
-rw-r--r--server/examples/client.rs70
-rw-r--r--server/protocol/src/lib.rs7
-rw-r--r--server/protocol/src/movement.rs21
-rw-r--r--server/src/game.rs119
-rw-r--r--server/src/lib.rs1
-rw-r--r--server/src/main.rs2
-rw-r--r--server/src/spatial_index.rs31
-rw-r--r--test-client/index.html2
-rw-r--r--test-client/main.ts17
-rw-r--r--test-client/movement.ts36
-rw-r--r--test-client/protocol.ts2
15 files changed, 181 insertions, 184 deletions
diff --git a/pixel-client/src/game.rs b/pixel-client/src/game.rs
index 1fc49c6b..7e43bdc9 100644
--- a/pixel-client/src/game.rs
+++ b/pixel-client/src/game.rs
@@ -348,7 +348,10 @@ impl Game {
}
pub fn draw(&self, ctx: &mut SpriteRenderer) {
- ctx.set_view(-self.camera_center + (ctx.size / ctx.get_scale() / 2.), 1.);
+ ctx.set_view(
+ -self.camera_center + (ctx.size / ctx.get_scale() / 2.),
+ ctx.size.min_element() / 32. / 10.,
+ );
self.tilemap.draw(ctx);
diff --git a/pixel-client/src/main.rs b/pixel-client/src/main.rs
index db2585af..7501aba2 100644
--- a/pixel-client/src/main.rs
+++ b/pixel-client/src/main.rs
@@ -15,10 +15,9 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-use anyhow::anyhow;
use clap::{Parser, Subcommand};
use game::Game;
-use hurrycurry_protocol::glam::{UVec2, Vec2};
+use hurrycurry_protocol::glam::Vec2;
use menu::Menu;
use network::Network;
use render::SpriteRenderer;
@@ -27,10 +26,7 @@ use sdl2::{
keyboard::{KeyboardState, Keycode},
pixels::Color,
};
-use std::{
- str::FromStr,
- time::{Duration, Instant},
-};
+use std::time::{Duration, Instant};
pub mod game;
pub mod helper;
@@ -41,9 +37,6 @@ pub mod tilemap;
#[derive(Debug, Parser)]
pub struct Args {
- #[arg(short = 'r', long, default_value = "320x240")]
- logical_resolution: Resolution,
-
#[clap(subcommand)]
action: Option<Action>,
}
@@ -58,16 +51,6 @@ pub enum Action {
},
}
-#[derive(Debug, Clone)]
-struct Resolution(UVec2);
-impl FromStr for Resolution {
- type Err = anyhow::Error;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- let (x, y) = s.split_once("x").ok_or(anyhow!("sep missing"))?;
- Ok(Resolution(UVec2::new(x.parse()?, y.parse()?)))
- }
-}
-
enum State {
Ingame(Game),
Menu(Menu),
@@ -83,7 +66,6 @@ fn main() {
.unwrap();
let sdl_context = sdl2::init().unwrap();
- let ttf_context = sdl2::ttf::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem
@@ -113,22 +95,12 @@ fn main() {
)),
};
- // let font = ttf_context
- // .load_font("/usr/share/fonts/noto/NotoSansMono-Regular.ttf", 24)
- // .unwrap();
- // let text = font.render("Hello world").blended(Color::WHITE).unwrap();
- // texture_creator.create_texture_from_surface(text).unwrap();
-
let mut events = sdl_context.event_pump().unwrap();
let mut last_tick = Instant::now();
- canvas
- .set_logical_size(args.logical_resolution.0.x, args.logical_resolution.0.y)
- .unwrap();
-
'mainloop: loop {
- let (width, height) = canvas.logical_size();
+ let (width, height) = canvas.output_size().unwrap();
renderer.size = Vec2::new(width as f32, height as f32);
let keyboard = KeyboardState::new(&events);
diff --git a/pixel-client/src/menu.rs b/pixel-client/src/menu.rs
index d1f43a84..0a05e84c 100644
--- a/pixel-client/src/menu.rs
+++ b/pixel-client/src/menu.rs
@@ -8,10 +8,5 @@ impl Menu {
Self {}
}
pub fn tick(&mut self, dt: f32, keyboard: &KeyboardState, layout: &AtlasLayout) {}
- pub fn draw(&self, ctx: &mut SpriteRenderer) {
-
-
-
-
- }
+ pub fn draw(&self, ctx: &mut SpriteRenderer) {}
}
diff --git a/pixel-client/src/render/mod.rs b/pixel-client/src/render/mod.rs
index a2aea365..f18d96ad 100644
--- a/pixel-client/src/render/mod.rs
+++ b/pixel-client/src/render/mod.rs
@@ -34,6 +34,8 @@ pub struct SpriteRenderer<'a> {
pub size: Vec2,
texture: Texture<'a>,
+ round: bool,
+
view_scale: Vec2,
view_offset: Vec2,
@@ -103,6 +105,7 @@ impl<'a> SpriteRenderer<'a> {
.collect::<HashMap<_, _>>();
Self {
+ round: true,
texture,
size: Vec2::ONE,
metadata,
@@ -139,10 +142,10 @@ impl<'a> SpriteRenderer<'a> {
z_order: sprite.z_order,
src: sprite.src,
dst: FRect::new(
- ((sprite.dst.x + self.view_offset.x) * self.view_scale.x).round(),
- ((sprite.dst.y + self.view_offset.y) * self.view_scale.y).round(),
- (sprite.dst.w * self.view_scale.x).round(),
- (sprite.dst.h * self.view_scale.y).round(),
+ (sprite.dst.x + self.view_offset.x) * self.view_scale.x,
+ (sprite.dst.y + self.view_offset.y) * self.view_scale.y,
+ sprite.dst.w * self.view_scale.x,
+ sprite.dst.h * self.view_scale.y,
),
})
}
diff --git a/server/examples/client.rs b/server/examples/client.rs
deleted file mode 100644
index 70b1bb00..00000000
--- a/server/examples/client.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- Hurry Curry! - a game about cooking
- Copyright 2024 metamuffin
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as published by
- the Free Software Foundation, version 3 of the License only.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-*/
-use hurrycurry_protocol::{glam::Vec2, PacketC, PacketS};
-use std::{
- io::{stdin, BufRead, BufReader, Write},
- net::TcpStream,
- thread,
-};
-
-fn main() {
- let mut sock = TcpStream::connect("127.0.0.1:27031").unwrap();
-
- let sock2 = BufReader::new(sock.try_clone().unwrap());
- thread::spawn(move || {
- for line in sock2.lines() {
- let line = line.unwrap();
- let packet: PacketC = serde_json::from_str(&line).unwrap();
- eprintln!("{packet:?}")
- }
- });
-
- for line in stdin().lines() {
- let line = line.unwrap();
- let mut toks = line.split(" ");
- let packet = match toks.next().unwrap() {
- "j" => PacketS::Join {
- character: 0,
- name: "test".to_string(),
- },
- "p" => PacketS::Position {
- pos: Vec2::new(
- toks.next().unwrap().parse().unwrap(),
- toks.next().unwrap().parse().unwrap(),
- ),
- boosting: false,
- rot: 0.,
- },
- "i" => PacketS::Position {
- pos: Vec2::new(
- toks.next().unwrap().parse().unwrap(),
- toks.next().unwrap().parse().unwrap(),
- ),
- boosting: false,
- rot: toks.next().unwrap_or("0").parse().unwrap(),
- },
- _ => {
- println!("unknown");
- continue;
- }
- };
- sock.write_all(serde_json::to_string(&packet).unwrap().as_bytes())
- .unwrap();
- sock.write_all(b"\n").unwrap();
- }
-}
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index f2a6dd27..14c410b3 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -88,11 +88,12 @@ pub enum PacketS {
character: i32,
},
Leave,
- Position {
+ Movement {
#[bincode(with_serde)]
- pos: Vec2,
- rot: f32,
+ direction: Vec2,
boosting: bool,
+ #[bincode(with_serde)]
+ pos: Option<Vec2>,
},
Interact {
#[bincode(with_serde)]
diff --git a/server/protocol/src/movement.rs b/server/protocol/src/movement.rs
index 9abff295..ab4eb818 100644
--- a/server/protocol/src/movement.rs
+++ b/server/protocol/src/movement.rs
@@ -72,21 +72,32 @@ impl MovementBase {
self.velocity += direction * dt * speed;
self.position += self.velocity * dt;
self.velocity = self.velocity * (-dt * PLAYER_FRICTION).exp();
- collide_player(self, map);
+ collide_player_tiles(self, map);
- PacketS::Position {
- pos: self.position,
+ PacketS::Movement {
+ pos: Some(self.position),
boosting: self.boosting,
- rot: self.rotation,
+ direction,
}
}
+ pub fn collide(&mut self, other: &mut Self, dt: f32) {
+ let diff = self.position - other.position;
+ let d = diff.length();
+ if d < 0.01 || d > PLAYER_SIZE * 2. {
+ return;
+ }
+ let norm = diff.normalize();
+ let f = 100. / (1. + d);
+ self.velocity += norm * f * dt
+ }
+
pub fn get_interact_target(&self) -> IVec2 {
(self.position + Vec2::new(self.rotation.sin(), self.rotation.cos())).as_ivec2()
}
}
-pub fn collide_player(p: &mut MovementBase, map: &HashSet<IVec2>) {
+fn collide_player_tiles(p: &mut MovementBase, map: &HashSet<IVec2>) {
for xo in -1..=1 {
for yo in -1..=1 {
let tile = IVec2::new(xo, yo) + p.position.as_ivec2();
diff --git a/server/src/game.rs b/server/src/game.rs
index 1c50c7c2..b3b23ce0 100644
--- a/server/src/game.rs
+++ b/server/src/game.rs
@@ -20,16 +20,18 @@ use crate::{
data::Gamedata,
entity::{Entity, EntityT},
interaction::{interact, tick_slot, InteractEffect, TickEffect},
+ spatial_index::SpatialIndex,
};
use anyhow::{anyhow, bail, Result};
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
+ movement::MovementBase,
ClientGamedata, ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, RecipeIndex,
TileIndex,
};
use log::{info, warn};
use std::{
- collections::{HashMap, VecDeque},
+ collections::{HashMap, HashSet, VecDeque},
sync::Arc,
time::{Duration, Instant},
};
@@ -55,17 +57,22 @@ pub struct Tile {
pub struct Player {
pub name: String,
pub character: i32,
- pub position: Vec2,
- pub last_position_ts: Instant,
pub interacting: Option<IVec2>,
pub item: Option<Item>,
pub communicate_persist: Option<Message>,
+
+ movement: MovementBase,
+ direction: Vec2,
+ boost: bool,
+ last_position_update: Instant,
}
pub struct Game {
pub data: Arc<Gamedata>,
tiles: HashMap<IVec2, Tile>,
+ walkable: HashSet<IVec2>,
pub players: HashMap<PlayerID, Player>,
+ players_spatial_index: SpatialIndex<PlayerID>,
packet_out: VecDeque<PacketC>,
demand: Option<DemandState>,
pub points: i64,
@@ -80,9 +87,11 @@ impl Game {
packet_out: Default::default(),
players: HashMap::new(),
tiles: HashMap::new(),
+ walkable: HashSet::new(),
demand: None,
end: None,
entities: vec![],
+ players_spatial_index: SpatialIndex::default(),
points: 0,
}
}
@@ -130,15 +139,27 @@ impl Game {
}),
},
);
+ if !self.data.tile_collide[tile.0] {
+ self.walkable.insert(p);
+ }
}
for (id, (name, character)) in players {
self.players.insert(
id,
Player {
item: None,
- last_position_ts: Instant::now(),
character,
- position: self.data.chef_spawn,
+ movement: MovementBase {
+ position: self.data.chef_spawn,
+ facing: Vec2::X,
+ rotation: 0.,
+ velocity: Vec2::ZERO,
+ boosting: false,
+ stamina: 0.,
+ },
+ last_position_update: Instant::now(),
+ boost: false,
+ direction: Vec2::ZERO,
communicate_persist: None,
interacting: None,
name: name.clone(),
@@ -189,7 +210,7 @@ impl Game {
for (&id, player) in &self.players {
out.push(PacketC::AddPlayer {
id,
- position: player.position,
+ position: player.movement.position,
character: player.character,
name: player.name.clone(),
});
@@ -262,9 +283,18 @@ impl Game {
player,
Player {
item: None,
- last_position_ts: Instant::now(),
character,
- position,
+ movement: MovementBase {
+ position: self.data.chef_spawn,
+ facing: Vec2::X,
+ rotation: 0.,
+ velocity: Vec2::ZERO,
+ boosting: false,
+ stamina: 0.,
+ },
+ last_position_update: Instant::now(),
+ boost: false,
+ direction: Vec2::ZERO,
communicate_persist: None,
interacting: None,
name: name.clone(),
@@ -282,8 +312,11 @@ impl Game {
.players
.remove(&player)
.ok_or(anyhow!("player does not exist"))?;
+
+ self.players_spatial_index.remove_entry(player);
+
if let Some(item) = p.item {
- let pos = p.position.floor().as_ivec2();
+ let pos = p.movement.position.floor().as_ivec2();
if let Some(tile) = self.tiles.get_mut(&pos) {
if tile.item.is_none() {
self.packet_out.push_back(PacketC::SetItem {
@@ -297,37 +330,25 @@ impl Game {
self.packet_out
.push_back(PacketC::RemovePlayer { id: player })
}
- PacketS::Position { pos, rot, boosting } => {
- let pid = player;
+ PacketS::Movement {
+ pos,
+ boosting,
+ direction,
+ } => {
let player = self
.players
.get_mut(&player)
.ok_or(anyhow!("player does not exist"))?;
- // let dt = player.last_position_ts.elapsed().as_secs_f32();
- // let dist = pos.distance(player.position);
- // let speed = dist / dt;
- // let interact_dist = player
- // .interacting
- // .map(|p| (p.as_vec2() + Vec2::splat(0.5)).distance(player.position))
- // .unwrap_or_default();
- // let movement_ok = speed < PLAYER_SPEED_LIMIT && dist < 1. && interact_dist < 2.;
- // if movement_ok {
- player.position = pos;
- player.last_position_ts = Instant::now();
- // }
- self.packet_out.push_back(PacketC::Position {
- player: pid,
- pos: player.position,
- rot,
- boosting,
- });
- // if !movement_ok {
- // bail!(
- // "{:?} moved to quickly. speed={speed:.02} dist={dist:.02}",
- // player.name
- // )
- // }
+ player.direction = direction;
+ player.boost = boosting;
+
+ if let Some(pos) = pos {
+ let dt = player.last_position_update.elapsed();
+ player.last_position_update += dt;
+ player.movement.position +=
+ (pos - player.movement.position).clamp_length_max(dt.as_secs_f32());
+ }
}
PacketS::Collide { player, force } => {
self.packet_out
@@ -348,7 +369,7 @@ impl Game {
};
let entpos = pos.as_vec2() + Vec2::splat(0.5);
- if edge && entpos.distance(player.position) > 2. {
+ if edge && entpos.distance(player.movement.position) > 2. {
bail!("interacting too far from player");
}
@@ -364,7 +385,7 @@ impl Game {
let other_pid = if !self.data.is_tile_interactable(tile.kind) {
self.players
.iter()
- .find(|(id, p)| **id != pid && p.position.distance(entpos) < 0.7)
+ .find(|(id, p)| **id != pid && p.movement.position.distance(entpos) < 0.7)
.map(|(&id, _)| id)
} else {
None
@@ -497,6 +518,30 @@ impl Game {
}
for (&pid, player) in &mut self.players {
+ player
+ .movement
+ .update(&self.walkable, player.direction, player.boost, dt);
+
+ self.players_spatial_index
+ .update_entry(pid, player.movement.position);
+ }
+
+ self.players_spatial_index.all(|p1, pos1| {
+ self.players_spatial_index.query(pos1, 2., |p2, _pos2| {
+ if let Some([a, b]) = self.players.get_many_mut([&p1, &p2]) {
+ a.movement.collide(&mut b.movement, dt)
+ }
+ })
+ });
+
+ for (&pid, player) in &mut self.players {
+ self.packet_out.push_back(PacketC::Position {
+ player: pid,
+ pos: player.movement.position,
+ boosting: player.movement.boosting,
+ rot: player.movement.rotation,
+ });
+
if let Some(effect) = tick_slot(dt, &self.data, None, &mut player.item) {
match effect {
TickEffect::Progress(warn) => self.packet_out.push_back(PacketC::SetProgress {
diff --git a/server/src/lib.rs b/server/src/lib.rs
index afd6f1db..0339b535 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -22,3 +22,4 @@ pub mod entity;
pub mod game;
pub mod interaction;
pub mod state;
+pub mod spatial_index;
diff --git a/server/src/main.rs b/server/src/main.rs
index 6f73851a..1cee94cf 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -207,7 +207,7 @@ async fn run() -> anyhow::Result<()> {
if matches!(
packet,
- PacketS::Position { .. } | PacketS::ReplayTick { .. }
+ PacketS::Movement { .. } | PacketS::ReplayTick { .. }
) {
trace!("<- {id:?} {packet:?}");
} else {
diff --git a/server/src/spatial_index.rs b/server/src/spatial_index.rs
new file mode 100644
index 00000000..4395f0f5
--- /dev/null
+++ b/server/src/spatial_index.rs
@@ -0,0 +1,31 @@
+use hurrycurry_protocol::glam::Vec2;
+use std::{collections::HashMap, hash::Hash};
+
+// TODO stub implementation. please implement
+pub struct SpatialIndex<T> {
+ entries: HashMap<T, Vec2>,
+}
+
+impl<T: Eq + Hash + Copy> SpatialIndex<T> {
+ pub fn update_entry(&mut self, id: T, position: Vec2) {
+ self.entries.insert(id, position);
+ }
+ pub fn remove_entry(&mut self, id: T) {
+ self.entries.remove(&id);
+ }
+ pub fn all(&self, mut cb: impl FnMut(T, Vec2)) {
+ for (&e, &pos) in &self.entries {
+ cb(e, pos)
+ }
+ }
+ pub fn query(&self, _position: Vec2, _radius: f32, cb: impl FnMut(T, Vec2)) {
+ self.all(cb)
+ }
+}
+impl<T> Default for SpatialIndex<T> {
+ fn default() -> Self {
+ Self {
+ entries: Default::default(),
+ }
+ }
+}
diff --git a/test-client/index.html b/test-client/index.html
index 5b0fb206..dfabbf59 100644
--- a/test-client/index.html
+++ b/test-client/index.html
@@ -20,7 +20,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Hurry Curry - Test Client</title>
+ <title>Hurry Curry! Test Client</title>
<script src="./main.js" type="module"></script>
<style>
body {
diff --git a/test-client/main.ts b/test-client/main.ts
index 30e67f67..d56cf7e6 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -17,7 +17,7 @@
*/
/// <reference lib="dom" />
-import { MovementBase, update_movement } from "./movement.ts";
+import { MovementBase, collide_player_player, update_movement } from "./movement.ts";
import { Gamedata, ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts";
import { V2, lerp_exp_v2_mut, normalize, lerp_exp } from "./util.ts";
import { draw_ingame, draw_wait } from "./visual.ts";
@@ -76,6 +76,7 @@ export interface PlayerData extends MovementBase {
id: number,
name: string,
item?: ItemData,
+ direction: V2,
character: number,
anim_position: V2,
message?: MessageData,
@@ -145,6 +146,7 @@ function packet(p: PacketC) {
rot: 0,
facing: { x: 0, y: 1 },
vel: { x: 0, y: 0 },
+ direction: { x: 0, y: 0 },
stamina: 0,
boosting: false,
})
@@ -294,7 +296,7 @@ function set_interact(edge: boolean) {
function tick_update() {
const p = players.get(my_id)
if (!p) return
- send({ type: "position", pos: [p.position.x, p.position.y], rot: p.rot, boosting: p.boosting })
+ send({ type: "movement", pos: [p.position.x, p.position.y], direction: [p.direction.x, p.direction.y], boosting: p.boosting })
}
function frame_update(dt: number) {
@@ -303,12 +305,17 @@ function frame_update(dt: number) {
if (time_remaining != null) time_remaining -= dt
- const input = normalize({
+ const direction = normalize({
x: (+keys_down.has(KEY_RIGHT) - +keys_down.has(KEY_LEFT)),
y: (+keys_down.has(KEY_DOWN) - +keys_down.has(KEY_UP))
})
- if (interacting) input.x *= 0, input.y *= 0
- update_movement(p, dt, input, keys_down.has("KeyK"))
+ if (interacting) direction.x *= 0, direction.y *= 0
+ p.direction = direction
+ update_movement(p, dt, direction, keys_down.has("KeyK"))
+
+ for (const [_, a] of players)
+ for (const [_, b] of players)
+ collide_player_player(a, b, dt)
const update_item = (item: ItemData) => {
if (item.tracking) lerp_exp_v2_mut(item, item.tracking, dt * 10.)
diff --git a/test-client/movement.ts b/test-client/movement.ts
index 9102d7c2..1bbb9569 100644
--- a/test-client/movement.ts
+++ b/test-client/movement.ts
@@ -17,7 +17,7 @@
*/
import { data } from "./main.ts";
-import { tiles, players } from "./main.ts";
+import { tiles } from "./main.ts";
import { V2, normalize, length, sub_v2, lerp_exp_v2_mut } from "./util.ts";
export const PLAYER_SIZE = 0.4
@@ -36,24 +36,23 @@ export interface MovementBase {
stamina: number
}
-export function update_movement(p: MovementBase, dt: number, input: V2, boost: boolean) {
- if (length(input) > 0.1) lerp_exp_v2_mut(p.facing, input, dt * 10.)
+export function update_movement(p: MovementBase, dt: number, direction: V2, boost: boolean) {
+ if (length(direction) > 0.1) lerp_exp_v2_mut(p.facing, direction, dt * 10.)
p.rot = Math.atan2(p.facing.x, p.facing.y)
- boost &&= length(input) > 0.1
+ boost &&= length(direction) > 0.1
p.boosting = boost && (p.boosting || p.stamina >= 1) && p.stamina > 0
if (p.boosting) p.stamina -= dt / BOOST_DURATION
else p.stamina += dt / BOOST_RESTORE
p.stamina = Math.max(Math.min(p.stamina, 1), 0)
const speed = PLAYER_SPEED * (p.boosting ? BOOST_FACTOR : 1)
- p.vel.x += input.x * dt * speed
- p.vel.y += input.y * dt * speed
+ p.vel.x += direction.x * dt * speed
+ p.vel.y += direction.y * dt * speed
p.position.x += p.vel.x * dt
p.position.y += p.vel.y * dt
collide_player(p, dt)
lerp_exp_v2_mut(p.vel, { x: 0, y: 0 }, dt * PLAYER_FRICTION)
}
-
-function collide_player(p: MovementBase, dt: number) {
+function collide_player(p: MovementBase, _dt: number) {
for (let xo = -1; xo <= 1; xo++) {
for (let yo = -1; yo <= 1; yo++) {
const x = Math.floor(p.position.x) + xo
@@ -79,17 +78,16 @@ function collide_player(p: MovementBase, dt: number) {
p.vel.y -= grad_y * vdotn
}
}
-
- for (const [_, player] of players) {
- const diff = sub_v2(p.position, player.position)
- const d = length(diff)
- if (d < 0.01) continue
- if (d >= PLAYER_SIZE * 2) continue
- const norm = normalize(diff);
- const f = 100 / (1 + d)
- p.vel.x += norm.x * f * dt
- p.vel.y += norm.y * f * dt
- }
+}
+export function collide_player_player(a: MovementBase, b: MovementBase, dt: number) {
+ const diff = sub_v2(a.position, b.position)
+ const d = length(diff)
+ if (d < 0.01) return
+ if (d >= PLAYER_SIZE * 2) return
+ const norm = normalize(diff);
+ const f = 100 / (1 + d)
+ a.vel.x += norm.x * f * dt
+ a.vel.y += norm.y * f * dt
}
export function aabb_point_distance(
diff --git a/test-client/protocol.ts b/test-client/protocol.ts
index f8241854..2a0f2b87 100644
--- a/test-client/protocol.ts
+++ b/test-client/protocol.ts
@@ -38,7 +38,7 @@ export interface Gamedata {
export type PacketS =
{ type: "join", name: string, character: number } // Spawns your character. Dont send it to spectate.
| { type: "leave" } // Despawns your character
- | { type: "position", pos: Vec2, rot: number, boosting: boolean } // Update your position and rotation in radians (0 is -y)
+ | { type: "movement", pos: Vec2, direction: Vec2, boosting: boolean }
| { type: "interact", pos?: Vec2 } // Interact with some tile. pos is a position when pressing and null when releasing interact button
| { type: "communicate", message?: Message, persist: boolean } // Send a message
| { type: "collide", player: PlayerID, force: Vec2 } // Apply force to another player as a result of a collision