Continue fixing (part 2)

This commit is contained in:
Michael Huebner 2025-03-25 13:51:08 +01:00
parent e5d94f32f0
commit fabcff5a65
2 changed files with 257 additions and 276 deletions

View file

@ -1,4 +1,4 @@
use std::sync::{Arc, Mutex};
use std::sync::Arc;
use anyhow::Result;
use engine::prelude::{
@ -14,7 +14,7 @@ pub struct BoardSlot {
pub y: usize,
pub z: usize,
state: Mutex<BoardSlotState>,
state: BoardSlotState,
pub position: Vector2<f32>,
pub slot_marker: Option<Entity>,
}
@ -49,7 +49,7 @@ impl BoardSlot {
y,
z,
state: Mutex::new(BoardSlotState::default()),
state: BoardSlotState::default(),
position,
slot_marker: Some(world.add_entity(marker)?),
})
@ -61,7 +61,7 @@ impl BoardSlot {
y,
z,
state: Mutex::new(BoardSlotState::Invalid),
state: BoardSlotState::Invalid,
position: vec2(0.0, 0.0),
slot_marker: None,
}
@ -106,30 +106,30 @@ impl BoardSlot {
}
pub fn state(&self) -> BoardSlotState {
*self.state.lock().unwrap()
self.state
}
pub fn set_state(&self, state: BoardSlotState) {
*self.state.lock().unwrap() = state;
pub fn set_state(&mut self, state: BoardSlotState) {
self.state = state;
}
pub fn valid(&self) -> bool {
*self.state.lock().unwrap() != BoardSlotState::Invalid
self.state != BoardSlotState::Invalid
}
pub fn is_empty(&self) -> bool {
*self.state.lock().unwrap() == BoardSlotState::Empty
self.state == BoardSlotState::Empty
}
pub fn white(&self) -> bool {
match *self.state.lock().unwrap() {
match self.state {
BoardSlotState::White(_) => true,
_ => false,
}
}
pub fn black(&self) -> bool {
match *self.state.lock().unwrap() {
match self.state {
BoardSlotState::Black(_) => true,
_ => false,
}
@ -277,13 +277,13 @@ impl Board {
&mut self.slots
}
pub fn close_to_marker(&mut self, position: Vector2<f32>) -> Option<&mut BoardSlot> {
pub fn close_to_marker(&self, position: Vector2<f32>) -> Option<&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 {
for outer in self.slots.iter() {
for inner in outer.iter() {
for slot in inner.iter() {
if slot.state != BoardSlotState::Invalid {
if (slot.position - position).magnitude() <= DISTANCE {
return Some(slot);
}
@ -349,9 +349,7 @@ impl Board {
_ => unreachable!(),
} {
let neighbour_state = neighbour.state.lock().unwrap();
match *neighbour_state {
match neighbour.state {
BoardSlotState::Empty => {
neighbours.push(neighbour);
}

View file

@ -244,13 +244,6 @@ impl MillGame {
sun_light.set_position(vec3(0.0, 0.0, 100.0))?;
sun_light.set_power(10000000000.0)?;
let scene = world.resources.get_mut::<Scene>();
scene.add_light(sun_light)?;
let view = scene.view_mut();
view.camera_mut().set_center(board.center());
view.update_buffer()?;
let white_stones = Self::init_nine_stones(world, Color::White)?
.into_iter()
.enumerate()
@ -283,29 +276,38 @@ impl MillGame {
.try_into()
.unwrap_or_else(|_: Vec<Stone>| unreachable!("create array from vec from an array"));
let mut camera_control = TopDownCameraControl::new(&mut scene)?;
let scene = world.resources.get_mut::<Scene>();
scene.add_light(sun_light)?;
let view = scene.view_mut();
view.camera_mut().set_center(board.center());
view.update_buffer()?;
let mut camera_control = TopDownCameraControl::new(view)?;
camera_control.set_zoom_levels(
(3..60).into_iter().rev().map(|z| z as f32).collect(),
5,
&mut scene,
view,
)?;
world.resources.insert(camera_control);
let gui = GuiBuilder::new(
engine.gui_handler(),
&AssetPath::from((
engine.settings().resource_base_path.as_str(),
let path = AssetPath::from((
world
.resources
.get::<EngineSettings>()
.resource_base_path
.as_str(),
"mainmenu.xml",
)),
)?;
));
let gui = GuiBuilder::new(world, &path)?;
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(world.resources.get_mut::<GuiHandler>())?;
gui.enable(world)?;
start_button.set_callback({
let weak_grid = Arc::downgrade(&grid);
@ -323,7 +325,7 @@ impl MillGame {
me.state = GameState::Placing;
me.current_player = PlayerColor::Black;
me.finish_turn();
me.finish_turn(world);
me.last_turn_timing = now;
Ok(())
@ -346,7 +348,7 @@ impl MillGame {
mouse_y: 0,
turn_finished: false,
turn_states: TurnState::default(),
turn_states: Vec::new(),
selected_field: None,
@ -363,28 +365,31 @@ impl MillGame {
Ok(())
}
pub fn finish_turn(&mut self) {
pub fn finish_turn(&mut self, world: &World) {
Self::log(
&format!("{:?} finished turn", self.current_player),
LogSeverity::Debug,
);
self.last_turn_timing = self.engine.time();
self.last_turn_timing = world.now();
self.turn_finished = true;
self.selected_field = None;
}
fn print_game_state(&self, severity: LogSeverity, log_state: bool) -> Result<()> {
let current_turn_state = TurnState::new(self)?;
fn print_game_state(
&mut self,
world: &World,
severity: LogSeverity,
log_state: bool,
) -> Result<()> {
let current_turn_state = TurnState::new(world, self)?;
if log_state {
current_turn_state.log(severity);
}
let mut turn_states = self.turn_states.lock().unwrap();
if !turn_states.is_empty() {
let (new_diff, old_diff) = current_turn_state.diff(turn_states.last().unwrap());
if !self.turn_states.is_empty() {
let (new_diff, old_diff) = current_turn_state.diff(self.turn_states.last().unwrap());
// verity that last turn actually something happened
debug_assert!(!new_diff.is_empty());
@ -396,136 +401,127 @@ impl MillGame {
new_diff.log(severity);
}
turn_states.push(current_turn_state);
self.turn_states.push(current_turn_state);
Ok(())
}
fn next_game_step(&self) -> Result<()> {
{
let mut state = self.state.lock().unwrap();
fn next_game_step(&mut self, world: &World) -> Result<()> {
Self::log(
&format!(
" =========================== NEW TURN ({:?}) ===========================",
state
self.state
),
LogSeverity::Basic,
);
self.print_game_state(LogSeverity::Basic, false)?;
self.print_game_state(world, LogSeverity::Basic, false)?;
match *state {
match self.state {
GameState::Placing => {
// check if all stones are placed
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)
{
Self::log("change state to Main", LogSeverity::Debug);
*state = GameState::Main;
self.state = GameState::Main;
}
self.current_player.lock().unwrap().swap();
self.current_player.swap();
}
GameState::Removing => {
// check if all stones are placed, then decide whether main or placing is next state
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)
{
Self::log("change state to Main", LogSeverity::Debug);
*state = GameState::Main;
self.state = GameState::Main;
} else {
Self::log("change state to Placing", LogSeverity::Debug);
*state = GameState::Placing;
self.state = GameState::Placing;
}
self.current_player.lock().unwrap().swap();
self.current_player.swap();
}
GameState::Main => {
// check if each player has enough stones to play
if self
.white_stones
.lock()
.unwrap()
.iter()
.filter(|stone| stone.state != StoneState::Dead)
.collect::<Vec<&Stone>>()
.len()
<= 3
{
*state = GameState::Won(PlayerColor::Black);
self.state = GameState::Won(PlayerColor::Black);
return Ok(());
}
if self
.black_stones
.lock()
.unwrap()
.iter()
.filter(|stone| stone.state != StoneState::Dead)
.collect::<Vec<&Stone>>()
.len()
<= 3
{
*state = GameState::Won(PlayerColor::White);
self.state = GameState::Won(PlayerColor::White);
return Ok(());
}
self.current_player.lock().unwrap().swap();
self.current_player.swap();
}
GameState::Waiting => unreachable!(),
GameState::Won(_) => (),
}
}
let player = *self.current_player.lock().unwrap();
Self::log(
&format!("current player {:?}", self.current_player),
LogSeverity::Debug,
);
Self::log(&format!("current player {:?}", player), LogSeverity::Debug);
let mut resources = world.resources.multi_mut();
let gui_handler = resources.get::<GuiHandler>();
let simple_ai = resources.get::<SimpleAI>();
match player {
match self.current_player {
PlayerColor::White => {
self.black_player_label
.set_background(Color::try_from("#9b9292")?)?;
self.white_player_label.set_background(Color::Yellow)?;
.set_background(gui_handler, Color::try_from("#9b9292")?)?;
self.white_player_label
.set_background(gui_handler, Color::Yellow)?;
}
PlayerColor::Black => {
self.white_player_label
.set_background(Color::try_from("#9b9292")?)?;
self.black_player_label.set_background(Color::Yellow)?;
.set_background(gui_handler, Color::try_from("#9b9292")?)?;
self.black_player_label
.set_background(gui_handler, Color::Yellow)?;
}
}
if player == self.simple_ai.player_color {
if self.current_player == simple_ai.player_color {
Self::log("current player is AI", LogSeverity::Debug);
self.simple_ai.step(
&mut self.stones(self.simple_ai.player_color),
self.board.lock().unwrap().slots(),
simple_ai.step(
&mut self.stones(simple_ai.player_color),
self.board.slots_mut(),
&mut *self.scene.lock().unwrap(),
&mut *self.state.lock().unwrap(),
&mut self.state,
)?;
self.finish_turn();
self.finish_turn(world);
}
Self::log("leave next_game_step", LogSeverity::Debug);
@ -601,12 +597,12 @@ impl MillGame {
(x, y, z): (usize, usize, usize),
board: &mut [[[BoardSlot; 3]; 3]; 3],
player_color: PlayerColor,
scene: &mut Scene,
world: &mut World,
state: &mut GameState,
) -> Result<MillState> {
Self::log("place_stone", LogSeverity::Debug);
let slot = &board[x][y][z];
let slot = &mut board[x][y][z];
match player_color {
PlayerColor::White => {
@ -637,7 +633,7 @@ impl MillGame {
stone.state = StoneState::Placed;
let entity = scene.entity_mut(stone.stone)?;
let entity = world.entity_mut(stone.stone)?;
let location = entity.get_component_mut::<Location>()?;
location.set_position(slot.position.extend(0.0));
@ -659,7 +655,7 @@ impl MillGame {
pub fn move_stone(
(x, y, z): (usize, usize, usize),
(tx, ty, tz): (usize, usize, usize),
scene: &mut Scene,
world: &mut World,
board: &mut [[[BoardSlot; 3]; 3]; 3],
state: &mut GameState,
) -> Result<Option<MillState>> {
@ -668,8 +664,8 @@ impl MillGame {
LogSeverity::Debug,
);
let slot = &board[x][y][z];
let neighbour = &board[tx][ty][tz];
let slot = &mut board[x][y][z];
let neighbour = &mut board[tx][ty][tz];
if neighbour.state() != BoardSlotState::Empty
|| !Self::is_neighbour((x, y, z), (tx, ty, tz))
@ -681,7 +677,7 @@ impl MillGame {
neighbour.set_state(slot.state());
slot.set_state(BoardSlotState::Empty);
scene
world
.entity_mut(match neighbour.state() {
BoardSlotState::Black(e) => {
Self::log(
@ -730,7 +726,7 @@ impl MillGame {
Ok(Some(millstate))
}
pub fn remove_stone(stone: &mut Stone, slot: &mut BoardSlot, scene: &mut Scene) -> Result<()> {
pub fn remove_stone(stone: &mut Stone, slot: &mut BoardSlot, world: &mut World) -> Result<()> {
Self::log("remove_stone", LogSeverity::Debug);
let entity = match slot.state() {
@ -761,7 +757,7 @@ impl MillGame {
_ => unreachable!(),
};
scene.remove_entity(entity)?;
world.remove_entity(entity);
assert_ne!(stone.state, StoneState::Dead);
stone.state = StoneState::Dead;
@ -831,30 +827,21 @@ impl MillGame {
MillState::None
}
fn check_mouse_click<F>(&self, f: F) -> Result<()>
fn check_mouse_click<F>(&mut self, scene: &Scene, f: F) -> Result<()>
where
F: FnOnce(
&Self,
(usize, usize, usize),
&mut [[[BoardSlot; 3]; 3]; 3],
&mut Scene,
) -> Result<()>,
F: FnOnce(&Self, (usize, usize, usize), &mut [[[BoardSlot; 3]; 3]; 3]) -> Result<()>,
{
Self::log("check_mouse_click", LogSeverity::Debug);
self.scene.lock().unwrap().on_scene(|scene| {
if let Some(world_space) = scene.screen_space_to_world(self.mouse_x, self.mouse_y)? {
let mut board = self.board.lock().unwrap();
if let Some(slot) = board.close_to_marker(world_space.truncate()) {
if let Some(slot) = self.board.close_to_marker(world_space.truncate()) {
Self::log("click is close to marker", LogSeverity::Debug);
f(self, (slot.x, slot.y, slot.z), board.slots(), scene)?;
f(self, (slot.x, slot.y, slot.z), self.board.slots_mut())?;
}
}
Ok(())
})
}
fn is_neighbour((x, y, z): (usize, usize, usize), (tx, ty, tz): (usize, usize, usize)) -> bool {
@ -904,7 +891,7 @@ impl MillGame {
if me.turn_finished {
if (me.last_turn_timing + Self::TURN_WAIT_TIME) < now {
me.turn_finished = false;
me.next_game_step()?;
me.next_game_step(world)?;
}
}
@ -919,28 +906,28 @@ impl EventConsumer for MillGame {
self.mouse_x = x;
self.mouse_y = y;
self.camera_controls.lock().unwrap().mouse_move(
x,
y,
&mut *self.scene.lock().unwrap(),
)?;
let mut resources = world.resources.multi_mut();
let camera_controls = resources.get::<TopDownCameraControl>();
let scene = resources.get::<Scene>();
camera_controls.mouse_move(x, y, scene.view_mut())?;
}
EngineEvent::MouseButtonDown(button) => {
match button {
EngineEvent::MouseButtonDown(button) => match button {
MouseButton::Left => {
let mut state = self.state.lock().unwrap();
Self::log(
&format!("User click at state {:?}", state),
&format!("User click at state {:?}", self.state),
LogSeverity::Debug,
);
match *state {
match self.state {
GameState::Placing => {
self.check_mouse_click(|me, (x, y, z), board, scene| {
let current_player = *me.current_player.lock().unwrap();
let mut resources = world.resources.multi_mut();
self.check_mouse_click(
resources.get::<Scene>(),
|me, (x, y, z), board| {
if let Some(placable) = me
.stones(current_player)
.stones(me.current_player)
.iter_mut()
.find(|stone| stone.state == StoneState::ReadyToBePlaced)
{
@ -949,12 +936,12 @@ impl EventConsumer for MillGame {
placable,
(x, y, z),
board,
current_player,
scene,
&mut *state,
me.current_player,
world,
&mut self.state,
)? == MillState::None
{
me.finish_turn();
me.finish_turn(world);
}
} else {
Self::log(
@ -969,28 +956,32 @@ impl EventConsumer for MillGame {
}
Ok(())
})?;
},
)?;
}
GameState::Removing => {
self.check_mouse_click(|me, (x, y, z), board, scene| {
let mut resources = world.resources.multi_mut();
self.check_mouse_click(
resources.get::<Scene>(),
|me, (x, y, z), board| {
let slot = &mut board[x][y][z];
Self::log(
&format!(
"state {:?} - player {:?}",
slot.state(),
*me.current_player.lock().unwrap()
me.current_player
),
LogSeverity::Debug,
);
if match (slot.state(), *me.current_player.lock().unwrap()) {
if match (slot.state(), me.current_player) {
(BoardSlotState::Black(_), PlayerColor::White) => true,
(BoardSlotState::White(_), PlayerColor::Black) => true,
_ => false,
} {
let mut stones =
self.stones(me.current_player.lock().unwrap().other());
let mut stones = self.stones(me.current_player.other());
let stone = stones
.iter_mut()
@ -1004,28 +995,27 @@ impl EventConsumer for MillGame {
})
.unwrap();
Self::remove_stone(stone, slot, scene)?;
Self::remove_stone(stone, slot, world)?;
me.finish_turn();
me.finish_turn(world);
}
Ok(())
})?;
},
)?;
}
GameState::Main => {
self.check_mouse_click(|me, (tx, ty, tz), board, scene| {
let mut selected_slot = me.selected_field.lock().unwrap();
let mut resources = world.resources.multi_mut();
match *selected_slot {
self.check_mouse_click(resources.get::<Scene>() , |me, (tx, ty, tz), board| {
match me.selected_field {
Some((x, y, z)) => {
if Self::is_neighbour((x, y, z), (tx, ty, tz)) {
if let Some(millstate)
= Self::move_stone((x,y,z), (tx,ty,tz), scene, board, &mut state)? {
= Self::move_stone((x,y,z), (tx,ty,tz), world, board, &mut self.state)? {
if let MillState::None = millstate {
*selected_slot = None;
drop(selected_slot);
self.finish_turn();
me.selected_field = None;
self.finish_turn(world);
}
}
}
@ -1035,7 +1025,7 @@ impl EventConsumer for MillGame {
match (
slot.state(),
*me.current_player.lock().unwrap(),
me.current_player,
) {
(BoardSlotState::Black(_), PlayerColor::Black)
| (BoardSlotState::White(_), PlayerColor::White) => {
@ -1044,7 +1034,7 @@ impl EventConsumer for MillGame {
LogSeverity::Basic,
);
*selected_slot = Some((tx, ty, tz));
me.selected_field = Some((tx, ty, tz));
}
_ => (),
@ -1058,43 +1048,36 @@ impl EventConsumer for MillGame {
GameState::Waiting | GameState::Won(_) => (),
}
}
MouseButton::Middle => self.camera_controls.lock().unwrap().hold(),
MouseButton::Middle => world.resources.get_mut::<TopDownCameraControl>().hold(),
MouseButton::Right => {
let mut selected_slot = self.selected_field.lock().unwrap();
if selected_slot.is_some() {
if self.selected_field.is_some() {
Self::log(
&format!("Released selection ({:?})", selected_slot.unwrap()),
&format!("Released selection ({:?})", self.selected_field.unwrap()),
LogSeverity::Basic,
);
*selected_slot = None;
self.selected_field = None;
}
}
MouseButton::Forward => (),
MouseButton::Backward => (),
}
}
},
EngineEvent::MouseButtonUp(button) => match button {
MouseButton::Left => (),
MouseButton::Middle => self.camera_controls.lock().unwrap().release(),
MouseButton::Middle => world.resources.get_mut::<TopDownCameraControl>().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::MouseWheel(_x, y, direction) => {
let mut resources = world.resources.multi_mut();
let camera_controls = resources.get::<TopDownCameraControl>();
let scene = resources.get::<Scene>();
EngineEvent::KeyDown(_) => (),
EngineEvent::KeyUp(_) => (),
EngineEvent::ButtonDown(_) => (),
EngineEvent::ButtonUp(_) => (),
EngineEvent::ControllerAxis(_) => (),
EngineEvent::ControllerAdded(_) => (),
EngineEvent::ControllerRemoved(_) => (),
EngineEvent::FileDrop(_) => (),
camera_controls.scroll_wheel(y, direction, scene.view_mut())?;
}
_ => (),
}
Ok(())