[實作] 打字遊戲

學習到的知識點

CSS

  • display:none
  • display:flex

JS

  • Math.length()
  • Math.floor()
  • setInterval()

簡介

Demo

打字遊戲

HTML

結構

這邊的結構十分清楚,沒有特別困難的點。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<button id="settings-btn" class="settings-btn">
<i class="fas fa-cog"></i>
</button>

<div id="settings" class="settings">
<form id="settings-form">
<div>
<label for="difficulty">Difficulty</label>
<select id="difficulty">
<option value="easy">Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</select>
</div>
</form>
</div>

<div class="container">
<h2>💻 Speed Typer ⌨️</h2>
<small>Type the following:</small>

<h1 id="word"></h1>

<input
type="text"
id="text"
autocomplete="off"
placeholder="Type the word here..."
/>

<p class="time-container">Time left: <span id="time">10s</span></p>

<p class="score-container">Score: <span id="score">0</span></p>

<div id="end-game-container" class="end-game-container"></div>
</div>

CSS

  • -webkit- 私有前綴
  • -webkit-appearance: none,去除瀏覽器的預設樣式。
1
2
3
4
5
6
7
8
9
select {
width: 200px;
padding: 5px;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
border-radius: 0;
background-color: #a7c5e3;
}

JS

宣告變數 Declare varialbe

原生 Js

這邊使用陣列儲存測驗單字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const word = document.getElementById("word");
const text = document.getElementById("text");
const scoreEl = document.getElementById("score");
const timeEl = document.getElementById("time");
const endgameEl = document.getElementById("end-game-container");
const settingsBtn = document.getElementById("settings-btn");
const settings = document.getElementById("settings");
const settingsForm = document.getElementById("settings-form");
const difficultySelect = document.getElementById("difficulty");

// List of words for game
const words = [
"sigh",
"tense",
"airplane",
"ball",
"pies",
"juice",
"warlike",
"bad",
"north",
"dependent",
"steer",
"silver",
"highfalutin",
"superficial",
"quince",
"eight",
"feeble",
"admit",
"drag",
"loving",
];

// Init word
let randomWord;

// Init score
let score = 0;

// Init time
let time = 10;

Jquery

選擇器

1
2
3
4
5
6
7
8
9
$("#word")
$("#text")
$("#score")
$("#time")
$("#end-game-container")
$("#settings-btn")
$("#settings")
$("#settings-form")
$("#difficulty")

隨機挑選陣列裡的單字,加到元素的div裡

getRandomWord()
addWordToDOM()

原生 Js

  • Math.random()函式,會隨機產生出0~1之間的小數,出來的值永遠不會大於1。
  • Math.floor()函式會無條件捨去到比自身小的最大整數。ex 4.6213 回傳 4
  • words.length是20,乘上隨機0-1之間的數,再取整數。

1
2
3
4
5
6
7
8
9
10
11
12
13
// Generate random word from array
function getRandomWord() {
//回傳隨機的字
return words[Math.floor(Math.random() * words.length)];
}

//Add word to DOM 將取得的字,放到#word裡。
function addWordToDOM() {
randomWord = getRandomWord();
word.innerHTML = randomWord;
}

addWordToDOM();

Jquery

  1. 原生JS是用打好的陣列,再去取得測驗字。
  2. 這裡使用實作無限滾動頁面取的API的方法(搜尋random word api),得到測驗字串。
  3. 再直接將得到的字串放入#word裡。

使用$.ajax方法。

1
2
3
4
5
6
7
8
9
10
function getRandomWord() {
$.ajax({
url: "https://random-word-api.herokuapp.com/word?number=1",
method: "get",
dataType: "json",
success: function (data) {
$("#word").text(data);
},
});
}

更新成績,判斷輸入的字是否符合出現的字

updateScore()

addEventListenerinput不需要按下Enter就會直接輸入。

判斷輸入是正確後,會直接清空輸入框。

原生 Js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Update score 更新成績
function updateScore() {
score++;
scoreEl.innerHTML = score;
}

addWordToDOM();

// Event listeners

// Typing
text.addEventListener("input", (e) => {
//取得輸入的值
const insertedText = e.target.value;
//如果輸入的值與隨機單字相同
if (insertedText === randomWord) {
//更新成績+更換下一個隨機單字,更新成績
addWordToDOM();
updateScore();

// Clear
//輸入正確,自動清空輸入框,增加體驗
e.target.value = "";
}
});

