mirror of
https://github.com/lisk77/comet.git
synced 2025-10-23 21:38:50 +00:00
feat: moved the ECS related functions to the App to remove unnecessary calling of the World struct inside App.
This commit is contained in:
parent
f07b829b7d
commit
ee3d0bdb9e
7 changed files with 258 additions and 81 deletions
|
|
@ -21,6 +21,7 @@ bytemuck = "1.18.0"
|
|||
chrono = "0.4.0"
|
||||
winit_input_helper = "0.16.0"
|
||||
spin_sleep = "1.2.1"
|
||||
crossbeam-channel = "0.5.14"
|
||||
|
||||
[dependencies.image]
|
||||
version = "0.24"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use std::any::{type_name, Any};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
use comet_ecs::{Component, ComponentSet, Render, Transform2D, Transform3D, World};
|
||||
use crossbeam_channel::bounded;
|
||||
use comet_ecs::{Component, ComponentSet, Entity, Render, Transform2D, Transform3D, World};
|
||||
use comet_resources::{ResourceManager, Vertex};
|
||||
use comet_renderer::renderer2d::Renderer2D;
|
||||
|
||||
|
|
@ -17,6 +19,7 @@ use comet_ecs::math::Point3;
|
|||
use comet_log::*;
|
||||
use winit::dpi::{LogicalSize, PhysicalSize};
|
||||
use winit::event_loop::ControlFlow;
|
||||
use winit::window::Fullscreen;
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
use comet_input::input_handler::InputHandler;
|
||||
use comet_input::keyboard::Key;
|
||||
|
|
@ -28,8 +31,15 @@ pub enum ApplicationType {
|
|||
App3D
|
||||
}
|
||||
|
||||
pub struct App<'a> {
|
||||
title: &'a str,
|
||||
pub enum AppMessage {
|
||||
Resize(PhysicalSize<u32>),
|
||||
Input(WinitInputHelper),
|
||||
UpdateCompleted(f32),
|
||||
Quit
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
title: String,
|
||||
icon: Option<Icon>,
|
||||
size: Option<LogicalSize<u32>>,
|
||||
clear_color: Option<LinearRgba>,
|
||||
|
|
@ -42,10 +52,10 @@ pub struct App<'a> {
|
|||
should_quit: bool
|
||||
}
|
||||
|
||||
impl<'a> App<'a> {
|
||||
impl App {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
title: "Untitled",
|
||||
title: "Untitled".to_string(),
|
||||
icon: None,
|
||||
size: None,
|
||||
clear_color: None,
|
||||
|
|
@ -59,13 +69,13 @@ impl<'a> App<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn with_title(mut self, title: &'a str) -> Self {
|
||||
self.title = title;
|
||||
pub fn with_title(mut self, title: impl Into<String>) -> Self {
|
||||
self.title = title.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_icon(mut self, path: &'a str) -> Self {
|
||||
self.icon = Some(Self::load_icon(std::path::Path::new(path)).unwrap());
|
||||
pub fn with_icon(mut self, path: impl AsRef<std::path::Path>) -> Self {
|
||||
self.icon = Self::load_icon(path.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +109,13 @@ impl<'a> App<'a> {
|
|||
}
|
||||
|
||||
fn load_icon(path: &std::path::Path) -> Option<Icon> {
|
||||
let image = image::open(path).expect("Failed to open icon image");
|
||||
let image = match image::open(path) {
|
||||
Ok(image) => image,
|
||||
Err(e) => {
|
||||
error!("Failed loading icon {}", path.display());
|
||||
return None;
|
||||
}
|
||||
};
|
||||
let rgba_image = image.to_rgba8();
|
||||
let (width, height) = rgba_image.dimensions();
|
||||
Some(Icon::from_rgba(rgba_image.into_raw(), width, height).unwrap())
|
||||
|
|
@ -113,14 +129,6 @@ impl<'a> App<'a> {
|
|||
self.game_state.as_mut()?.downcast_mut::<T>()
|
||||
}
|
||||
|
||||
pub fn world(&self) -> &World {
|
||||
&self.world
|
||||
}
|
||||
|
||||
pub fn world_mut(&mut self) -> &mut World {
|
||||
&mut self.world
|
||||
}
|
||||
|
||||
pub fn input_manager(&self) -> &WinitInputHelper {
|
||||
&self.input_manager
|
||||
}
|
||||
|
|
@ -137,6 +145,46 @@ impl<'a> App<'a> {
|
|||
self.input_manager.key_released(key)
|
||||
}
|
||||
|
||||
pub fn new_entity(&mut self) -> u32 {
|
||||
self.world.new_entity()
|
||||
}
|
||||
|
||||
pub fn delete_entity(&mut self, entity_id: usize) {
|
||||
self.world.delete_entity(entity_id)
|
||||
}
|
||||
|
||||
pub fn get_entity(&self, entity_id: usize) -> Option<&Entity> {
|
||||
self.world.get_entity(entity_id)
|
||||
}
|
||||
|
||||
pub fn get_entity_mut(&mut self, entity_id: usize) -> Option<&mut Entity> {
|
||||
self.world.get_entity_mut(entity_id)
|
||||
}
|
||||
|
||||
pub fn register_component<C: Component>(&mut self) {
|
||||
self.world.register_component::<C>()
|
||||
}
|
||||
|
||||
pub fn deregister_component<C: Component>(&mut self) {
|
||||
self.world.deregister_component::<C>()
|
||||
}
|
||||
|
||||
pub fn add_component<C: Component>(&mut self, entity_id: usize, component: C) {
|
||||
self.world.add_component(entity_id, component)
|
||||
}
|
||||
|
||||
pub fn remove_component<C: Component>(&mut self, entity_id: usize) {
|
||||
self.world.remove_component::<C>(entity_id)
|
||||
}
|
||||
|
||||
pub fn get_component<C: Component>(&self, entity_id: usize) -> Option<&C> {
|
||||
self.world.get_component::<C>(entity_id)
|
||||
}
|
||||
|
||||
pub fn get_component_mut<C: Component>(&mut self, entity_id: usize) -> Option<&mut C> {
|
||||
self.world.get_component_mut::<C>(entity_id)
|
||||
}
|
||||
|
||||
pub fn quit(&mut self) {
|
||||
self.should_quit = true;
|
||||
}
|
||||
|
|
@ -154,7 +202,7 @@ impl<'a> App<'a> {
|
|||
self.update_timer = 1.0/update_rate as f32;
|
||||
}
|
||||
|
||||
fn create_window(app_title: &str, app_icon: &Option<Icon>, window_size: &Option<LogicalSize<u32>>, event_loop: &EventLoop<()>) -> Window {
|
||||
fn create_window(app_title: String, app_icon: &Option<Icon>, window_size: &Option<LogicalSize<u32>>, event_loop: &EventLoop<()>) -> Window {
|
||||
let winit_window = winit::window::WindowBuilder::new()
|
||||
.with_title(app_title);
|
||||
|
||||
|
|
@ -173,19 +221,103 @@ impl<'a> App<'a> {
|
|||
winit_window.build(event_loop).unwrap()
|
||||
}
|
||||
|
||||
/*pub fn run<R: Renderer>(mut self, setup: fn(&mut App, &mut R), update: fn(&mut App, &mut R, f32)) {
|
||||
/*pub fn run<R: Renderer + 'static>(mut self, setup: fn(&mut App, &mut R), update: fn(&mut App, &mut R, f32)) {
|
||||
info!("Starting up {}!", self.title);
|
||||
|
||||
pollster::block_on(async {
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
let window = Arc::new(Self::create_window(self.title, &self.icon, &self.size ,&event_loop));
|
||||
let mut renderer = R::new(window.clone(), self.clear_color.clone()).await;
|
||||
let window = Arc::new(Self::create_window(self.title.clone(), &self.icon, &self.size, &event_loop));
|
||||
let mut renderer = Arc::new(RwLock::new(R::new(window.clone(), self.clear_color.clone()).await));
|
||||
info!("Renderer created! ({})", type_name::<R>());
|
||||
window.set_maximized(true);
|
||||
|
||||
setup(&mut self, &mut renderer);
|
||||
let app = Arc::new(RwLock::new(self.clone()));
|
||||
|
||||
// Run setup with locked app
|
||||
{
|
||||
let mut app_lock = app.write().unwrap();
|
||||
let mut renderer_lock = renderer.write().unwrap();
|
||||
setup(&mut *app_lock, &mut *renderer_lock);
|
||||
}
|
||||
|
||||
let (game_tx, game_rx) = bounded::<AppMessage>(10);
|
||||
let (render_tx, render_rx) = bounded::<AppMessage>(10);
|
||||
|
||||
// Spawn game logic thread
|
||||
let game_thread_app = Arc::clone(&app);
|
||||
let game_thread_renderer = Arc::clone(&renderer);
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut time_stack = 0.0;
|
||||
let mut last_update = Instant::now();
|
||||
|
||||
while !game_thread_app.read().unwrap().should_quit {
|
||||
let now = Instant::now();
|
||||
let delta = now.duration_since(last_update).as_secs_f32();
|
||||
|
||||
// Get a single write lock and use it for the entire update
|
||||
let mut app_lock = game_thread_app.write().unwrap();
|
||||
app_lock.delta_time = delta;
|
||||
|
||||
time_stack += delta;
|
||||
let update_timer = app_lock.update_timer; // Store the timer value
|
||||
|
||||
while time_stack > update_timer {
|
||||
let mut renderer_lock = game_thread_renderer.write().unwrap();
|
||||
update(&mut *app_lock, &mut *renderer_lock, delta);
|
||||
drop(renderer_lock);
|
||||
time_stack -= update_timer;
|
||||
render_tx.send(AppMessage::UpdateCompleted(delta)).unwrap();
|
||||
}
|
||||
|
||||
// Lock is automatically released here
|
||||
drop(app_lock);
|
||||
|
||||
last_update = now;
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
});
|
||||
|
||||
// Main thread handles events and rendering
|
||||
info!("Starting event loop!");
|
||||
event_loop.run(move |event, elwt| {
|
||||
// Get a single write lock for the entire input handling
|
||||
let mut app_lock = app.write().unwrap();
|
||||
if app_lock.should_quit {
|
||||
elwt.exit();
|
||||
}
|
||||
app_lock.input_manager.update(&event);
|
||||
drop(app_lock); // Explicitly drop the lock before event handling
|
||||
|
||||
match event {
|
||||
Event::WindowEvent { ref event, .. } => {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
app.write().unwrap().quit();
|
||||
elwt.exit();
|
||||
}
|
||||
WindowEvent::Resized(size) => {
|
||||
let mut renderer_lock = renderer.write().unwrap();
|
||||
renderer_lock.resize(*size);
|
||||
}
|
||||
WindowEvent::RedrawRequested => {
|
||||
while let Ok(AppMessage::UpdateCompleted(_)) = render_rx.try_recv() {
|
||||
let mut renderer_lock = renderer.write().unwrap();
|
||||
match renderer_lock.render() {
|
||||
Ok(_) => window.request_redraw(),
|
||||
Err(e) => error!("Error rendering: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}).unwrap();
|
||||
});
|
||||
|
||||
info!("Shutting down {}!", self.title);
|
||||
info!("Shutting down {}!", self.title.clone());
|
||||
}*/
|
||||
|
||||
pub fn run<R: Renderer>(mut self, setup: fn(&mut App, &mut R), update: fn(&mut App, &mut R, f32)) {
|
||||
|
|
@ -193,10 +325,10 @@ impl<'a> App<'a> {
|
|||
|
||||
pollster::block_on(async {
|
||||
let event_loop = EventLoop::new().unwrap();
|
||||
let window = Arc::new(Self::create_window(self.title, &self.icon, &self.size ,&event_loop));
|
||||
let window = Arc::new(Self::create_window(self.title.clone(), &self.icon, &self.size ,&event_loop));
|
||||
let mut renderer = R::new(window.clone(), self.clear_color.clone()).await;
|
||||
info!("Renderer created! ({})", type_name::<R>());
|
||||
window.set_maximized(true);
|
||||
//window.set_maximized(true);
|
||||
|
||||
info!("Setting up!");
|
||||
setup(&mut self, &mut renderer);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue