use std::sync::{ atomic::{AtomicU32, Ordering::SeqCst}, Arc, Mutex, }; use anyhow::Result; use engine::prelude::{cgmath::vec3, *}; use crate::{board::Board, objects::Objects}; pub struct MillGame { board: Arc, white_stones: [Entity; 9], black_stones: [Entity; 9], scene: Mutex, camera_controls: Mutex, mouse_x: AtomicU32, mouse_y: AtomicU32, } impl MillGame { pub const OFFSET_TO_BOARD: f32 = 0.01; pub fn new(engine: Arc) -> Result> { let mut scene = SceneHandle::new(&engine)?; let board = Board::new(&engine, &mut scene)?; let mut white_stones = None; let mut black_stones = None; scene.on_scene(|scene| { let view = scene.view_mut(); view.camera_mut().set_center(board.center()); view.update_buffer()?; // add light let mut sun_light = engine.new_directional_light()?; sun_light.set_direction(vec3(10.0, -4.0, -20.0))?; sun_light.set_color(vec3(1.0, 1.0, 1.0))?; sun_light.set_position(vec3(0.0, 0.0, 100.0))?; sun_light.set_power(10000000000.0)?; scene.add_light(sun_light)?; white_stones = Some( Self::init_nine_stones(&engine, Color::White)? .into_iter() .enumerate() .map(|(index, mut e)| { let location = e.get_component_mut::()?; location.set_position(board.white_start_slots()[index].extend(0.0)); scene.add_entity(e) }) .collect::>>()? .try_into() .unwrap_or_else(|_: Vec| { unreachable!("create array from vec from an array") }), ); black_stones = Some( Self::init_nine_stones(&engine, Color::Black)? .into_iter() .enumerate() .map(|(index, mut e)| { let location = e.get_component_mut::()?; location.set_position(board.black_start_slots()[index].extend(0.0)); scene.add_entity(e) }) .collect::>>()? .try_into() .unwrap_or_else(|_: Vec| { unreachable!("create array from vec from an array") }), ); Ok(()) })?; let camera_control = CameraControl::new(&mut scene)?; scene.activate()?; Ok(Arc::new(Self { board, white_stones: white_stones.unwrap(), black_stones: black_stones.unwrap(), scene: Mutex::new(scene), camera_controls: Mutex::new(camera_control), mouse_x: AtomicU32::new(0), mouse_y: AtomicU32::new(0), })) } fn init_nine_stones(engine: &Arc, color: Color) -> Result<[EntityObject; 9]> { Ok((0..9) .map(|_| Self::init_stone(engine, color)) .collect::>>()? .try_into() .unwrap_or_else(|_: Vec| { unreachable!("create array from vec from an array") })) } fn init_stone(engine: &Arc, color: Color) -> Result { let mut marker = engine.assets().empty_entity(); let draw = Draw::new(vec![{ let mut mesh = AssetMesh::new( engine.device(), engine.settings().graphics_info()?.render_type, )?; let vertex_buffer = Buffer::builder() .set_data(&Objects::create_cylinder(1.0, 0.25, 12)) .set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) .set_memory_usage(MemoryUsage::CpuOnly) .build(engine.device().clone())?; let a: [f32; 3] = color.into(); mesh.add_primitive( vertex_buffer, None, None, PrimitiveMaterial { color: [a[0], a[1], a[2], 1.0], metallic_factor: 0.2, emissive_factor: [0.2, 0.2, 0.2], roughness_factor: 0.8, alpha_mode: AlphaMode::Opaque, alpha_cut_off: 0.5, }, true, )?; mesh }]); marker.insert_component(draw); let location = Location::from_entity(&mut marker); marker.insert_component(location); Ok(marker) } } impl EngineObject for MillGame { fn name(&self) -> &str { "MillGame" } fn update(&self) -> Result<()> { Ok(()) } fn event(&self, event: EngineEvent) -> Result<()> { match event { EngineEvent::MouseMotion(x, y) => { self.mouse_x.store(x, SeqCst); self.mouse_y.store(y, SeqCst); self.camera_controls.lock().unwrap().mouse_move( x, y, &mut *self.scene.lock().unwrap(), )?; } EngineEvent::MouseButtonDown(button) => match button { MouseButton::Left => { self.scene.lock().unwrap().on_scene(|scene| { if let Some(world_space) = scene.screen_space_to_world( self.mouse_x.load(SeqCst), self.mouse_y.load(SeqCst), )? { if self.board.close_to_marker(world_space.truncate()) { println!("close to marker"); } else { println!("not close to a marker"); } } Ok(()) })?; } MouseButton::Middle => self.camera_controls.lock().unwrap().hold(), MouseButton::Right => (), MouseButton::Forward => (), MouseButton::Backward => (), }, EngineEvent::MouseButtonUp(button) => match button { MouseButton::Left => (), MouseButton::Middle => self.camera_controls.lock().unwrap().release(), MouseButton::Right => (), MouseButton::Forward => (), MouseButton::Backward => (), }, EngineEvent::MouseWheel(_x, y, direction) => self .camera_controls .lock() .unwrap() .scroll_wheel(y, direction, &mut *self.scene.lock().unwrap())?, EngineEvent::KeyDown(_) => (), EngineEvent::KeyUp(_) => (), EngineEvent::ButtonDown(_) => (), EngineEvent::ButtonUp(_) => (), EngineEvent::ControllerAxis(_) => (), EngineEvent::ControllerAdded(_) => (), EngineEvent::ControllerRemoved(_) => (), EngineEvent::FileDrop(_) => (), } Ok(()) } }