Jquery

  • .innerHTML = 轉成 .html
  • text.addEventListener("input"轉成 $("#text").on("input"
  • e.target.value 轉成 $(this).val()
  • e.target.value = "" 轉成 $(this).val("")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function updateScore() {
score++;
$("#score").html(score);
}

$("#text").on("input", function () {
const insertedText = $(this).val();
const randomWord = $("#word").text();
if (insertedText === randomWord) {
updateScore();
getRandomWord();
$(this).val("");
}
});

每秒更新倒數狀態,倒數到0時,出現gameOver Panel

原生 Js

updateTime()
gameOver()

  • setInterval()固定延遲了某段時間之後,才去執行對應的程式碼,然後「不斷循環」。
  • 使用setInterval()才會開始倒數,少了這一行,time變數就不會更動。
  • 秒數歸0時,在css預先寫好的style,讓他出現(display:flex),預設為(display:none)。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // Start counting down
    const timeInterval = setInterval(updateTime, 1000);

    // Update time
    function updateTime() {
    time--;
    timeEl.innerHTML = time + "s";
    // 等於0時,呼叫gameOevr()
    if (time === 0) {
    clearInterval(time);
    //end the game
    gameOver();
    }
    }

    // Game over,show end screen
    // 顯示GameOver的Panel
    function gameOver() {
    endgameEl.innerHTML = `
    <h1>Time ran out</h1>
    <p>Your final score is ${score}</p>
    <button onclick="location.reload()">Reload</button>
    `;

    endgameEl.style.display = "flex";
    }

Jquery

  • .style.display =轉成.css("display", "flex")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const timeInterval = setInterval(updateTime, 1000);

function updateTime() {
var timeEl = $("#time");
time--;
timeEl.html(time + "s");
if (time === 0) {
clearInterval(time);
gameOver();
}
}

function gameOver() {
const endgameEl = $("#end-game-container");
endgameEl.html(`
<h1>Time ran out</h1>
<p>Your final score is ${score}</p>
<button onclick="location.reload()">Reload</button>
`);

endgameEl.css("display", "flex");
}

用Localstorge去設定與判斷使用者選的難度

原生Js

  • 宣告difficulty變數,並且做判斷。如果困難度為空,就從localStorage取得值,如果沒有值,就預設medium
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Set difficulty to value in localStorage or medium
let difficulty =
localStorage.getItem("difficulty") !== null
? localStorage.getItem("difficulty")
: "medium";

// Set difficulty select value
difficultySelect.value =
localStorage.getItem("difficulty") !== null
? localStorage.getItem("difficulty")
: "medium";

// 依照不同的困難度,增加不同的時間。
if (difficulty == "hard") {
time += 3;
} else if (difficulty == "medium") {
time += 4;
} else {
time += 6;
}

updateTime();

Jquery

  • .value = 轉成 .val
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let difficulty =
localStorage.getItem("difficulty") !== null
? localStorage.getItem("difficulty")
: "medium";

$("#difficulty").val(
localStorage.getItem("difficulty") !== null
? localStorage.getItem("difficulty")
: "medium"
);

if (difficulty == "hard") {
time += 3;
} else if (difficulty == "medium") {
time += 6;
} else {
time += 8;
}
updateTime();

設定與下拉選單的事件監聽

Js

1
2
3
4
5
6
7
8
9
10
// Settings btn click
// 按下左下角的齒輪,可以收合settings面板。
settingsBtn.addEventListener("click", () => settings.classList.toggle("hide"));

// Settings select
// 下拉式選單改變時,將值儲存在localStorage
settingsForm.addEventListener("change", (e) => {
difficulty = e.target.value;
localStorage.setItem("difficulty", difficulty);
});

Jquery

  • .classList.toggle() 轉成 .toggleClass()
  • .target.value 轉成 .val()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $("#settings-btn").on("click", function () {
    $("#settings").toggleClass("hide");
    });

    $("#settings-form").on("click", function () {
    difficulty = $("#difficulty").val();
    localStorage.setItem("difficulty", difficulty);
    });

參考文章

許多內容都跟之前的實作有重複,都是參考之前的筆記XD。


[實作] 打字遊戲
https://phoebeho.com/Portfolio/20210128/301319586/
作者
Phoebe
發布於
2021年1月28日
許可協議