[Hero Of UnderGround 地下城] — 6F SECONDS CHALLENGE 倒數遊戲

RexHung
14 min readMar 13, 2019

--

成果 & 程式碼

Demo:點我
Code Source:點我

Introduction & 前言

混了一個禮拜(誤,這次要勇闖6F,記得剛看到這層的時候也是抱著一樣的想法,完蛋了。感覺需要用到大量JS,但時常發現,會弄到的東西,就差不多那一些了(或許是我還太菜?!

6F的大魔王- 60秒算數遊戲

Summary & 摘要

由於JS地下城每個BOSS的弱點都不一樣,每一層都要由弱點去進行攻略,本次BOSS的弱點有二 項。

  • 【特定技術】遊戲規則
    a.0~20 秒為 1位數計算 (5–3),21~40 秒為 2 位數計算 (30*19),41~60 秒為 3 位數計算 (332+312),加減乘除規則請用隨機產生,不可寫死題目,60 秒內可無限次數答題。
    b.0~40 秒答對加一分,41~60 秒答對加五分,答錯扣一分,最多僅能扣到零分
  • 【特定技術】不可設計跳轉頁面,都得在同一頁內部切換頁面完成。

額外條件

  1. 你攻略此 BOSS 的攻略過程心得
  2. 如果你是駭客,是否能透過 console 執行 JS ,逆向工程讓自己在遊戲上獲得 999 分以上
  3. 承 2,如何寫出具備資訊安全的 JS 程式?可思考純 JS 解法,或結合後端設計
  4. 延伸擴充功能,例如線上排行榜、雙人遊戲
這邊使用display:none方式

畫面製作

一開始看見BOSS的弱點不可設計跳轉頁面就決定要使用 display:none 來做視覺上的頁面切換了,我把它分為三部分。
Step1 → before-play
Step2 → play
Step3 → end-game

這邊還學到了 marquee 跑馬燈的方法,每次切新的版面就會花大把時間在美觀上呀…(參數設定請參考這邊

<marquee 這裡放參數設定>這裡放要跑的文字</marquee>

後更

跑馬燈部分有部分瀏覽器不支持及安全性問題,不建議使用,如果需要建議自己使用 JS 寫一個跑馬燈。這邊特別感謝 曾琬庭 大大的留言,她自己寫了一個跑馬燈,點我查看。

關於開始及setTimeout

$('body').keydown(function(e) { //body可替換成你要的目標
if (e.keyCode == 32) { //空白鍵的keyCode為32
$('.step1-box').hide();
$('.before-star-box').show();
beforeStarCount(); //進入倒數畫面
}
}); //e為event
$('.step1-box').hide();
$('.before-star-box').show();
beforeStarCount(); //進入倒數畫面
}
}); //e為event

這邊想到了上次在3F的計算機有人使用了鍵盤監聽的功能,便拿一開始的開始鍵做嘗試啦,關於 KeyCode 點我查看。

因為怕玩家沒有準備還有畫面太單調,我在開始前加入了倒數的畫面,並且使用了 SetTimeout() 以及音樂播放。

