aboutsummaryrefslogtreecommitdiff
path: root/light-client/src/game.rs
diff options
context:
space:
mode:
Diffstat (limited to 'light-client/src/game.rs')
-rw-r--r--light-client/src/game.rs155
1 files changed, 135 insertions, 20 deletions
diff --git a/light-client/src/game.rs b/light-client/src/game.rs
index cf265344..b35a15d7 100644
--- a/light-client/src/game.rs
+++ b/light-client/src/game.rs
@@ -15,31 +15,47 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::{sprite_renderer::SpriteRenderer, tilemap::Tilemap};
+use crate::{
+ sprite_renderer::{SpriteRect, SpriteRenderer},
+ tilemap::Tilemap,
+};
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
- PacketC, PlayerID, TileIndex,
+ movement::MovementBase,
+ ClientGamedata, ItemIndex, ItemLocation, PacketC, PacketS, PlayerID, TileIndex,
};
use log::{info, warn};
-use sdl2::rect::FRect;
-use std::collections::HashMap;
+use sdl2::{
+ keyboard::{KeyboardState, Scancode},
+ rect::{FRect, Rect},
+};
+use std::collections::{HashMap, HashSet, VecDeque};
pub struct Game {
+ data: ClientGamedata,
tiles: HashMap<IVec2, Tile>,
tilemap: Tilemap,
+ collision_map: HashSet<IVec2>,
players: HashMap<PlayerID, Player>,
my_id: PlayerID,
+
+ item_sprites: Vec<SpriteRect>,
+ movement_send_cooldown: f32,
}
pub struct Tile {
kind: TileIndex,
+ item: Option<Item>,
}
pub struct Player {
+ movement: MovementBase,
+ item: Option<Item>,
+ name: String,
character: i32,
+}
+pub struct Item {
position: Vec2,
- name: String,
- boosting: bool,
- rot: f32,
+ kind: ItemIndex,
}
impl Game {
@@ -49,6 +65,10 @@ impl Game {
players: HashMap::new(),
tilemap: Tilemap::default(),
my_id: PlayerID(0),
+ data: ClientGamedata::default(),
+ collision_map: HashSet::new(),
+ movement_send_cooldown: 0.,
+ item_sprites: Vec::new(),
}
}
@@ -57,6 +77,20 @@ impl Game {
PacketC::Init { id } => self.my_id = id,
PacketC::Data { data } => {
self.tilemap.init(&data.tile_names, renderer.metadata());
+ self.item_sprites = data
+ .item_names
+ .iter()
+ .map(|name| {
+ SpriteRect::new(
+ renderer
+ .metadata()
+ .get(&format!("{name}:a"))
+ .copied()
+ .unwrap_or(Rect::new(0, 0, 32, 24)),
+ )
+ })
+ .collect();
+ self.data = data;
}
PacketC::UpdateMap {
tile,
@@ -64,9 +98,15 @@ impl Game {
neighbors,
} => {
if let Some(kind) = kind {
- self.tiles.insert(tile, Tile { kind });
+ self.tiles.insert(tile, Tile { kind, item: None });
+ if self.data.tile_collide[kind.0] {
+ self.collision_map.remove(&tile);
+ } else {
+ self.collision_map.insert(tile);
+ }
} else {
self.tiles.remove(&tile);
+ self.collision_map.remove(&tile);
}
self.tilemap.set(tile, kind, neighbors);
}
@@ -81,10 +121,16 @@ impl Game {
id,
Player {
character,
- position,
name,
- boosting: false,
- rot: 0.,
+ item: None,
+ movement: MovementBase {
+ position,
+ facing: Vec2::X,
+ rotation: 0.,
+ velocity: Vec2::ZERO,
+ boosting: false,
+ stamina: 0.,
+ },
},
);
}
@@ -98,14 +144,21 @@ impl Game {
rot,
boosting,
} => {
- if let Some(p) = self.players.get_mut(&player) {
- p.position = pos;
- p.rot = rot;
- p.boosting = boosting;
+ if player != self.my_id {
+ if let Some(p) = self.players.get_mut(&player) {
+ p.movement.position = pos;
+ p.movement.rotation = rot;
+ p.movement.boosting = boosting;
+ }
}
}
- PacketC::MoveItem { from, to } => (),
- PacketC::SetItem { location, item } => (),
+ PacketC::MoveItem { from, to } => *self.get_item(to) = self.get_item(from).take(),
+ PacketC::SetItem { location, item } => {
+ *self.get_item(location) = item.map(|kind| Item {
+ kind,
+ position: Vec2::ZERO,
+ })
+ }
PacketC::SetProgress {
item,
progress,
@@ -132,18 +185,80 @@ impl Game {
}
}
+ pub fn get_item(&mut self, location: ItemLocation) -> &mut Option<Item> {
+ match location {
+ ItemLocation::Tile(pos) => &mut self.tiles.get_mut(&pos).unwrap().item,
+ ItemLocation::Player(pid) => &mut self.players.get_mut(&pid).unwrap().item,
+ }
+ }
+
+ pub fn tick(&mut self, dt: f32, keyboard: &KeyboardState, packet_out: &mut VecDeque<PacketS>) {
+ let direction = IVec2::new(
+ keyboard.is_scancode_pressed(Scancode::D) as i32
+ - keyboard.is_scancode_pressed(Scancode::A) as i32,
+ keyboard.is_scancode_pressed(Scancode::S) as i32
+ - keyboard.is_scancode_pressed(Scancode::W) as i32,
+ )
+ .as_vec2();
+ let boost = keyboard.is_scancode_pressed(Scancode::K);
+ let interact = keyboard.is_scancode_pressed(Scancode::Space)
+ | keyboard.is_scancode_pressed(Scancode::J);
+
+ self.movement_send_cooldown -= dt;
+ let send_movement = self.movement_send_cooldown < 0.;
+ if send_movement {
+ self.movement_send_cooldown += 0.04
+ }
+
+ for (pid, player) in &mut self.players {
+ if *pid == self.my_id {
+ let movement_packet =
+ player
+ .movement
+ .update(&self.collision_map, direction, boost, dt);
+
+ if send_movement {
+ packet_out.push_back(movement_packet);
+ }
+ }
+ if let Some(item) = &mut player.item {
+ item.position = player.movement.position
+ }
+ }
+ for (pos, tile) in &mut self.tiles {
+ if let Some(item) = &mut tile.item {
+ item.position = pos.as_vec2() + 0.5
+ }
+ }
+ }
+
pub fn draw(&self, ctx: &mut SpriteRenderer) {
self.tilemap.draw(ctx);
for p in self.players.values() {
let src = ctx.misc_textures().player;
let dst = FRect::new(
- p.position.x - src.width() as f32 / 32. / 2.,
- p.position.y + 1. - src.height() as f32 / 24.,
+ p.movement.position.x - src.width() as f32 / 32. / 2.,
+ p.movement.position.y + 0.3 - src.height() as f32 / 24.,
src.width() as f32 / 32.,
src.height() as f32 / 24.,
);
- ctx.draw(((dst.y + dst.h + 1.) * 24.) as i32, src, dst);
+ ctx.draw(dst.y + dst.h + 1., src, dst);
+ if let Some(item) = &p.item {
+ item.draw(ctx, &self.item_sprites)
+ }
+ }
+ for tile in self.tiles.values() {
+ if let Some(item) = &tile.item {
+ item.draw(ctx, &self.item_sprites)
+ }
}
}
}
+
+impl Item {
+ pub fn draw(&self, ctx: &mut SpriteRenderer, item_sprites: &[SpriteRect]) {
+ eprintln!("item {} at {}", self.kind.0, self.position);
+ item_sprites[self.kind.0].draw_at(ctx, self.position)
+ }
+}