因為會忘,所以要寫下來

JS地下城:6F-60秒算數遊戲

3 minutes to read

規則

  • 【特定技術】 0 ~ 20 秒為 1 位數計算 (5-3),21 ~ 40 秒為 2 位數計算 (30*19),41 ~ 60 秒為 3 位數計算 (332+312),加減乘除規則請用隨機產生,不可寫 死題目,60 秒內可無限次數答題。 0~40 秒答對加一分,41 ~ 60 秒答對加五分,答錯 扣一分,最多僅能扣到零分

  • 【特定技術】不可設計跳轉頁面,都得在同一頁內部切換頁面完成。


這次使用 vue 挑戰此次的關卡

demo 頁 sourse code


刻畫面

  • 字型載入設計稿所使用的的字型 為 Roboto Condensed 並非電腦裡的內建字型所以需 要到 GoogleFont 裡搜尋後取得字型連結 讓頁面載入使 用

使用 flex 排版 處理畫面

程式開始

畫面切分

將畫面拆分成三個子組件分別為初始畫面 start 遊戲進行 play 遊戲結束 end

  • 雷 1 原本是使用 display 的 block 跟 none 做作畫面切換後來發現在程式執行時 三個 畫面會同時執行(這不是我要的結果 rrrrr) 試了許多方式後,改用 v-if v-else 後 才能分別執行

template 如下

var vm = new Vue({
  el: '#app',
  data: {
    page: 'start',
  },
  template: `
    <div>
      <start v-if="page === 'start'" />
      <play v-else-if="page === 'play'" />
      <end v-else="page === 'end'" />
    </div>``
  `,
});

當 data 裡的 page ==‘start’ 時則 start 的畫面就會顯示,其他兩個畫面則不會顯示在 html 裡 code 也不會存在

倒數計時

這裡我選用 setTimeout 做倒數計時或許是因為對程式還沒很熟練 這部份我寫了好久

methods 裡做一個 countdown 的函式 處理倒數計時

countdown(){
  let t;
  if( --this.time === 0 ){
    clearTimeout(t);
  }else{
    t = setTimeout( this.countdown, 1000 );
  }
}

這裡學到了另一種運算式的處理方式

假如 x 是 3,那 —x 將把 x 設定為 2 並回傳 2,而 x— 會回傳 3 , 接著才把 x 設 定為 2。

可參考 :MDN-運算式與運算子

另一種方式(過去常用的方式)

countdown(){
  let t;
  if( this.time === 0 ){
    clearTimeout(t);
  }else{
    this.time--;
    t = setTimeout( this.countdown, 1000 );
  }
}
  • 雷 2 之前在 computed 裡做 發現倒數計時跳很快,後來才想到 computed 會根 據data裡面的數值變動 自動執行程式 才會導致時間錯亂

亂數取值

之前在 js30 天的最後一個單元 有練 習到亂數取值所以就直接將程式拿來用了

randTime(min, max) {
  return Math.round(Math.random() * (max - min) + min);
}

題目製作

再來就是一連串的算式處理了

數字 跟 加減乘除 都跑亂數

過程中也有使用過 eval 處理數字運算但爬了文後 文裡都說 避免在不必要的情况下使用 eval

所以就選用 if else 的處理方式

在題目處理上 我這裡過濾掉了一些題目答案裡有小數點的 、除不盡的 、 負數的

遇到這些題目 就回傳 重新再跑一次

答題得分

這裡使用 input v-model 跟答案做比對輸入的數值跟 答案一樣 就加分,不一樣就減 分將分數紀錄到 play 子組件裡的 score 等到 countdown 倒數計時時間為 0 秒時 再將 score的分數 回傳到父組件 做記綠( 因為要給end子組件取分 )

  • 雷 3( 雙向綁定 子組件溝通 ) 之前以為 只要直接改子組件 data 裡的值 父組件也會跟 著改 結果發現 console 裡一直報錯 所傳的值也並非我預期(被 vuex 寵壞了) 後來估狗 了一下 要使用 this.$emit 方式才能將子組件裡的值 回傳到父組件 供其他子組件取 用

父組件

<play @getscore="getscore"></play>
data:{
  score: '',
},
methods: {
  getscore( data ){
    this.score = data;
  },
},

子組件 將值傳到父組件

// this.$emit('綁定名稱',值);
this.$emit('getscore', this.score);

40 秒前 跟 40 秒後的計分方式有改變,且題目也有變動所以在 40 前出現的題目 超過 40 秒後答完題 一樣也是 40 秒前的計分方式

所以我多加了題目判斷當題目還是 2 位數時 跟 40 秒前的處理方式是一樣的

  • 雷 4 .lengthnumber 型態處理時 會出現undefined,必須先轉字串後 才能得 到所要的長度

到這裡就處理的差不多囉再來就是遊戲測試囉 以上!如有更好的建議 或 寫法上有錯誤 不 吝賜教 感謝您花時間觀看

後記

有些地方還能再更優化些倒數計時上可以改時間方式處理

對這篇文章有什麼想法嗎?

Copyright © 2023 Mandy. All rights reserved. Build with Astro