倒數畫面
function beforeStarCount() {
setTimeout(function() {

$(‘.before-star-text’).html(starTime);
$(‘.before-star-box’).addClass(‘animated zoomIn’);
}, 500)
//這邊可以加上自己的CSS或動畫
.
.
.
setTimeout(function() {
$('.before-star-box').hide(); /
/隱藏倒數畫面
$('.step2-box').show();
//顯示遊戲畫面
BgMusic[0].play();
//播放音樂
StarGame();
//開始遊戲
print_number()
//產生第一組隨機數字
}, 3500)

關於setTimeout()及setInterval()

很多人認為一個是執行一次,而另一個就是自動重複執行只有這樣的差別,其實更深入的還有其他差別,但是兩種都有結束方式。
setTimeout() → 執行一次
setInterval() → 循環執行
clearTimeout() → 結束
clearInterval() → 結束

setTimeout 所設定的程式碼,會因為目前任務佇列所執行的程式碼而可能發生延誤執行的狀況,setInterval 是一開始就標定了執行時間點,當所註冊的函式(func)超過執行的時間點,結束時則會馬上觸發(func)。

兩種其實都有延遲,但是 setTimeout 延遲了少許,在實驗中結束與開始的兼具至少是我們所設定的時間,相關文章請點我

var interval = setInterval(() => {
count_time--;
//開始倒數
if (count_time > 9) {
$('.count-time').html('00 :' + ' ' + count_time);
} else {
$('.count-time').html('00 :' + ' 0' + count_time);
}
if (count_time <= 0) {
$('.count-time').html('00 : 00');
BgMusic[0].pause();
timeout[0].play();
//清除自動倒數的函式
clearInterval(interval);
.
.
.
}, 1000);

遊戲開始後的倒數這邊採用 setInterval 因為我們要讓他重複執行,進而去抓取時間另外設定其他我們要做的事情。

善用Math.round()及Math.random()

關於兩者的詳細用法可以點我參考

Math.round() → 傳回四捨五入的整數
Math.random() → 傳回介於0~1間的亂數

//產生隨機數字
function number(min, max) {
return Math.round(Math.random() * (max - min) + min);
}

簡單來說就是取你所設定的數字範圍(min~max),最後加上min是為了不讓他小於一,乘上 Math.random() 後在四捨五入,最終取得我們要的區間。

function print_number() {
let question_number_1 = 1;
//給要取得的區間一個變數
let question_number_2 = 1;
//給要取得的區間一個變數
//判斷秒數並抓取隨機不等於零的亂數
if (count_time >= 40) {
//取個位數
num1 = 1;
num2 = 9;
num3 = 1;
num4 = 9;
} else if (count_time >= 20) {
//取雙數
num1 = 1;
num2 = 99;
num3 = 1;
num4 = 99;
} else if (count_time >= 0) {
//取三位數
num1 = 1;
num2 = 999;
num3 = 1;
um4 = 999;
}
question_number_1 = number(num1, num2)
question_number_2 = number(num3, num4)
.
.
.
//換上隨機取得的數字及符號
$('.question-number-1').html(question_number_1);
$('.question-number-2').html(question_number_2);
}

這邊可以狠狠地打擊BOSS的第一個弱點,我的想法是40~60s應該是最簡單的一位數(4+4),20~40s是中階二位數(10x20),最後0~20s是最難的三位數部分(200÷100),跟題目有點相反,但我想這樣比較符合玩家的流程!?

裡面還能加上自己的判斷,例如 question_number_1 < question_number_2 又是減的運算符號的話,就重抓一次,如果question_number_1 % question_number_2 != 0 的話就是不整除,一樣再重抓一次。

function gotsign() {
let plus = '+';
let minus = '-';
let multiplied = 'x';
let divide = '÷';
//隨機抓取四個運算符號
let
sign = ['+', '-', 'x', '÷'];
let signnumber = Math.floor(Math.random() * 4)
.
.
.
return sign[signnumber];
}

另外運算符號的部分我們一樣用 Math.random() 並且採用陣列方式,不得不說陣列真的很好用啊,初學JS幾個月的我應該要更努力專研,有效大幅精簡我的程式碼。
另外我們可以再給運算符號一個變數,例如 ’+’ = 1,’-’ = 2…等,讓我們去判斷抓取的是哪一個符號,最後能在最一開始的 print_number() function 裡去判斷這個運算符號是不是抓取第二次了。

平均抽取的機率

因為我們重抓一次的關係,除號和減號可能大幅降低被選中的機率,也可以說是被濾掉了,這邊我們可以再給他另一個變數。

function print_number() {
.
.
.
if (again == false) {
//判斷是不是因為答案為負數或是除不盡而重來的變數
sign = gotsign()
} else {
sign = again_sign;
//這邊裝重來的運算符號
sign_code = again_code;
//這邊裝重來的運算符號自己取的代號
}

//判斷是否前一個數字小於後面以至於相減為負數
if (question_number_1 < question_number_2) {
again = true;
//讓式子去判斷因為我們的條件而重來
again_sign = '-';
//這邊裝重來的運算符號
again_code = 2;
//這邊裝重來的運算符號自己取的代號
print_number()
return;
}
//判斷是否前一個數字小於後面以至於除不盡及相除不等於零
if (question_number_1 < question_number_2 || question_number_1 % question_number_2 != 0) {
again = true;
again_sign = '÷';
//這邊裝重來的運算符號
again_code = 4;
//這邊裝重來的運算符號自己取的代號
print_number()
return;
}
.
.
.
}

監聽事件

送出答案的部分和我們設定開始的按鈕一模一樣,關於 KeyCode 請再次點我查看。

關於分數那點事
$('body').keydown(function(e) {
//這邊加上第二個enter_keydown防止在其他頁面按下Enter
if (e.keyCode == 13 && enter_keydown) {
//判斷分數的位數
if ($('.answer-input').val() == answer) {
//判斷時間後答對加分
if (count_time >= 20) {
score++;
//答對加一分
} else if (count_time > 0 && count_time < 20) {
//小於20秒答對加五分
score += 5;
}
.
.
.
//答錯的部分
} else {
if (count_time >= 0 && score > 0) {
score--;
if (score > 0 && score < 10) {
$('.score-box').html('00' + score);
return;
} else if (score > 9 && score < 100) {
$('.score-box').html('0' + score);
return;
} else {
$('.score-box').html('000');
return;
}
}
}
}
999大神(其實自己偷改的

最後因為結束的頁面 Class 跟我分數欄的 Class命名一樣,所以不需要特別去做設定,這邊深刻體會到命名的重要性。
而按下重玩的案件就把所有的變數回到原樣就好了,一切就會重來,而有考慮到要弄個線上排行榜出來,不過我想那個需要動到資料庫(或許我太菜?!),想想等以後比較熟悉了再回過頭來,我想那時候在看這時候自己寫的文章還有Code都會暈倒吧哈。

關於資訊安全

資訊安全

我們都聽說過 XSS(Cross Site Script,跨站點腳本編制,也稱為跨站腳本攻擊),指的是攻擊者向合法的 Web 頁面中插入惡意腳本代碼(通常是 HTML 代碼和 JavaScript 代碼)然後提交請求給服務器,隨即服務器響應頁面即被植入了攻擊者的惡意腳本代碼,攻擊者可以利用這些惡意腳本代碼進行會話劫持等攻擊…詳全文

關於資訊安全的部分,菜雞如我其實一竅不通,不過我們秉持著不懂就爬文的精神,慢慢去增廣見聞。JavaScript 其實會被攻擊也會被劫持,攻擊者不免都是要取得更多權限或取得個資等等,而我們能做的即是預防勝過治療,例如自動化檢測 JavaScript 安全漏洞,或是 JavaScript 代碼加密,甚至使用 Dojo、JQuery 等等已經壓縮代碼的第三方 JavaScript 代碼庫。
關於更多JS安全請點我前往,對於資訊安全幼幼班的我會再努力吸取新知更新並補上的。

作品出爐啦

Conclusion & 結論

這次算是免強通關吧,在通關前一樣想著大概又要掛在這層了的想法,不過勇者就是要想盡一切方法通關呀!我想這次讓我成長更多的除了更熟悉 JavaScript 之外,文章也慢慢精簡到重要部分,希望能在近期達到精簡扼要的地步,其實這篇文章打第二次了,暈倒,這邊沒有幫我儲存到…看來我對這個網站還是苦手啊。

另外每次不懂每次爬文就是一次成長,看了看其他人在看自己還是有好大一截需要努力,除了繼續努力之外還是要列出檢討的地方,然後朝下一關繼續加油,完畢。

  • JS
  • 邏輯
  • 文筆
  • 體重

我的其他範例

  • Hero Of UnderGround — 1F Multiplicatio 九九乘法表

Demo:點我
Code Source:點我

  • Hero Of UnderGround — 2F Clock 時鐘

Demo:點我
Code Source:點我

  • Hero Of UnderGround — 3F Calculator 計算機

Demo:點我
Code Source:點我

  • Hero Of UnderGround — 4F World Clock 各國時區

Demo:點我
Code Source:點我
Blog:點我

  • Hero Of UnderGround — 5F AQI 全台空氣指標儀表板

Demo:點我
Code Source:點我
Blog:
點我

參考網站

Mandy大神的Bolg — JS地下城:6F-60秒算數遊戲
W3school 教學網站
camel ‘s blog — 深入了解 setTimeout() 與 setInterval() 的不同之處
維克的煩惱 — Math.random及Math.round的用法
蒂其之死 — 關於JS安全
繁簡轉換
巴哈姆特 舒壓用

--

--

RexHung

菜雞學Code之路,期許自己哪天能成長茁壯。