Start placing phse
This commit is contained in:
parent
139f7d92cc
commit
686dae95bf
5 changed files with 324 additions and 35 deletions
8
resources/mainmenu.xml
Normal file
8
resources/mainmenu.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<root reference_width="1280" reference_height="720">
|
||||
<grid id="grid" x_dim="3" y_dim="1" x_offset="-400" y_offset="10" width="800" height="80"
|
||||
vert_align="top" hori_align="middle" margin="0" padding="20">
|
||||
<label id="white_player_label" x_slot="0" y_slot="0" text_color="white">White Player (AI)</label>
|
||||
<button id="start" x_slot="1" y_slot="0" text_color="white" select="true">Start</button>
|
||||
<label id="black_player_label" x_slot="2" y_slot="0" text_color="white">Black Player</label>
|
||||
</grid>
|
||||
</root>
|
30
src/board.rs
30
src/board.rs
|
@ -98,10 +98,10 @@ impl Default for BoardSlotState {
|
|||
}
|
||||
|
||||
pub struct Board {
|
||||
board: Entity,
|
||||
_board: Entity,
|
||||
center: Vector3<f32>,
|
||||
|
||||
connection_lines: Vec<Entity>,
|
||||
_connection_lines: Vec<Entity>,
|
||||
|
||||
slots: [[[BoardSlot; 3]; 3]; 3],
|
||||
white_start_slots: [Vector2<f32>; 9],
|
||||
|
@ -109,7 +109,7 @@ pub struct Board {
|
|||
}
|
||||
|
||||
impl Board {
|
||||
pub fn new(engine: &Arc<Engine>, scene: &mut SceneHandle) -> Result<Arc<Self>> {
|
||||
pub fn new(engine: &Arc<Engine>, scene: &mut SceneHandle) -> Result<Self> {
|
||||
let mut board_entity = engine.assets().empty_entity();
|
||||
|
||||
let meshes = vec![Self::create_board_base(&engine)?];
|
||||
|
@ -209,16 +209,16 @@ impl Board {
|
|||
vec2(16.0, -distance),
|
||||
];
|
||||
|
||||
Ok(Arc::new(Self {
|
||||
board: board.unwrap(),
|
||||
Ok(Self {
|
||||
_board: board.unwrap(),
|
||||
center: vec3(0.0, 0.0, 0.0),
|
||||
|
||||
connection_lines: Self::create_connection_lines(scene, Color::Black)?,
|
||||
_connection_lines: Self::create_connection_lines(scene, Color::Black)?,
|
||||
|
||||
slots: slots.unwrap(),
|
||||
white_start_slots,
|
||||
black_start_slots,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn center(&self) -> Vector3<f32> {
|
||||
|
@ -233,22 +233,26 @@ impl Board {
|
|||
&self.black_start_slots
|
||||
}
|
||||
|
||||
pub fn close_to_marker(&self, position: Vector2<f32>) -> bool {
|
||||
pub fn slots(&mut self) -> &mut [[[BoardSlot; 3]; 3]; 3] {
|
||||
&mut self.slots
|
||||
}
|
||||
|
||||
pub fn close_to_marker(&mut self, position: Vector2<f32>) -> Option<&mut BoardSlot> {
|
||||
const DISTANCE: f32 = 1.25;
|
||||
|
||||
for outer in self.slots.iter() {
|
||||
for inner in outer.iter() {
|
||||
for slot in inner.iter() {
|
||||
for outer in self.slots.iter_mut() {
|
||||
for inner in outer.iter_mut() {
|
||||
for slot in inner.iter_mut() {
|
||||
if slot.state != BoardSlotState::Invalid {
|
||||
if (slot.position - position).magnitude() <= DISTANCE {
|
||||
return true;
|
||||
return Some(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
|
267
src/game.rs
267
src/game.rs
|
@ -4,24 +4,74 @@ use std::sync::{
|
|||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use assetpath::AssetPath;
|
||||
use engine::prelude::{cgmath::vec3, *};
|
||||
|
||||
use crate::{board::Board, objects::Objects};
|
||||
use crate::{
|
||||
board::{Board, BoardSlot, BoardSlotState},
|
||||
objects::Objects,
|
||||
simple_ai::SimpleAI,
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub enum StoneState {
|
||||
ReadyToBePlaced,
|
||||
Placed,
|
||||
Dead,
|
||||
}
|
||||
|
||||
pub struct Stone {
|
||||
pub stone: Entity,
|
||||
pub state: StoneState,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub enum GameState {
|
||||
Placing,
|
||||
Main,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub enum PlayerColor {
|
||||
White,
|
||||
Black,
|
||||
}
|
||||
|
||||
impl PlayerColor {
|
||||
pub fn swap(&mut self) {
|
||||
*self = match *self {
|
||||
PlayerColor::White => PlayerColor::Black,
|
||||
PlayerColor::Black => PlayerColor::White,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MillGame {
|
||||
board: Arc<Board>,
|
||||
white_stones: [Entity; 9],
|
||||
black_stones: [Entity; 9],
|
||||
board: Arc<Mutex<Board>>,
|
||||
white_stones: Mutex<[Stone; 9]>,
|
||||
black_stones: Mutex<[Stone; 9]>,
|
||||
|
||||
state: Mutex<GameState>,
|
||||
current_player: Mutex<PlayerColor>,
|
||||
|
||||
scene: Mutex<SceneHandle>,
|
||||
camera_controls: Mutex<CameraControl>,
|
||||
|
||||
mouse_x: AtomicU32,
|
||||
mouse_y: AtomicU32,
|
||||
|
||||
simple_ai: SimpleAI,
|
||||
|
||||
white_player_label: Arc<Label>,
|
||||
black_player_label: Arc<Label>,
|
||||
start_button: Arc<Button>,
|
||||
grid: Arc<Grid>,
|
||||
|
||||
gui: Arc<GuiBuilder>,
|
||||
}
|
||||
|
||||
impl MillGame {
|
||||
pub const OFFSET_TO_BOARD: f32 = 0.01;
|
||||
pub const OFFSET_TO_BOARD: f32 = 0.02;
|
||||
|
||||
pub fn new(engine: Arc<Engine>) -> Result<Arc<Self>> {
|
||||
let mut scene = SceneHandle::new(&engine)?;
|
||||
|
@ -53,28 +103,34 @@ impl MillGame {
|
|||
let location = e.get_component_mut::<Location>()?;
|
||||
location.set_position(board.white_start_slots()[index].extend(0.0));
|
||||
|
||||
scene.add_entity(e)
|
||||
Ok(Stone {
|
||||
stone: scene.add_entity(e)?,
|
||||
state: StoneState::ReadyToBePlaced,
|
||||
})
|
||||
.collect::<Result<Vec<Entity>>>()?
|
||||
})
|
||||
.collect::<Result<Vec<Stone>>>()?
|
||||
.try_into()
|
||||
.unwrap_or_else(|_: Vec<Entity>| {
|
||||
.unwrap_or_else(|_: Vec<Stone>| {
|
||||
unreachable!("create array from vec from an array")
|
||||
}),
|
||||
);
|
||||
|
||||
black_stones = Some(
|
||||
Self::init_nine_stones(&engine, Color::Black)?
|
||||
Self::init_nine_stones(&engine, Color::try_from("#2c2c2c")?)?
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, mut e)| {
|
||||
let location = e.get_component_mut::<Location>()?;
|
||||
location.set_position(board.black_start_slots()[index].extend(0.0));
|
||||
|
||||
scene.add_entity(e)
|
||||
Ok(Stone {
|
||||
stone: scene.add_entity(e)?,
|
||||
state: StoneState::ReadyToBePlaced,
|
||||
})
|
||||
.collect::<Result<Vec<Entity>>>()?
|
||||
})
|
||||
.collect::<Result<Vec<Stone>>>()?
|
||||
.try_into()
|
||||
.unwrap_or_else(|_: Vec<Entity>| {
|
||||
.unwrap_or_else(|_: Vec<Stone>| {
|
||||
unreachable!("create array from vec from an array")
|
||||
}),
|
||||
);
|
||||
|
@ -82,21 +138,135 @@ impl MillGame {
|
|||
Ok(())
|
||||
})?;
|
||||
|
||||
let camera_control = CameraControl::new(&mut scene)?;
|
||||
let mut camera_control = CameraControl::new(&mut scene)?;
|
||||
camera_control.set_zoom_levels(
|
||||
(3..60).into_iter().rev().map(|z| z as f32).collect(),
|
||||
5,
|
||||
&mut scene,
|
||||
)?;
|
||||
|
||||
scene.activate()?;
|
||||
|
||||
Ok(Arc::new(Self {
|
||||
board,
|
||||
white_stones: white_stones.unwrap(),
|
||||
black_stones: black_stones.unwrap(),
|
||||
let gui = GuiBuilder::new(
|
||||
engine.gui_handler(),
|
||||
&AssetPath::from((
|
||||
engine.settings().resource_base_path.as_str(),
|
||||
"mainmenu.xml",
|
||||
)),
|
||||
)?;
|
||||
|
||||
let grid: Arc<Grid> = gui.element("grid")?;
|
||||
let white_player_label: Arc<Label> = gui.element("white_player_label")?;
|
||||
let black_player_label: Arc<Label> = gui.element("black_player_label")?;
|
||||
let start_button: Arc<Button> = gui.element("start")?;
|
||||
|
||||
gui.enable()?;
|
||||
|
||||
let me = Arc::new(Self {
|
||||
board: Arc::new(Mutex::new(board)),
|
||||
white_stones: Mutex::new(white_stones.unwrap()),
|
||||
black_stones: Mutex::new(black_stones.unwrap()),
|
||||
|
||||
state: Mutex::new(GameState::Placing),
|
||||
current_player: Mutex::new(PlayerColor::White),
|
||||
|
||||
scene: Mutex::new(scene),
|
||||
camera_controls: Mutex::new(camera_control),
|
||||
|
||||
mouse_x: AtomicU32::new(0),
|
||||
mouse_y: AtomicU32::new(0),
|
||||
}))
|
||||
|
||||
simple_ai: SimpleAI::new(PlayerColor::White),
|
||||
|
||||
grid: grid.clone(),
|
||||
white_player_label,
|
||||
black_player_label,
|
||||
start_button: start_button.clone(),
|
||||
|
||||
gui,
|
||||
});
|
||||
|
||||
start_button.set_callback({
|
||||
let weak_grid = Arc::downgrade(&grid);
|
||||
let weak_self = Arc::downgrade(&me);
|
||||
|
||||
move || {
|
||||
if let Some(grid) = weak_grid.upgrade() {
|
||||
grid.detach(1, 0)?;
|
||||
}
|
||||
|
||||
if let Some(me) = weak_self.upgrade() {
|
||||
*me.state.lock().unwrap() = GameState::Placing;
|
||||
*me.current_player.lock().unwrap() = PlayerColor::White;
|
||||
|
||||
me.next_game_step()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
|
||||
Ok(me)
|
||||
}
|
||||
|
||||
fn next_game_step(&self) -> Result<()> {
|
||||
match *self.current_player.lock().unwrap() {
|
||||
PlayerColor::White => {
|
||||
self.black_player_label
|
||||
.set_background(Color::try_from("#9b9292")?)?;
|
||||
self.white_player_label.set_background(Color::Yellow)?;
|
||||
}
|
||||
PlayerColor::Black => {
|
||||
self.white_player_label
|
||||
.set_background(Color::try_from("#9b9292")?)?;
|
||||
self.black_player_label.set_background(Color::Yellow)?;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut state = self.state.lock().unwrap();
|
||||
|
||||
match *state {
|
||||
GameState::Placing => {
|
||||
if !self
|
||||
.black_stones
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|stones| stones.state == StoneState::ReadyToBePlaced)
|
||||
&& !self
|
||||
.white_stones
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|stones| stones.state == StoneState::ReadyToBePlaced)
|
||||
{
|
||||
*state = GameState::Main;
|
||||
}
|
||||
}
|
||||
GameState::Main => {}
|
||||
}
|
||||
}
|
||||
|
||||
if *self.current_player.lock().unwrap() == self.simple_ai.player_color {
|
||||
match self.simple_ai.player_color {
|
||||
PlayerColor::White => self.simple_ai.step(
|
||||
&mut *self.white_stones.lock().unwrap(),
|
||||
self.board.lock().unwrap().slots(),
|
||||
&mut *self.scene.lock().unwrap(),
|
||||
)?,
|
||||
PlayerColor::Black => self.simple_ai.step(
|
||||
&mut *self.black_stones.lock().unwrap(),
|
||||
self.board.lock().unwrap().slots(),
|
||||
&mut *self.scene.lock().unwrap(),
|
||||
)?,
|
||||
}
|
||||
|
||||
self.current_player.lock().unwrap().swap();
|
||||
self.next_game_step()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_nine_stones(engine: &Arc<Engine>, color: Color) -> Result<[EntityObject; 9]> {
|
||||
|
@ -150,6 +320,39 @@ impl MillGame {
|
|||
|
||||
Ok(marker)
|
||||
}
|
||||
|
||||
pub fn place_stone(
|
||||
stone: &mut Stone,
|
||||
slot: &mut BoardSlot,
|
||||
player_color: PlayerColor,
|
||||
scene: &mut Scene,
|
||||
) -> Result<()> {
|
||||
match player_color {
|
||||
PlayerColor::White => slot.state = BoardSlotState::White(stone.stone),
|
||||
PlayerColor::Black => slot.state = BoardSlotState::Black(stone.stone),
|
||||
}
|
||||
|
||||
stone.state = StoneState::Placed;
|
||||
|
||||
let entity = scene.entity_mut(stone.stone)?;
|
||||
|
||||
let location = entity.get_component_mut::<Location>()?;
|
||||
location.set_position(slot.position.extend(0.0));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_for_mill(&self) -> Result<bool> {
|
||||
let slots = self.board.lock().unwrap().slots();
|
||||
|
||||
for x in 0..3 {
|
||||
for y in 0..3 {
|
||||
for z in 0..3 {
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EngineObject for MillGame {
|
||||
|
@ -175,20 +378,40 @@ impl EngineObject for MillGame {
|
|||
}
|
||||
EngineEvent::MouseButtonDown(button) => match button {
|
||||
MouseButton::Left => {
|
||||
let mut placed = false;
|
||||
|
||||
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");
|
||||
if let Some(slot) = self
|
||||
.board
|
||||
.lock()
|
||||
.unwrap()
|
||||
.close_to_marker(world_space.truncate())
|
||||
{
|
||||
if let Some(placable) = self
|
||||
.black_stones
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter_mut()
|
||||
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
||||
{
|
||||
Self::place_stone(placable, slot, PlayerColor::Black, scene)?;
|
||||
|
||||
placed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
if placed {
|
||||
self.current_player.lock().unwrap().swap();
|
||||
self.next_game_step()?;
|
||||
}
|
||||
}
|
||||
MouseButton::Middle => self.camera_controls.lock().unwrap().hold(),
|
||||
MouseButton::Right => (),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
mod board;
|
||||
mod game;
|
||||
mod objects;
|
||||
mod simple_ai;
|
||||
|
||||
use anyhow::Result;
|
||||
use assetpath::AssetPath;
|
||||
|
@ -19,6 +20,11 @@ fn main() -> Result<()> {
|
|||
AssetPath::from((create_info.resource_base_path.as_str(), ""));
|
||||
|
||||
create_info.graphics_info.render_scale = 1.0;
|
||||
create_info.graphics_info.vsync = true;
|
||||
create_info.graphics_info.sample_count = VK_SAMPLE_COUNT_4_BIT;
|
||||
|
||||
create_info.rasterizer_info.enable_lighting = true;
|
||||
create_info.rasterizer_info.shadow_image_size = 512;
|
||||
|
||||
create_info.window_info.height = 600;
|
||||
create_info.window_info.width = 800;
|
||||
|
|
48
src/simple_ai.rs
Normal file
48
src/simple_ai.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use crate::{
|
||||
board::{BoardSlot, BoardSlotState},
|
||||
game::{MillGame, PlayerColor, Stone, StoneState},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use engine::prelude::*;
|
||||
|
||||
pub struct SimpleAI {
|
||||
pub player_color: PlayerColor,
|
||||
}
|
||||
|
||||
impl SimpleAI {
|
||||
pub fn new(player_color: PlayerColor) -> Self {
|
||||
Self { player_color }
|
||||
}
|
||||
|
||||
pub fn step(
|
||||
&self,
|
||||
stones: &mut [Stone; 9],
|
||||
board: &mut [[[BoardSlot; 3]; 3]; 3],
|
||||
scene: &mut SceneHandle,
|
||||
) -> Result<()> {
|
||||
if let Some(placable) = stones
|
||||
.iter_mut()
|
||||
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
|
||||
{
|
||||
let mut free_slots: Vec<&mut BoardSlot> = board
|
||||
.iter_mut()
|
||||
.flatten()
|
||||
.flatten()
|
||||
.filter(|slot| slot.state == BoardSlotState::Empty)
|
||||
.collect();
|
||||
|
||||
let len = free_slots.len();
|
||||
|
||||
let slot = &mut free_slots[Random::range(0, len as u32) as usize];
|
||||
|
||||
scene.on_scene(|scene| {
|
||||
MillGame::place_stone(placable, slot, self.player_color, scene)?;
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue