pellest/src/island_client.ml

178 lines
5.1 KiB
OCaml
Raw Normal View History

open Brr
2022-12-11 18:58:56 +01:00
open Brr_io
open Brr_canvas
2022-12-11 18:58:56 +01:00
open Shared
module G = struct
include Brr.G
let request_animation_frame f =
(ignore : int -> unit) @@ Brr.G.request_animation_frame f
end
2022-12-07 00:10:41 +01:00
let get_el id =
match Document.find_el_by_id G.document (Jstr.of_string id) with
| None -> Log.err "could not find element with id `%s`" id
2022-12-07 00:10:41 +01:00
| Some el -> el
2022-12-06 02:31:33 +01:00
let tile_size = 40
let width = 875
2022-12-06 02:31:33 +01:00
let height = 675
2022-12-06 02:31:33 +01:00
2022-12-07 00:10:41 +01:00
let canvas =
let el = get_el "canvas" in
Canvas.of_el el
2022-12-06 02:31:33 +01:00
2022-12-07 00:10:41 +01:00
let context = C2d.get_context canvas
2022-12-06 02:31:33 +01:00
let tiles_per_w =
let n = width / tile_size in
if n mod 2 = 0 then n - 1 else n
2022-12-06 02:31:33 +01:00
let tiles_per_h =
let n = height / tile_size in
if n mod 2 = 0 then n - 1 else n
2022-12-06 02:31:33 +01:00
let orig_x = (width - (tiles_per_w * tile_size)) / 2
let orig_y = (height - (tiles_per_h * tile_size)) / 2
2022-12-07 00:10:41 +01:00
let grass = C2d.image_src_of_el (get_el "grass")
2022-12-06 02:31:33 +01:00
2022-12-08 04:08:27 +01:00
let papy_left = C2d.image_src_of_el (get_el "papy_left")
let papy_right = C2d.image_src_of_el (get_el "papy_right")
let papy_down = C2d.image_src_of_el (get_el "papy_down")
let papy_up = C2d.image_src_of_el (get_el "papy_up")
2022-12-06 03:08:30 +01:00
2022-12-07 00:10:41 +01:00
let water = C2d.image_src_of_el (get_el "water")
2022-12-06 03:08:30 +01:00
let draw_canvas =
2022-12-08 04:08:27 +01:00
let papy_x = float_of_int (width - tile_size) /. 2. in
let papy_y = (float_of_int height /. 2.) -. (float_of_int tile_size *. 1.5) in
2022-12-26 02:06:13 +01:00
fun state ->
let open State in
2022-12-08 04:08:27 +01:00
for x = 0 to tiles_per_w - 1 do
let map_x = x + state.player_pos.x - (tiles_per_w / 2) in
2022-12-08 04:08:27 +01:00
let tile_x = float_of_int ((x * tile_size) + orig_x) in
for y = 0 to tiles_per_h - 1 do
let map_y = y + state.player_pos.y - (tiles_per_h / 2) in
2022-12-08 04:08:27 +01:00
let tile_y = float_of_int ((y * tile_size) + orig_y) in
let tile_img =
2022-12-26 02:06:13 +01:00
match Map.get_tile_kind ~x:map_x ~y:map_y state.map with
2022-12-08 04:08:27 +01:00
| Grass -> grass
| Water -> water
| Black -> water
in
C2d.draw_image context tile_img ~x:tile_x ~y:tile_y
done
done;
let papy =
match state.player_pos.dir with
2022-12-08 04:08:27 +01:00
| Left -> papy_left
| Right -> papy_right
| Down -> papy_down
| Up -> papy_up
in
C2d.draw_image context papy ~x:papy_x ~y:papy_y
let draw_topbar state =
let mana_lvl = Jv.get Jv.global "mana_lvl" in
Jv.set mana_lvl "innerHTML"
(Jv.of_string @@ string_of_int state.Shared.State.mana)
2022-12-26 02:06:13 +01:00
(* queue for action to be done *)
let input_queue = Queue.create ()
(* queue for action' to apply to client state *)
let to_apply_queue : State.action' Queue.t = Queue.create ()
let send_action state action =
match State.check_action state action with
| Error e ->
(* TODO: display this in the window *)
Log.debug "invalid action: %s@\n" e
| Ok Look_at_the_sky -> ()
| Ok _ ->
Log.debug "sending action %a to server@\n" State.pp_action action;
Ws_client.send (Network.Action_msg action)
2022-12-26 02:06:13 +01:00
let kb_handler ev =
let open State in
let act =
match ev |> Ev.as_type |> Ev.Keyboard.code |> Jstr.to_string with
| "KeyW" | "ArrowUp" -> Move Up
| "KeyA" | "ArrowLeft" -> Move Left
| "KeyS" | "ArrowDown" -> Move Down
| "KeyD" | "ArrowRight" -> Move Right
| "KeyM" -> Meditate
| _s -> Do_nothing
in
Queue.add act input_queue
2022-12-07 23:14:11 +01:00
let render state =
draw_canvas state;
draw_topbar state
let rec game_loop state last_auto_update timestamp =
render state;
let should_auto_update =
timestamp -. last_auto_update
>= Time.ms_to_float (Time.s_to_ms State.auto_update_rate)
in
2023-01-07 23:15:03 +01:00
let last_auto_update =
if should_auto_update then timestamp else last_auto_update
in
let state =
(* apply queue of actions *)
2022-12-26 02:06:13 +01:00
let state = Queue.fold State.perform_action state to_apply_queue in
Queue.clear to_apply_queue;
(* send input action to server *)
Queue.iter (send_action state) input_queue;
Queue.clear input_queue;
(* state auto update *)
if should_auto_update then State.auto_update state else state
2022-12-26 02:06:13 +01:00
in
G.request_animation_frame (game_loop state last_auto_update)
2022-12-06 03:30:16 +01:00
let () =
2022-12-08 04:08:27 +01:00
(* init canvas *)
Canvas.set_w canvas width;
Canvas.set_h canvas height;
C2d.set_fill_style context (C2d.color (Jstr.v "#FF1188"));
C2d.fill_rect context ~x:0. ~y:0. ~w:(float_of_int width)
~h:(float_of_int height);
2022-12-11 18:58:56 +01:00
(* get state from server*)
let initial_state_fut = Ev.next Message.Ev.message Ws_client.ws_target in
2022-12-26 02:06:13 +01:00
(* attach message listener to update state *)
Ws_client.on_update_state_message (fun server_msg ->
match server_msg with
| Full_state _state ->
(* TODO reset state to received state *)
Log.debug "received `Full_state` message@\n"
2022-12-26 02:06:13 +01:00
| Update_result res -> (
match res with
| Error e -> Log.debug "received update result error: %s@\n" e
2022-12-26 02:06:13 +01:00
| Ok action' -> Queue.add action' to_apply_queue ) );
(* bind keys *)
let _e : Ev.listener =
Ev.listen Ev.keydown kb_handler (Window.as_target G.window)
in
2022-12-11 18:58:56 +01:00
Fut.await initial_state_fut (fun msg ->
2022-12-26 02:06:13 +01:00
match Ws_client.to_server_msg msg with
| Update_result _res_msg ->
Log.err
2022-12-26 02:06:13 +01:00
"invalid first server message received; received Update expected \
Full_state"
| Full_state state ->
(* start game *)
G.request_animation_frame (game_loop state 0.) )