以下是这段时间通过学习JavaScript编程语言做出的一个小游戏,如果那里有不恰当的地方欢迎提出建议和评论😄
构建游戏逻辑分析图
开始编码
调整结构
如果现在把项目跑起来,你会发现我们有这几处都需要进行改动。
- 首先,每个玩家的所得分数(
class="score" id="score--0"
和class="score" id="score--1"
)需要进行改动 - 目前还没有开始游戏,需要将游戏中间的骰子🎲隐藏起来。因此我们需要创建一个样式为
.hidden
类来将骰子或其他需要隐藏的元素隐藏起来。
观察HTML结构
找到相应的结构和样式后,现在就可以对它们进行JavaScript
操作了。
过去我们经常使用document.querySelector()
或document.querySelectorAll()
通过返回的数组进行元素的控制。但对于此项目,为了避免样式和操纵元素重复使用,我们使用CSS
中的ID
选择器来对文档进行控制。
在JavaScript
你同样可以使用document.querySelector()
来获取.class
或#ID
元素。例如就像下面这样写:
ini
const btn = document.querySelector('#controlButton');
const bg = document.querySelector('.background-image');
现在你可以使用Javascript
中专门获取CSS中ID
选择器的方法document.getElementById();
不用再刻意去写选择器的名称,就像这样:
ini
const btn = document.getElementById('controlButton');
因此,我们的代码可以写成这样:
script.js
javascript
'use strict';
//选择元素 selecting elements
// #score--0 对应的是第一位玩家所获得的分数
const score0El = document.querySelector('#score--0');
const score1El = document.getElementById('score--1'); // 另一种选择样式为id选择器的一种方式 #score--1 对应的是第二位玩家所获得的分数
const diceEl = document.querySelector('.dice');
// 将两个玩家的所获得分数置空
score0El.textContent = 0;
score1El.textContent = 0;
// 前往对应的style.css文件创建一个隐藏类.hidden
diceEl.classList.add('hidden'); // 隐藏骰子
style.css
css
.hidden{
display: none;
}
保存文件,现在就是游戏刚开始的界面啦
创建掷骰子的功能
首先思考一下掷骰子按钮功能的设计思路,在获取到页面主体上的btn--roll
元素后,接下来就可以为它创建一个点击事件。
在分配骰子🎲的数目时,我们又再一次用到Math.random()
方法生成随机数。因为在随机生成的骰子数有6个,一次对应着dice-1.png
、dice-2.png
等等。为了在摇骰子时将对应的图片调用出来,首先去掉刚才为diceEl
设置的hidden
隐藏样式类,调用diceEl
下的src
属性,利用模版字符串和随机数将对应的骰子图片路径描述出来。
ini
const dice = Math.trunc(Math.random() * 6) + 1;
// 2. Display dice 显示骰子数
diceEl.classList.remove('hidden');
diceEl.src = `dice-${dice}.png`;
按照设定的游戏规则,如果摇到的骰子数是1,那么则切换玩家。现在先不考虑切换玩家的情况,如果摇到的骰子数目不是1,则将摇到骰子数目加到当前的分数中,这里需要创建两个变量,一个是用来记录当前分数的currentScore
,另一个是为后期切换玩家准备的变量activePlayer
。
分析逻辑:
累积摇到的骰子数,需要用currentScore
变量依次将dice
的数字累加上。
另外,currentScore
作为数值变量不能直接传递到文本上,因此需要获取文本上的元素。注意:这里不仅要获取到当前分数在文档中的位置,更要清楚现在是在给哪个玩家加分,因此需要判断玩家的变量activePlayer
。
ini
if (dice !== 1) {
// 如果摇到的骰子数不是1,则将摇到的骰子数目加到当前的分数中。
currentScore += dice;
document.getElementById(`current--${activePlayer}`).textContent = currentScore;
}
当前是两个玩家,这里的计分变量score
应该是一个有两个元素的数组,同时装载着两个不同玩家的分数。
ini
const score = [0, 0];
切换玩家
刚才提到如果骰子数目为1时,就切换给另一个玩家,并且前一个玩家猜想的骰子数目为0。
现在我们想利用最简单的方式,利用activePlayer
来切换玩家。我们在这里为activePlayer
设定的值是1或0,这是因为我们在结构和样式中设定区分两个玩家的名称是score--0
或score--1
。在程序设计后期,如果玩家发生变化,还会涉及到样式的变换。因此设置activePlayer
的初始值非常重要。
假定摇到的骰子数dice
为1,那么则应该切换玩家,下面可以使用三目运算符来表示判断的依据:
ini
activePlayer = activePlayer === 0 ? 1 : 0;
// 如果玩家为第一个,即activePlayer为0,则切换为第二个(activePlayer为1)
// 反过来,如果玩家为第二个,即activePlayer为1,则切换为第一个(activePlayer为0)
简单测试一下,此时当骰子数为1时,虽然样式和左侧第一个玩家的当前分数没有清0,但右侧第二个玩家的当前分数已经开始变化。
让我们将程序设计的更完整些,现在设计换成第二个玩家后应该执行的操作。其中刚刚的currentScore
当前分数变量内的内容应该置空。
javascript
btnRoll.addEventListener('click', function () {
// 1. Generating a random dice roll 随机生成一个骰子数
const dice = Math.trunc(Math.random() * 6) + 1;
console.log(dice);
// 2. Display dice 显示骰子数
diceEl.classList.remove('hidden');
diceEl.src = `dice-${dice}.png`;
// 3. Check for rolled 1: if true, switch to next player
// 检查投掷的数目,如果是1,则交换给另一个玩家
// 检查是否投掷到1的骰子数
if (dice !== 1) {
// 如果摇到的骰子数不是1,则将摇到的骰子数目加到当前的分数中。
currentScore += dice;
document.getElementById(`current--${activePlayer}`).textContent = currentScore;
} else {
// 切换到第二位玩家
currentScore = 0;
document.getElementById(`current--${activePlayer}`).textContent = currentScore;
activePlayer = activePlayer === 0 ? 1 : 0;
}
});
测试刚刚编写的代码:
变换相应玩家的样式和分数
首先,获取两个玩家对应的样式。
ini
const player0El = document.querySelector('.player--0');
const player1El = document.querySelector('.player--1');
关于两个玩家在切换样式时的变化,你可能会想到要先使用player0El.classList.contain('player--active')
方法来检查一下该样式是否存在。在使用classList
下的add()
和remove()
方法来删除和添加样式。
实际上有一个更好的方法来解决这个问题,你可以利用classList
下的toggle
方法来决定样式的切换。toggle
方法不仅可以应用样式,还可以判断此样式是否存在。
developer.mozilla.org/zh-CN/docs/...
对于此项目而言,如果player0El
的样式下已存在.player-active
样式,则移除它,否则添加它。
arduino
player0El.classList.toggle('player--active');
player1El.classList.toggle('player--active');
完整代码:
ini
if (dice !== 1) {
// 如果摇到的骰子数不是1,则将摇到的骰子数目加到当前的分数中。
currentScore += dice;
document.getElementById(`current--${activePlayer}`).textContent = currentScore;
} else {
// 切换到第二位玩家
currentScore = 0;
document.getElementById(`current--${activePlayer}`).textContent = currentScore;
activePlayer = activePlayer === 0 ? 1 : 0;
player0El.classList.toggle('player--active');
player1El.classList.toggle('player--active');
}
设置投入分数按钮(Hold)
根据游戏规则:如果玩家按下"投入HOLD"按钮,当前猜到的骰子数将会累加到那个玩家的总分变量上。并同时将当前分数清0,完成后自动切换玩家。
python
btnHold.addEventListener('click', function () {
// 1. Add current score to active player's socre 将当前游戏得主的分数进行相加运算
// 2. Check if player's socre is >= 100 检查游戏玩家是否得分大于等于100
// Finish the game 完成游戏
//Switch to the next player 切换玩家
})
将当前游戏得主的得分进行累加
javascript
btnHold.addEventListener('click', function () {
// 1. Add current score to active player's socre 将当前游戏得主的分数进行相加运算
scores[activePlayer] += currentScore;
// scores[1] = scores[1] + currentScore; //activePlayer = 1;
// 将所摇到的骰子分数全部累加并显示在指定的score--0 或 score--1上
document.getElementById(`score--${activePlayer}`).textContent = scores[activePlayer];
// 2. Check if player's socre is >= 100 检查游戏玩家是否得分大于等于100
// Finish the game 完成游戏
//Switch to the next player 切换玩家
})
当游戏玩家的分数大于等于100时,宣布胜利玩家并结束游戏
javascript
btnHold.addEventListener('click', function () {
// 1. Add current score to active player's socre 将当前游戏得主的分数进行相加运算
scores[activePlayer] += currentScore;
// scores[1] = scores[1] + currentScore; //activePlayer = 1;
// 将所摇到的骰子分数全部累加并显示在指定的score--0 或 score--1上
document.getElementById(`score--${activePlayer}`).textContent = scores[activePlayer];
// 2. Check if player's socre is >= 100 检查游戏玩家是否得分大于等于100
if(scores[activePlayer] >= 100){
// Finish the game 完成游戏
diceEl.classList.add('hidden'); //隐藏骰子
document.querySelector(`.player--${activePlayer}`).classList.add('player--winner');
document.querySelector(`.player--${activePlayer}`).classList.remove('player--active');
}
//Switch to the next player 切换玩家
})
分数不足100时,切换玩家
这里也要使用切换玩家功能,因此不如将刚刚写好的切换玩家功能封装成一个函数。
ini
// 切换玩家函数
const switchPlayer = function () {
// 切换到第二位玩家
currentScore = 0;
document.getElementById(`current--${activePlayer}`).textContent = currentScore;
activePlayer = activePlayer === 0 ? 1 : 0;
player0El.classList.toggle('player--active');
player1El.classList.toggle('player--active');
}
如果两个玩家的分数都没有到达"大于等于100",这时"投入HOLD"的按钮还是可以按下去的,所以当一个玩家按下投入(HOLD)按钮时,程序会自动切换玩家供另一位玩家掷骰子。
javascript
btnHold.addEventListener('click', function () {
// 1. Add current score to active player's socre
scores[activePlayer] += currentScore;
// scores[1] = scores[1] + currentScore;
document.getElementById(`score--${activePlayer}`).textContent = scores[activePlayer];
// 2. Check if player's socre is >= 100
if (scores[activePlayer] >= 100) {
// Finish the game
diceEl.classList.add('hidden');
document.querySelector(`.player--${activePlayer}`).classList.add('player--winner');
document.querySelector(`.player--${activePlayer}`).classList.remove('player--active');
} else {
//切换玩家
switchPlayer();
}
})
现在我们基本完成了应用程序,在测试应用程序中,为了缩小数据范围。我们把游戏规则稍微调整一下,将"大于等于100"改为"大于等于10"。
看着好像没什么问题,但实际上你还是可以继续游戏,所以按照测试前的规则,如果其中一个玩家得到了大于等于100分的分数,第二个玩家也可以通过同样的手段得到同样甚至超过另一个玩家的分数。
所以下面就是程序出错的结果:
此时我们需要一个变量用来存储用户的游戏状态。
设置游戏状态变量
定义变量playing
为记录游戏状态的变量,这个变量是一个逻辑型变量。
bash
let playing = true; // 当我们正在玩游戏时,将游戏设置为true,否则设置为false
之后,通过这个变量,就可以对rollBtn
和holdBtn
进行游戏状态的设置
btnRoll.addEventListener()
javascript
btnRoll.addEventListener('click', function () {
if (playing === true) {
// 1. Generating a random dice roll 随机生成一个骰子数
const dice = Math.trunc(Math.random() * 6) + 1;
console.log(dice);
// 2. Display dice 显示骰子数
diceEl.classList.remove('hidden');
diceEl.src = `dice-${dice}.png`;
// 3. Check for rolled 1: if true, switch to next player
// 检查投掷的数目,如果是1,则交换给另一个玩家
// 检查是否投掷到1的骰子数
if (dice !== 1) {
// 如果摇到的骰子数不是1,则将摇到的骰子数目加到当前的分数中。
currentScore += dice;
document.getElementById(`current--${activePlayer}`).textContent = currentScore;
} else {
switchPlayer();
}
}
});
btnHold.addEventListener()
javascript
btnHold.addEventListener('click', function () {
if (playing) {
// console.log('Hold button');
// 1. Add current score to active player's socre
scores[activePlayer] += currentScore;
// scores[1] = scores[1] + currentScore;
document.getElementById(`score--${activePlayer}`).textContent = scores[activePlayer];
// 2. Check if player's socre is >= 100
if (scores[activePlayer] >= 10) {
// Finish the game
playing = false; //当玩家赢时,要将状态设置为false,终止roll和hold按钮的操作
diceEl.classList.add('hidden');
document.querySelector(`.player--${activePlayer}`).classList.add('player--winner');
document.querySelector(`.player--${activePlayer}`).classList.remove('player--active');
} else {
//Switch to the next player
switchPlayer();
}
}
})
在btnHold
中,如果任意一个玩家赢得比赛,要将状态设置为false,终止roll和hold按钮的操作。
现在重新启动应用,我们已经成功完成了两个重要按钮和功能的设置。就差一个功能------"重置游戏"。
设计"新的一局",让游戏可以重玩一遍
实际上,需要我们设计一个初始化函数来重置整个游戏应用。这个功能不仅在设置"新的一局"按钮🔘中发挥作用,也可以在第一次启动游戏时发挥作用。
ini
let scores, currentScore, activePlayer, playing;
// 初始化游戏
const init = function () {
scores = [0, 0];
currentScore = 0;
activePlayer = 0;
playing = true; // 当我们正在玩游戏时,将游戏设置为true,否则设置为false
score0El.textContent = 0; // 将每个玩家的总分重置为0
score1El.textContent = 0; // 将两个玩家的所获得分数置空
current0El.textContent = 0; //将当前分数重置为0
current1El.textContent = 0;
// 前往对应的style.css文件创建一个隐藏类.hidden
diceEl.classList.add('hidden'); // 隐藏骰子
player0El.classList.remove('player--winner');
player1El.classList.remove('player--winner');
player0El.classList.add('player--active');
player1El.classList.remove('player--active');
}
init();