This commit is contained in:
Thomas Forgione 2022-08-02 14:32:52 +02:00
parent fe1a0537b5
commit 27bcd3a5d2
2 changed files with 136 additions and 152 deletions

View File

@ -45,69 +45,25 @@ pub struct Engine {
/// ///
/// We need Rc<RefCell> in order to deal with events. /// We need Rc<RefCell> in order to deal with events.
pub inner: Rc<RefCell<InnerEngine>>, pub inner: Rc<RefCell<InnerEngine>>,
/// The web page window.
pub window: Rc<web_sys::Window>,
/// The web page document.
pub document: Rc<web_sys::Document>,
/// The canvas rendering context.
///
/// We keep a reference so that we can easily render things.
pub context: Rc<web_sys::CanvasRenderingContext2d>,
/// The performance object.
pub performance: Rc<web_sys::Performance>,
} }
impl Engine { impl Engine {
/// Creates a new engine. /// Creates a new engine.
pub fn new() -> Result<Engine> { pub fn new() -> Result<Engine> {
let window = unwrap!(web_sys::window()); let inner = Rc::new(RefCell::new(InnerEngine::new()?));
let document = unwrap!(window.document());
let performance = unwrap!(window.performance());
let canvas = unwrap!(document.get_element_by_id("canvas"));
let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::<web_sys::HtmlCanvasElement>()?;
canvas.set_width(1920); // let clone = inner.clone();
canvas.set_height(1080); // let cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::GamepadEvent| {
// let mut inner = clone.borrow_mut();
// inner.add_gamepad(&event);
// });
let context = // (*window)
unwrap!(canvas.get_context("2d")?).dyn_into::<web_sys::CanvasRenderingContext2d>()?; // .add_event_listener_with_callback("gamepadconnected", cb.as_ref().unchecked_ref())?;
let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap(); // cb.forget();
let mut scene = Scene::from_map(map);
let character = Character::new(); Ok(Engine { inner })
scene.add(character);
let inner = InnerEngine::new(&document, &performance, scene)?;
let inner = Rc::new(RefCell::new(inner));
let window = Rc::new(window);
let document = Rc::new(document);
let performance = Rc::new(performance);
let context = Rc::new(context);
let clone = inner.clone();
let cb = Closure::<dyn FnMut(_)>::new(move |event: web_sys::GamepadEvent| {
let mut inner = clone.borrow_mut();
inner.add_gamepad(&event);
});
(*window)
.add_event_listener_with_callback("gamepadconnected", cb.as_ref().unchecked_ref())?;
cb.forget();
Ok(Engine {
inner,
window,
document,
performance,
context,
})
} }
/// Starts the engine. /// Starts the engine.
@ -119,7 +75,10 @@ impl Engine {
} }
}); });
(*self.window).request_animation_frame(cb.as_ref().unchecked_ref())?; let inner = self.inner.borrow_mut();
inner
.window
.request_animation_frame(cb.as_ref().unchecked_ref())?;
cb.forget(); cb.forget();
@ -128,11 +87,13 @@ impl Engine {
/// Launches a loop of the engine, and schedules the next one. /// Launches a loop of the engine, and schedules the next one.
pub fn run(&self) -> Result<()> { pub fn run(&self) -> Result<()> {
let mut inner = self.inner.borrow_mut();
// Perform update // Perform update
self.update()?; inner.update()?;
// Perform render // Perform render
self.render()?; inner.render()?;
// Schedule next render // Schedule next render
let clone = self.clone(); let clone = self.clone();
@ -142,94 +103,14 @@ impl Engine {
} }
}); });
(*self.window).request_animation_frame(cb.as_ref().unchecked_ref())?; inner
.window
.request_animation_frame(cb.as_ref().unchecked_ref())?;
cb.forget(); cb.forget();
Ok(()) Ok(())
} }
/// Triggers the update of the model of the engine.
pub fn update(&self) -> Result<()> {
let mut inner = self.inner.borrow_mut();
// Manage the physics
let now = now(&self.performance);
let duration = unwrap!(now.duration_since(inner.after_loop).ok());
inner.after_loop = now;
if self.document.has_focus()? {
// Manage events
// while let Some(event) = inner.keyboard.pop() {
// inner.scene.manage_action(&action);
// }
// let keyboard = inner.keyboard.clone();
// if inner.scene.update(now, duration) == State::Finished {
// let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap();
// let mut scene = Scene::from_map(map);
// let character = Character::with_controls(Controls::default_keyboard());
// scene.add(character);
// inner.scene = scene;
// }
}
Ok(())
}
/// Draw a drawable.
pub fn draw<D: Drawable>(&self, drawable: &D, view: Bbox) -> Result<()> {
let inner = self.inner.borrow();
let image = inner.textures.get(drawable.texture());
let source = drawable.texture_rect(inner.after_loop);
let mut dest = source.clone();
dest.position = drawable.position() - view.position;
dest.position.x *= 1920.0 / view.size.x;
dest.position.y *= 1080.0 / view.size.y;
dest.size.x *= 1920.0 / view.size.x;
dest.size.y *= 1080.0 / view.size.y;
image.render(source, dest, &self.context)?;
Ok(())
}
/// Performs the rendering of the engine.
pub fn render(&self) -> Result<()> {
let inner = self.inner.borrow();
let view = inner.scene.view().unwrap(); // TODO remove this unwrap
// Clear render
self.context.clear_rect(0.0, 0.0, 1920.0, 1080.0);
self.context
.set_fill_style(&JsValue::from_str("rgb(135, 206, 235)"));
self.context.fill_rect(0.0, 0.0, 1920.0, 1080.0);
// Draw the scene
let map = inner.scene.map();
let rows = map.rows();
let cols = map.cols();
for i in 0..rows {
for j in 0..cols {
let tile = map.at(i, j);
if tile.graphic.is_visible() {
self.draw(&tile, view)?;
}
}
}
// Draw characters
for c in inner.scene.characters() {
if true {
self.draw(c, view)?;
}
}
Ok(())
}
} }
/// The data contained in our engine. /// The data contained in our engine.
@ -245,31 +126,131 @@ pub struct InnerEngine {
/// The input manager. /// The input manager.
pub inputs: InputManager, pub inputs: InputManager,
/// The web page window.
pub window: web_sys::Window,
/// The web page document.
pub document: web_sys::Document,
/// The canvas rendering context.
///
/// We keep a reference so that we can easily render things.
pub context: web_sys::CanvasRenderingContext2d,
/// The performance object.
pub performance: web_sys::Performance,
} }
impl InnerEngine { impl InnerEngine {
/// Initializes the engine. /// Initializes the engine.
pub fn new( pub fn new() -> Result<InnerEngine> {
document: &web_sys::Document, let window = unwrap!(web_sys::window());
performance: &web_sys::Performance, let document = unwrap!(window.document());
scene: Scene, let performance = unwrap!(window.performance());
) -> Result<InnerEngine> { let canvas = unwrap!(document.get_element_by_id("canvas"));
let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::<web_sys::HtmlCanvasElement>()?;
canvas.set_width(1920);
canvas.set_height(1080);
let context =
unwrap!(canvas.get_context("2d")?).dyn_into::<web_sys::CanvasRenderingContext2d>()?;
let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap();
let mut scene = Scene::from_map(map);
let character = Character::new();
scene.add(character);
Ok(InnerEngine { Ok(InnerEngine {
scene, scene,
after_loop: now(&performance), after_loop: now(&performance),
textures: TextureManager::new()?, textures: TextureManager::new()?,
inputs: InputManager::new(), inputs: InputManager::new(),
window,
document,
context,
performance,
}) })
} }
/// Adds a gamepad. /// Triggers the update of the model of the engine.
pub fn add_gamepad(&mut self, gamepad: &web_sys::GamepadEvent) { pub fn update(&mut self) -> Result<()> {
// let gamepad = GamepadMap::from_gamepad(gamepad.gamepad().unwrap()); // Manage the physics
// let clone = gamepad.clone(); let now = now(&self.performance);
// self.gamepads.push(clone); let duration = unwrap!(now.duration_since(self.after_loop).ok());
self.after_loop = now;
// let controlable = self.scene.controlable_mut().unwrap(); if self.document.has_focus()? {
// controlable.set_controls(Some(Controls::Gamepad(gamepad))); // Manage events
// while let Some(event) = inner.keyboard.pop() {
// inner.scene.manage_action(&action);
// }
// let keyboard = inner.keyboard.clone();
if self.scene.update(now, duration) == State::Finished {
let map = Map::from_str(include_str!("../../static/levels/level1.lvl")).unwrap();
let mut scene = Scene::from_map(map);
let character = Character::new();
scene.add(character);
self.scene = scene;
}
}
Ok(())
}
/// Performs the rendering of the engine.
pub fn render(&self) -> Result<()> {
let view = self.scene.view().unwrap(); // TODO remove this unwrap
// Clear render
self.context.clear_rect(0.0, 0.0, 1920.0, 1080.0);
self.context
.set_fill_style(&JsValue::from_str("rgb(135, 206, 235)"));
self.context.fill_rect(0.0, 0.0, 1920.0, 1080.0);
// Draw the scene
let map = self.scene.map();
let rows = map.rows();
let cols = map.cols();
for i in 0..rows {
for j in 0..cols {
let tile = map.at(i, j);
if tile.graphic.is_visible() {
self.draw(&tile, view)?;
}
}
}
// Draw characters
for c in self.scene.characters() {
if true {
self.draw(c, view)?;
}
}
Ok(())
}
/// Draw a drawable.
pub fn draw<D: Drawable>(&self, drawable: &D, view: Bbox) -> Result<()> {
let image = self.textures.get(drawable.texture());
let source = drawable.texture_rect(self.after_loop);
let mut dest = source.clone();
dest.position = drawable.position() - view.position;
dest.position.x *= 1920.0 / view.size.x;
dest.position.y *= 1080.0 / view.size.y;
dest.size.x *= 1920.0 / view.size.x;
dest.size.y *= 1080.0 / view.size.y;
image.render(source, dest, &self.context)?;
Ok(())
} }
} }

View File

@ -47,6 +47,9 @@ impl Scene {
/// Returns the controlable. /// Returns the controlable.
fn controlable(&self) -> Option<&Character> { fn controlable(&self) -> Option<&Character> {
// TODO fix this
return Some(&self.characters[0]);
for character in &self.characters { for character in &self.characters {
if character.controls().is_some() { if character.controls().is_some() {
return Some(&character); return Some(&character);