From 30280fe01d0e80cfe0420eba2d9809d845c01ab0 Mon Sep 17 00:00:00 2001 From: core Date: Tue, 11 Apr 2023 19:42:33 -0400 Subject: [PATCH] animation framework --- client/src/lib.rs | 27 ++++++++++++++++++++------- client/src/rendering/mod.rs | 1 + client/src/rendering/renderer.rs | 19 ++++++++++++------- web/play.html | 21 +++++++++++++++++---- web/static/css/play.css | 4 ++++ 5 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 web/static/css/play.css diff --git a/client/src/lib.rs b/client/src/lib.rs index bb36c67995f2bfedc3a58c53e0bfc33fbee5458f..c3dad3ff88fd5cb7796894d4e29ed6ad77cb8038 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -2,11 +2,11 @@ use std::error::Error; use std::str::FromStr; use futures::stream::{SplitSink, SplitStream}; -use futures::StreamExt; +use futures::{StreamExt, TryFutureExt}; use log::{debug, error, info, Level, trace, warn}; use wasm_bindgen::prelude::*; use ws_stream_wasm::{WsErr, WsMessage, WsMeta, WsStream}; -use starkingdoms_protocol::{Planet, State}; +use starkingdoms_protocol::{ProtocolPlanet, State}; use starkingdoms_protocol::PROTOCOL_VERSION; use starkingdoms_protocol::MessageS2C; use starkingdoms_protocol::MessageC2S; @@ -20,6 +20,7 @@ use futures::FutureExt; use wasm_bindgen_futures::JsFuture; use web_sys::{Window}; use starkingdoms_protocol::GoodbyeReason::PingPongTimeout; +use crate::rendering::Renderer; use crate::rendering::renderer::WebRenderer; use crate::textures::loader::TextureLoader; use crate::textures::{TextureManager, TextureSize}; @@ -39,7 +40,7 @@ extern { #[derive(Debug)] pub struct Client { pub client_data: Option, - pub planets: Vec, + pub planets: Vec, pub x: f64, pub y: f64 } @@ -50,7 +51,8 @@ pub struct ClientData { pub tx: SplitSink, pub rx: SplitStream, pub pong_timeout: u64, - pub textures: TextureLoader + pub textures: TextureLoader, + pub renderer: WebRenderer } pub const PONG_MAX_TIMEOUT: u64 = 5; @@ -81,7 +83,7 @@ pub async fn rust_init(gateway: &str, username: &str, texture_size: &str) -> Res let textures = TextureLoader::load(TextureSize::from_str(texture_size).unwrap()).map_err(|e| e.to_string())?; - match main(gateway, username, 1, textures).await { + match main(gateway, username, 1, textures, WebRenderer::get("canvas").await.unwrap()).await { Ok(c) => c, Err(e) => { error!("Error initializing gateway client: {}", e); @@ -95,7 +97,7 @@ pub async fn rust_init(gateway: &str, username: &str, texture_size: &str) -> Res } #[async_recursion(?Send)] -pub async fn main(gateway: &str, username: &str, backoff: i32, textures: TextureLoader) -> Result<(), Box> { +pub async fn main(gateway: &str, username: &str, backoff: i32, textures: TextureLoader, renderer: WebRenderer) -> Result<(), Box> { if backoff != 1 { info!("Backing off connection: waiting {} seconds", backoff * backoff); wait_for(sleep(backoff * backoff * 1000)).await; @@ -119,7 +121,7 @@ pub async fn main(gateway: &str, username: &str, backoff: i32, textures: Texture Err(e) => { return match e { WsErr::ConnectionFailed { .. } => { - main(gateway, username, backoff + 1, textures).await + main(gateway, username, backoff + 1, textures, renderer).await }, _ => { Err(e.into()) @@ -136,6 +138,7 @@ pub async fn main(gateway: &str, username: &str, backoff: i32, textures: Texture rx, pong_timeout: (js_sys::Date::now() as u64 / 1000) + 5, textures, + renderer }; trace!("Split stream, handshaking with server"); @@ -286,4 +289,14 @@ pub fn get_texture(texture_id: &str) -> Option { } else { None } +} + +#[wasm_bindgen] +pub async fn render_frame(delta: f64) -> Result<(), JsError> { + let client = CLIENT.read().unwrap(); + if let Some(client_data) = &client.client_data { + Ok(client_data.renderer.render_frame(delta).await.map_err(|e| JsError::new(&format!("{}", e)))?) + } else { + Err(JsError::new("Client not yet initialized")) + } } \ No newline at end of file diff --git a/client/src/rendering/mod.rs b/client/src/rendering/mod.rs index 13b95d4d3ff8650ddb128fcfcd157198403d15a1..d53c3c98e09d951cf7c0c692e84b5eeef7376ec5 100644 --- a/client/src/rendering/mod.rs +++ b/client/src/rendering/mod.rs @@ -6,4 +6,5 @@ pub mod renderer; #[async_trait] pub trait Renderer { async fn get(canvas_element_id: &str) -> Result> where Self: Sized; + async fn render_frame(&self, time_delta_ms: f64) -> Result<(), Box>; } \ No newline at end of file diff --git a/client/src/rendering/renderer.rs b/client/src/rendering/renderer.rs index 7d410d5c241b086d253a2545c56e62fa0acd0978..e287fe417a90f47993703049b556c51cac724d5f 100644 --- a/client/src/rendering/renderer.rs +++ b/client/src/rendering/renderer.rs @@ -4,22 +4,27 @@ use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement}; use crate::rendering::Renderer; use wasm_bindgen::JsCast; +#[derive(Debug)] pub struct WebRenderer { - canvas: HtmlCanvasElement, - context: CanvasRenderingContext2d + canvas_element_id: String } #[async_trait] impl Renderer for WebRenderer { async fn get(canvas_element_id: &str) -> Result> { + Ok(Self { + canvas_element_id: canvas_element_id.to_string() + }) + } + + async fn render_frame(&self, time_delta_ms: f64) -> Result<(), Box> { + // TODO + // time_delta_ms is the delta, in ms, from when the last render_frame was called by the browser let window = web_sys::window().ok_or("window needs to exist")?; let document = window.document().ok_or("window.document needs to exist")?; - let canvas_element = document.get_element_by_id(canvas_element_id).ok_or("canvas element does not exist")?; + let canvas_element = document.get_element_by_id(&self.canvas_element_id).ok_or("canvas element does not exist")?; let typed_canvas_element: HtmlCanvasElement = canvas_element.dyn_into::().map_err(|_| ()).unwrap(); let context = typed_canvas_element.get_context("2d").unwrap().unwrap().dyn_into::().unwrap(); - Ok(Self { - canvas: typed_canvas_element, - context - }) + Ok(()) } } \ No newline at end of file diff --git a/web/play.html b/web/play.html index 335cb223dae031e36cdf75a7821a143b021e8aba..3fb48c57979f1dcb74df312d07373ec227bc3c19 100644 --- a/web/play.html +++ b/web/play.html @@ -2,10 +2,8 @@ StarKingdoms.TK - - + - @@ -27,7 +25,7 @@