Impl main menu
Only "LocalMultiplayer" can be chosen for the game-mode since neither AI nor Networked-Multiplayer has been implemented yet.
This commit is contained in:
parent
20d9562aa8
commit
130cc42d86
3 changed files with 184 additions and 9 deletions
|
@ -4,6 +4,44 @@
|
|||
<meta charset="utf-8" />
|
||||
<title>Four-Line Dropper</title>
|
||||
<style>
|
||||
b {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
div.menu {
|
||||
background-color: #555;
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
left: 25%;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 8px;
|
||||
grid-auto-rows: 33%;
|
||||
}
|
||||
button.menuSinglePlayer {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
}
|
||||
button.menuLocalMultiplayer {
|
||||
grid-row: 2;
|
||||
grid-column: 3;
|
||||
}
|
||||
button.menuMultiplayer {
|
||||
grid-row: 2;
|
||||
grid-column: 4;
|
||||
}
|
||||
b.menuText {
|
||||
color: #FFF;
|
||||
grid-row: 1;
|
||||
grid-column: 2 / 5;
|
||||
line-height: 64px;
|
||||
text-align: center;
|
||||
}
|
||||
div.hidden_menu {
|
||||
display: none;
|
||||
}
|
||||
div.wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 50px) 400px;
|
||||
|
|
|
@ -2,6 +2,21 @@ use std::cell::Cell;
|
|||
use std::fmt::Display;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum GameState {
|
||||
MainMenu,
|
||||
SinglePlayer,
|
||||
LocalMultiplayer,
|
||||
NetworkedMultiplayer,
|
||||
PostGameResults(Turn),
|
||||
}
|
||||
|
||||
impl Default for GameState {
|
||||
fn default() -> Self {
|
||||
GameState::MainMenu
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum BoardState {
|
||||
Empty,
|
||||
|
@ -83,6 +98,7 @@ impl Turn {
|
|||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SharedState {
|
||||
pub board: [Rc<Cell<BoardState>>; 56],
|
||||
pub game_state: Rc<Cell<GameState>>,
|
||||
pub turn: Rc<Cell<Turn>>,
|
||||
}
|
||||
|
||||
|
@ -148,6 +164,7 @@ impl Default for SharedState {
|
|||
Rc::new(Cell::new(BoardState::default())),
|
||||
Rc::new(Cell::new(BoardState::default())),
|
||||
],
|
||||
game_state: Rc::new(Cell::new(GameState::default())),
|
||||
turn: Rc::new(Cell::new(Turn::CyanPlayer)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,93 @@
|
|||
use crate::constants::{COLS, INFO_TEXT_MAX_ITEMS, ROWS};
|
||||
use crate::state::{BoardState, SharedState};
|
||||
use crate::state::{BoardState, GameState, SharedState, Turn};
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
use yew::prelude::*;
|
||||
|
||||
pub struct MainMenu {}
|
||||
|
||||
pub enum MainMenuMessage {
|
||||
SinglePlayer,
|
||||
LocalMultiplayer,
|
||||
NetworkedMultiplayer,
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<GameState> for MainMenuMessage {
|
||||
fn into(self) -> GameState {
|
||||
match self {
|
||||
MainMenuMessage::SinglePlayer => GameState::SinglePlayer,
|
||||
MainMenuMessage::LocalMultiplayer => GameState::LocalMultiplayer,
|
||||
MainMenuMessage::NetworkedMultiplayer => GameState::NetworkedMultiplayer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for MainMenu {
|
||||
type Message = MainMenuMessage;
|
||||
type Properties = ();
|
||||
|
||||
fn create(_ctx: &Context<Self>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let (shared, _) = ctx
|
||||
.link()
|
||||
.context::<SharedState>(Callback::noop())
|
||||
.expect("state to be set");
|
||||
match shared.game_state.get() {
|
||||
GameState::MainMenu => {
|
||||
let onclick_local_multiplayer =
|
||||
ctx.link().callback(|_| MainMenuMessage::LocalMultiplayer);
|
||||
html! {
|
||||
<div class={"menu"} id={"mainmenu"}>
|
||||
<b class={"menuText"}>{"Please pick a game mode."}</b>
|
||||
<button class={"menuSinglePlayer"}>
|
||||
{"Singleplayer"}
|
||||
</button>
|
||||
<button class={"menuLocalMultiplayer"} onclick={onclick_local_multiplayer}>
|
||||
{"Local Multiplayer"}
|
||||
</button>
|
||||
<button class={"menuMultiplayer"}>
|
||||
{"Networked Multiplayer"}
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
_ => html! {
|
||||
<div class={"hidden_menu"} id={"mainmenu"}>
|
||||
</div>
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
let (shared, _) = ctx
|
||||
.link()
|
||||
.context::<SharedState>(Callback::noop())
|
||||
.expect("state to be set");
|
||||
let window = web_sys::window().expect("no window exists");
|
||||
let document = window.document().expect("window should have a document");
|
||||
|
||||
shared.game_state.replace(msg.into());
|
||||
if shared.game_state.get() != GameState::MainMenu {
|
||||
let mainmenu = document
|
||||
.get_element_by_id("mainmenu")
|
||||
.expect("mainmenu should exist");
|
||||
mainmenu.set_class_name("hidden_menu");
|
||||
mainmenu.set_inner_html("");
|
||||
|
||||
let info_text_turn = document
|
||||
.get_element_by_id("info_text1")
|
||||
.expect("info_text1 should exist");
|
||||
info_text_turn.set_inner_html("<p><b class=\"cyan\">It is CyanPlayer's Turn</b></p>");
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Slot {}
|
||||
|
||||
pub enum SlotMessage {
|
||||
|
@ -39,6 +123,15 @@ impl Component for Slot {
|
|||
}
|
||||
|
||||
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
||||
let (shared, _) = ctx
|
||||
.link()
|
||||
.context::<SharedState>(Callback::noop())
|
||||
.expect("state to be set");
|
||||
|
||||
if shared.game_state.get() == GameState::MainMenu {
|
||||
return false;
|
||||
}
|
||||
|
||||
match msg {
|
||||
SlotMessage::Press(idx) => {
|
||||
// notify Wrapper with message
|
||||
|
@ -74,6 +167,7 @@ impl Component for Wrapper {
|
|||
.expect("state to be set");
|
||||
html! {
|
||||
<div class="wrapper">
|
||||
<MainMenu />
|
||||
<Slot idx=0 state={shared.board[0].clone()} />
|
||||
<Slot idx=1 state={shared.board[1].clone()} />
|
||||
<Slot idx=2 state={shared.board[2].clone()} />
|
||||
|
@ -302,6 +396,10 @@ impl Component for InfoText {
|
|||
}
|
||||
|
||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||
let (shared, _) = ctx
|
||||
.link()
|
||||
.context::<SharedState>(Callback::noop())
|
||||
.expect("state to be set");
|
||||
match ctx.props().id {
|
||||
0 => {
|
||||
html! {
|
||||
|
@ -311,6 +409,17 @@ impl Component for InfoText {
|
|||
}
|
||||
}
|
||||
1 => {
|
||||
if shared.game_state.get() == GameState::MainMenu {
|
||||
html! {
|
||||
<div id={format!("info_text{}", ctx.props().id)} class={format!("info_text{}", ctx.props().id)}>
|
||||
<p>
|
||||
<b>
|
||||
{"Waiting to choose game-mode..."}
|
||||
</b>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
} else if shared.turn.get() == Turn::CyanPlayer {
|
||||
html! {
|
||||
<div id={format!("info_text{}", ctx.props().id)} class={format!("info_text{}", ctx.props().id)}>
|
||||
<p>
|
||||
|
@ -320,6 +429,17 @@ impl Component for InfoText {
|
|||
</p>
|
||||
</div>
|
||||
}
|
||||
} else {
|
||||
html! {
|
||||
<div id={format!("info_text{}", ctx.props().id)} class={format!("info_text{}", ctx.props().id)}>
|
||||
<p>
|
||||
<b class={"magenta"}>
|
||||
{"It is MagentaPlayer's turn"}
|
||||
</b>
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
|
|
Loading…
Reference in a new issue