use std::sync::{Arc, Mutex}; use anyhow::Result; use engine::prelude::{ cgmath::{vec2, vec3, Vector2, Vector3}, *, }; use crate::{game::MillGame, objects::Objects}; #[derive(Debug)] pub struct BoardSlot { pub x: usize, pub y: usize, pub z: usize, pub state: Mutex, pub position: Vector2, pub slot_marker: Option, } impl BoardSlot { pub const SLOT_MARKER_SIZE: f32 = 1.5; pub fn new( x: usize, y: usize, z: usize, position: Vector2, scene: &mut Scene, ) -> Result { let mut marker = scene.engine().assets().empty_entity(); let meshes = vec![Self::create_mesh(&scene.engine(), Color::Black)?]; let draw = Draw::new(meshes); marker.insert_component(draw); let mut location = Location::from_entity(&mut marker); location.set_position(position.extend(MillGame::OFFSET_TO_BOARD)); marker.insert_component(location); Ok(Self { x, y, z, state: Mutex::new(BoardSlotState::default()), position, slot_marker: Some(scene.add_entity(marker)?), }) } pub fn invalid(x: usize, y: usize, z: usize) -> Self { Self { x, y, z, state: Mutex::new(BoardSlotState::Invalid), position: vec2(0.0, 0.0), slot_marker: None, } } fn create_mesh(engine: &Arc, color: Color) -> Result { let mut mesh = AssetMesh::new( engine.device(), engine.settings().graphics_info()?.render_type, )?; let vertex_buffer = Buffer::builder() .set_data(&Objects::create_flat_quad([ vec2(-Self::SLOT_MARKER_SIZE * 0.5, -Self::SLOT_MARKER_SIZE * 0.5), vec2(Self::SLOT_MARKER_SIZE * 0.5, -Self::SLOT_MARKER_SIZE * 0.5), vec2(Self::SLOT_MARKER_SIZE * 0.5, Self::SLOT_MARKER_SIZE * 0.5), vec2(-Self::SLOT_MARKER_SIZE * 0.5, Self::SLOT_MARKER_SIZE * 0.5), ])) .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, )?; Ok(mesh) } pub fn valid(&self) -> bool { *self.state.lock().unwrap() != BoardSlotState::Invalid } pub fn white(&self) -> bool { match *self.state.lock().unwrap() { BoardSlotState::White(_) => true, _ => false, } } pub fn black(&self) -> bool { match *self.state.lock().unwrap() { BoardSlotState::Black(_) => true, _ => false, } } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum BoardSlotState { Invalid, Empty, Black(Entity), White(Entity), } impl Default for BoardSlotState { fn default() -> Self { Self::Empty } } pub struct Board { _board: Entity, center: Vector3, _connection_lines: Vec, slots: [[[BoardSlot; 3]; 3]; 3], white_start_slots: [Vector2; 9], black_start_slots: [Vector2; 9], } impl Board { pub fn new(engine: &Arc, scene: &mut SceneHandle) -> Result { let mut board_entity = engine.assets().empty_entity(); let meshes = vec![Self::create_board_base(&engine)?]; let draw = Draw::new(meshes); board_entity.insert_component(draw); let location = Location::from_entity(&mut board_entity); board_entity.insert_component(location); let mut board = None; let mut slots = None; scene.on_scene(|scene| { board = Some(scene.add_entity(board_entity)?); slots = Some([ [ [ BoardSlot::new(0, 0, 0, vec2(-15.0, -15.0), scene)?, // 0 0 0 BoardSlot::new(0, 0, 1, vec2(-10.0, -10.0), scene)?, // 0 0 1 BoardSlot::new(0, 0, 2, vec2(-5.0, -5.0), scene)?, // 0 0 2 ], [ BoardSlot::new(0, 1, 0, vec2(-15.0, 0.0), scene)?, // 0 1 0 BoardSlot::new(0, 1, 1, vec2(-10.0, 0.0), scene)?, // 0 1 1 BoardSlot::new(0, 1, 2, vec2(-5.0, 0.0), scene)?, // 0 1 2 ], [ BoardSlot::new(0, 2, 0, vec2(-15.0, 15.0), scene)?, // 0 2 0 BoardSlot::new(0, 2, 1, vec2(-10.0, 10.0), scene)?, // 0 2 1 BoardSlot::new(0, 2, 2, vec2(-5.0, 5.0), scene)?, // 0 2 2 ], ], [ [ BoardSlot::new(1, 0, 0, vec2(0.0, -15.0), scene)?, // 1 0 0 BoardSlot::new(1, 0, 1, vec2(0.0, -10.0), scene)?, // 1 0 1 BoardSlot::new(1, 0, 2, vec2(0.0, -5.0), scene)?, // 1 0 2 ], [ BoardSlot::invalid(1, 1, 0), // 1 1 0 BoardSlot::invalid(1, 1, 1), // 1 1 1 BoardSlot::invalid(1, 1, 2), // 1 1 2 ], [ BoardSlot::new(1, 2, 0, vec2(0.0, 15.0), scene)?, // 1 2 0 BoardSlot::new(1, 2, 1, vec2(0.0, 10.0), scene)?, // 1 2 1 BoardSlot::new(1, 2, 2, vec2(0.0, 5.0), scene)?, // 1 2 2 ], ], [ [ BoardSlot::new(2, 0, 0, vec2(15.0, -15.0), scene)?, // 2 0 0 BoardSlot::new(2, 0, 1, vec2(10.0, -10.0), scene)?, // 2 0 1 BoardSlot::new(2, 0, 2, vec2(5.0, -5.0), scene)?, // 2 0 2 ], [ BoardSlot::new(2, 1, 0, vec2(15.0, 0.0), scene)?, // 2 1 0 BoardSlot::new(2, 1, 1, vec2(10.0, 0.0), scene)?, // 2 1 1 BoardSlot::new(2, 1, 2, vec2(5.0, 0.0), scene)?, // 2 1 2 ], [ BoardSlot::new(2, 2, 0, vec2(15.0, 15.0), scene)?, // 2 2 0 BoardSlot::new(2, 2, 1, vec2(10.0, 10.0), scene)?, // 2 2 1 BoardSlot::new(2, 2, 2, vec2(5.0, 5.0), scene)?, // 2 2 2 ], ], ]); Ok(()) })?; let distance = 20.0; let white_start_slots = [ vec2(-16.0, distance), vec2(-12.0, distance), vec2(-8.0, distance), vec2(-4.0, distance), vec2(0.0, distance), vec2(4.0, distance), vec2(8.0, distance), vec2(12.0, distance), vec2(16.0, distance), ]; let black_start_slots = [ vec2(-16.0, -distance), vec2(-12.0, -distance), vec2(-8.0, -distance), vec2(-4.0, -distance), vec2(0.0, -distance), vec2(4.0, -distance), vec2(8.0, -distance), vec2(12.0, -distance), vec2(16.0, -distance), ]; Ok(Self { _board: board.unwrap(), center: vec3(0.0, 0.0, 0.0), _connection_lines: Self::create_connection_lines(scene, Color::Black)?, slots: slots.unwrap(), white_start_slots, black_start_slots, }) } pub fn center(&self) -> Vector3 { self.center } pub fn white_start_slots(&self) -> &[Vector2; 9] { &self.white_start_slots } pub fn black_start_slots(&self) -> &[Vector2; 9] { &self.black_start_slots } pub fn slots(&mut self) -> &mut [[[BoardSlot; 3]; 3]; 3] { &mut self.slots } pub fn close_to_marker(&mut self, position: Vector2) -> Option<&mut BoardSlot> { const DISTANCE: f32 = 1.25; for outer in self.slots.iter_mut() { for inner in outer.iter_mut() { for slot in inner.iter_mut() { if *slot.state.lock().unwrap() != BoardSlotState::Invalid { if (slot.position - position).magnitude() <= DISTANCE { return Some(slot); } } } } } None } } impl Board { fn create_board_base(engine: &Arc) -> Result { let mut board_base = AssetMesh::new( engine.device(), engine.settings().graphics_info()?.render_type, )?; let vertex_buffer = Buffer::builder() .set_data(&Objects::create_cuboid( vec3(-22.5, -25.0, -2.0), vec3(45.0, 50.0, 2.0), )) .set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) .set_memory_usage(MemoryUsage::CpuOnly) .build(engine.device().clone())?; let color = Color::try_from("#b77b2b")?; let a: [f32; 3] = color.into(); board_base.add_primitive( vertex_buffer, None, None, PrimitiveMaterial { color: [a[0], a[1], a[2], 1.0], metallic_factor: 0.2, emissive_factor: [0.5, 0.5, 0.5], roughness_factor: 0.8, alpha_mode: AlphaMode::Opaque, alpha_cut_off: 0.5, }, true, )?; Ok(board_base) } fn create_connection_lines(scene: &mut SceneHandle, color: Color) -> Result> { let mut entities = Vec::new(); scene.on_scene(|scene| { let mut lines = scene.engine().assets().empty_entity(); let draw = Draw::new(vec![{ let mut mesh = AssetMesh::new( scene.engine().device(), scene.engine().settings().graphics_info()?.render_type, )?; let vertex_buffer = Buffer::builder() .set_data( &[ Objects::create_flat_quad([ vec2(-15.25, -15.25), vec2(15.25, -15.25), vec2(15.25, -14.75), vec2(-15.25, -14.75), ]), Objects::create_flat_quad([ vec2(-10.25, -10.25), vec2(10.25, -10.25), vec2(10.25, -9.75), vec2(-10.25, -9.75), ]), Objects::create_flat_quad([ vec2(-5.25, -5.25), vec2(5.25, -5.25), vec2(5.25, -4.75), vec2(-5.25, -4.75), ]), Objects::create_flat_quad([ vec2(-15.25, 14.75), vec2(15.25, 14.75), vec2(15.25, 15.25), vec2(-15.25, 15.25), ]), Objects::create_flat_quad([ vec2(-10.25, 9.75), vec2(10.25, 9.75), vec2(10.25, 10.25), vec2(-10.25, 10.25), ]), Objects::create_flat_quad([ vec2(-5.25, 4.75), vec2(5.25, 4.75), vec2(5.25, 5.25), vec2(-5.25, 5.25), ]), Objects::create_flat_quad([ vec2(-14.75, -15.25), vec2(-14.75, 15.25), vec2(-15.25, 15.25), vec2(-15.25, -15.25), ]), Objects::create_flat_quad([ vec2(-9.75, -10.25), vec2(-9.75, 10.25), vec2(-10.25, 10.25), vec2(-10.25, -10.25), ]), Objects::create_flat_quad([ vec2(-4.75, -5.25), vec2(-4.75, 5.25), vec2(-5.25, 5.25), vec2(-5.25, -5.25), ]), Objects::create_flat_quad([ vec2(15.25, -15.25), vec2(15.25, 15.25), vec2(14.75, 15.25), vec2(14.75, -15.25), ]), Objects::create_flat_quad([ vec2(10.25, -10.25), vec2(10.25, 10.25), vec2(9.75, 10.25), vec2(9.75, -10.25), ]), Objects::create_flat_quad([ vec2(5.25, -5.25), vec2(5.25, 5.25), vec2(4.75, 5.25), vec2(4.75, -5.25), ]), Objects::create_flat_quad([ vec2(0.25, -15.25), vec2(0.25, -4.75), vec2(-0.25, -4.75), vec2(-0.25, -15.25), ]), Objects::create_flat_quad([ vec2(-0.25, 15.25), vec2(-0.25, 4.75), vec2(0.25, 4.75), vec2(0.25, 15.25), ]), Objects::create_flat_quad([ vec2(-15.25, -0.25), vec2(-4.75, -0.25), vec2(-4.75, 0.25), vec2(-15.25, 0.25), ]), Objects::create_flat_quad([ vec2(15.25, 0.25), vec2(4.75, 0.25), vec2(4.75, -0.25), vec2(15.25, -0.25), ]), ] .concat(), ) .set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) .set_memory_usage(MemoryUsage::CpuOnly) .build(scene.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 }]); lines.insert_component(draw); let mut location = Location::from_entity(&mut lines); location.set_offset(vec3(0.0, 0.0, MillGame::OFFSET_TO_BOARD)); lines.insert_component(location); entities.push(scene.add_entity(lines)?); Ok(()) })?; Ok(entities) } } impl Map for Board { fn name(&self) -> &str { "MillBoard" } fn check_walkability( &self, _position: cgmath::Vector2, _direction: cgmath::Vector2, _radius: f32, ) -> Result { Ok(true) } fn get_height(&self, _x: f32, _y: f32) -> Result { Ok(0.0) } fn spawn_positions(&self) -> Result>> { Ok(vec![]) } fn leave_markers(&self) -> Result> { Ok(vec![]) } fn disable(&self, _scene: &mut Scene) -> Result<()> { unreachable!() } }