]> git.seodisparate.com - EN605.607.81.SP22_ASDM_Project/commitdiff
Impl main menu
authorStephen Seo <seo.disparate@gmail.com>
Fri, 4 Mar 2022 07:22:30 +0000 (16:22 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 4 Mar 2022 07:22:30 +0000 (16:22 +0900)
Only "LocalMultiplayer" can be chosen for the game-mode since neither
AI nor Networked-Multiplayer has been implemented yet.

front_end/index.html
front_end/src/state.rs
front_end/src/yew_components.rs

index b59827ba61554183503e813b645cf2d659fcf27e..d53901431301468d6f518c29a0fb6d174dfc1709 100644 (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;
index 4966d9bd5fd697cc0622bb6743d8749f4b0419bf..82780e26675fbddbc523524f1e9b585d2eed677d 100644 (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)),
         }
     }
index 817f28d35fccb090fd367c863964109d209aebf9..8f92889bf8f1b353ce16ae29cc745de413b9b7db 100644 (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>
+                    }
                 }
             }
             _ => {