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:
Stephen Seo 2022-03-04 16:22:30 +09:00
parent 20d9562aa8
commit 130cc42d86
3 changed files with 184 additions and 9 deletions

View File

@ -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;

View File

@ -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)),
}
}

View File

@ -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,14 +409,36 @@ impl Component for InfoText {
}
}
1 => {
html! {
<div id={format!("info_text{}", ctx.props().id)} class={format!("info_text{}", ctx.props().id)}>
<p>
<b class={"cyan"}>
{"It is CyanPlayer's turn"}
</b>
</p>
</div>
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>
<b class={"cyan"}>
{"It is CyanPlayer's turn"}
</b>
</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>
}
}
}
_ => {