在这篇文章中,我们将解释制作著名的猪游戏所需的步骤和各种逻辑,这是一个虚拟骰子游戏。
关于游戏:在这个游戏中,用户界面(UI)包含可以做三件事的用户/玩家,它们如下:
这场比赛将有两名球员。在游戏开始时,玩家 1将成为当前玩家,玩家 2将成为非活动玩家。
- 掷骰子:当前玩家必须掷骰子,然后会产生一个随机数。如果当前玩家在骰子上得到除 1 以外的任何数字,则该数字将添加到当前分数(最初当前分数将为 0 ),然后新分数将显示在当前分数部分下。注意:如果当前玩家的骰子点数为1,则玩家将被切换,即当前玩家将变为非活动状态,反之亦然。
- 保持:如果当前玩家点击保持,则当前得分将被添加到总得分中。当活动玩家单击保持按钮时,将评估总分。如果总分 >= 100,则当前玩家获胜,否则玩家将被切换。
- 重置:所有分数设置为 0,玩家 1设置为起始玩家(当前玩家)。
游戏制作:由网页浏览器渲染的游戏,它是在HTML、CSS (前端)和JavaScript (后端)的帮助下构建的。游戏的主要逻辑在于 JS 文件,而外观和用户界面则由HTML 和 CSS呈现。在这个项目中,基本上有四种类型的文件:
- HTML 文件 (index.html)
- CSS 文件 (style.css)
- JavaScript 文件(script.js 文件)
- 图像(dice.png 文件)
我们将分析所有这些文件,从而让您了解他们在这个游戏中的工作/贡献。所以,首先让我们从index.html文件开始:
HTML 文件: Index.html 文件是使 Web 浏览器能够理解并解释我们正在制作的文档类型的文件。它代表超文本标记语言,我们的网络浏览器通过V8 引擎读取这个文件并理解它的组件(它以一种语言解析代码,以便浏览器可以理解它)。下面是这个游戏的 HTML 代码:
HTML
Pig Game Design using JavaScript
Total Score
Player 1
43
Current Score
0
Total Score
Player 2
24
Current Score
0
CSS
* {
margin: 0;
padding: 0;
}
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
position: relative;
width: 80%;
height: 90%;
background-color: lightgreen;
overflow: hidden;
display: flex;
}
.player {
flex: 50%;
padding: 150px;
display: flex;
flex-direction: column;
align-items: center;
transition: all 0.75s;
}
.name {
position: relative;
font-weight: bold;
font-size: 38px;
text-align: center;
}
.pl {
font-size: 24px;
}
.tscore {
background-color: #fff;
border-radius: 9px;
width: 65%;
padding: 2rem;
text-align: center;
transition: all 0.75s;
}
.score {
font-size: 38px;
font-weight: bold;
margin-bottom: auto;
padding-top: 10px;
}
.player--active {
background-color: green;
}
.player--active .current {
opacity: 1;
}
.current {
margin-top: 10rem;
background-color: #fff;
border-radius: 9px;
width: 65%;
padding: 2rem;
text-align: center;
transition: all 0.75s;
}
.current-label {
text-transform: uppercase;
margin-bottom: 1rem;
font-size: 1.7rem;
color: #ddd;
}
.current-score {
font-size: 3.5rem;
}
.btn {
position: absolute;
left: 50%;
transform: translateX(-50%);
color: rgb(7, 124, 69);
border: none;
font-size: 30px;
cursor: pointer;
font-weight: bold;
background-color: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(10px);
padding: 10px 30px;
border-radius: 10px;
}
.btn--new {
top: 4rem;
}
.btn--roll {
top: 39.3rem;
}
.btn--hold {
top: 46.1rem;
}
.dice {
position: absolute;
left: 50%;
top: 24rem;
transform: translateX(-50%);
}
.player--winner {
background-color: #003612;
}
.player--winner .name {
font-weight: 700;
color: #c7365f;
}
.hidden {
display: none;
}
Javascript
'use strict';
// Selecting elements
const player0El = document.querySelector('.player--0');
const player1El = document.querySelector('.player--1');
const score0El = document.querySelector('#score--0');
const score1El = document.getElementById('score--1');
const current0El = document.getElementById('current--0');
const current1El = document.getElementById('current--1');
const diceEl = document.querySelector('.dice');
const btnNew = document.querySelector('.btn--new');
const btnRoll = document.querySelector('.btn--roll');
const btnHold = document.querySelector('.btn--hold');
let scores, currentScore, activePlayer, playing;
Javascript
// Rolling dice functionality
btnRoll.addEventListener('click', function () {
if (playing) {
// 1. Generating a random dice roll
const dice = Math.trunc(Math.random() * 6) + 1;
// 2. Display dice
diceEl.classList.remove('hidden');
diceEl.src = `dice-${dice}.png`;
// 3. Check for rolled 1
if (dice !== 1) {
// Add dice to current score
currentScore += dice;
document.getElementById(
`current--${activePlayer}`
).textContent = currentScore;
} else {
// Switch to next player
switchPlayer();
}
}
});
Javascript
const switchPlayer = function () {
document.getElementById(`current--${activePlayer}`).textContent = 0;
currentScore = 0;
activePlayer = activePlayer === 0 ? 1 : 0;
player0El.classList.toggle('player--active');
player1El.classList.toggle('player--active');
};
Javascript
btnHold.addEventListener('click', function () {
if (playing) {
// 1. Add current score to active player's score
scores[activePlayer] += currentScore;
// scores[1] = scores[1] + currentScore
document.getElementById(`score--${activePlayer}`)
.textContent = scores[activePlayer];
// 2. Check if player's score is >= 100
if (scores[activePlayer] >= 100) {
// Finish the game
playing = false;
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();
}
}
});
Javascript
// Starting conditions
const init = function () {
scores = [0, 0];
currentScore = 0;
activePlayer = 0;
playing = true;
score0El.textContent = 0;
score1El.textContent = 0;
current0El.textContent = 0;
current1El.textContent = 0;
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();
在上面的代码中,我们使用了各种类(例如:btn btn–roll、rte),这些将用于 CSS 文件中的样式目的,并将在 CSS 文件下讨论它们。
CSS 文件:为了格式化由 HTML 创建的标记和样式,我们需要级联样式表,以便标记(代码)看起来更好。下面是游戏的 CSS 代码。在深入代码之前,只需快速查看哪些类和 id 用于什么目的:
- 对于整个 HTML 页面和元素: * 将影响标记中的每个元素和标签。我们使用了另外 2 个标签来提供一些特定的样式,即 html 和 body 标签的样式。
- 布局元素:在那里定义了主要标签和播放器类样式。我们为 main 标签定义了position属性并将其属性设置为relative。
- 自制类:使页面更具吸引力所需的通用样式。
- 绝对定位类:我已经设置了btn 和其他类的位置属性并将其值设置为绝对,因为我们必须确保按钮和其他元素始终位于页面中的正确位置。绝对位置将根据相对定位的元素(在这种情况下,它是主标签)来安排该特定元素。
CSS
* {
margin: 0;
padding: 0;
}
body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
position: relative;
width: 80%;
height: 90%;
background-color: lightgreen;
overflow: hidden;
display: flex;
}
.player {
flex: 50%;
padding: 150px;
display: flex;
flex-direction: column;
align-items: center;
transition: all 0.75s;
}
.name {
position: relative;
font-weight: bold;
font-size: 38px;
text-align: center;
}
.pl {
font-size: 24px;
}
.tscore {
background-color: #fff;
border-radius: 9px;
width: 65%;
padding: 2rem;
text-align: center;
transition: all 0.75s;
}
.score {
font-size: 38px;
font-weight: bold;
margin-bottom: auto;
padding-top: 10px;
}
.player--active {
background-color: green;
}
.player--active .current {
opacity: 1;
}
.current {
margin-top: 10rem;
background-color: #fff;
border-radius: 9px;
width: 65%;
padding: 2rem;
text-align: center;
transition: all 0.75s;
}
.current-label {
text-transform: uppercase;
margin-bottom: 1rem;
font-size: 1.7rem;
color: #ddd;
}
.current-score {
font-size: 3.5rem;
}
.btn {
position: absolute;
left: 50%;
transform: translateX(-50%);
color: rgb(7, 124, 69);
border: none;
font-size: 30px;
cursor: pointer;
font-weight: bold;
background-color: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(10px);
padding: 10px 30px;
border-radius: 10px;
}
.btn--new {
top: 4rem;
}
.btn--roll {
top: 39.3rem;
}
.btn--hold {
top: 46.1rem;
}
.dice {
position: absolute;
left: 50%;
top: 24rem;
transform: translateX(-50%);
}
.player--winner {
background-color: #003612;
}
.player--winner .name {
font-weight: 700;
color: #c7365f;
}
.hidden {
display: none;
}
在 HTML 代码中,我们提供了各种类的名称。在这个文件中,我们提供了它们不同的功能。 CSS 文件在使网页或游戏看起来不错(仅在 Web 浏览器的情况下)方面起着重要作用。
到目前为止,我们已经完美地制作了游戏的用户界面,现在是更棘手的部分。所以让我们深入研究游戏逻辑……
JavaScript 文件:有一些JavaScript 变量,我们可以使用两种类型的变量,即let 和 constant。用let声明的变量可以修改,用constant声明的变量不能修改。在 JavaScript 文件中,我们基本上是在做DOM 操作(JavaScript 中的一切都是一种对象,所以我们将 UI 称为文档对象模型)。所以 document.querySelector() 是一种从 DOM 中选择元素的方法。
为了理解逻辑的工作流程,我们必须首先理解事件监听器的概念。事件侦听器是根据特定事件执行操作的函数。他们等待特定事件发生。这个游戏共有 03 个事件监听器: btnRoll、btnHold、btnNew。我们将了解所有这些事件侦听器的功能:
注意:在进入事件处理程序部分之前,我们必须在文件中声明一些变量,以便稍后在我们的游戏逻辑中使用它们。
Javascript
'use strict';
// Selecting elements
const player0El = document.querySelector('.player--0');
const player1El = document.querySelector('.player--1');
const score0El = document.querySelector('#score--0');
const score1El = document.getElementById('score--1');
const current0El = document.getElementById('current--0');
const current1El = document.getElementById('current--1');
const diceEl = document.querySelector('.dice');
const btnNew = document.querySelector('.btn--new');
const btnRoll = document.querySelector('.btn--roll');
const btnHold = document.querySelector('.btn--hold');
let scores, currentScore, activePlayer, playing;
在 JavaScript 文件的最开始,有一行“use strict”。 “use strict”的目的是表示代码应该在“严格模式”下执行。除 Internet Explorer 9 及更低版本外,所有现代浏览器都支持“严格使用”。
现在让我们开始查看 3 个事件处理程序中每一个的代码。
1. btnRoll 事件处理程序:
Javascript
// Rolling dice functionality
btnRoll.addEventListener('click', function () {
if (playing) {
// 1. Generating a random dice roll
const dice = Math.trunc(Math.random() * 6) + 1;
// 2. Display dice
diceEl.classList.remove('hidden');
diceEl.src = `dice-${dice}.png`;
// 3. Check for rolled 1
if (dice !== 1) {
// Add dice to current score
currentScore += dice;
document.getElementById(
`current--${activePlayer}`
).textContent = currentScore;
} else {
// Switch to next player
switchPlayer();
}
}
});
每当玩家点击Roll 按钮时,这个事件处理程序就会起作用(这就是我们在那里使用 click 事件的原因)。然后是一个以if-else 块开头的回调函数。因为我们已经声明了变量play = true ,所以这个事件处理程序的 if 块将为 true ,因此 if 块的代码将被执行。以下是前面的步骤:
- 步骤 1:在玩家点击掷骰子按钮后,此事件处理程序使用Math.trunc()函数生成一个随机数。我们使用了 Math.trunc()函数,因为该函数返回随机生成函数的整数部分,并为其添加了 1,因为random()函数可以生成从 0 到 1 的任何数字,但在我们的例子中,我们只需要从 1 到 6 的数字。
了解骰子变量:骰子变量将存储随机生成的数字。假设 Math.random()函数生成数字 0.02。根据代码,第一个 0.02 将乘以 6。因此可变骰子现在的值为 0.12。然后 Math.trunc()函数将起作用并使骰子变量为 0 。现在 1 将被添加到变量中,这将使骰子 = 1 (这就是我们需要的骰子数字) - Step2:现在我们已经得到了骰子的分数,我们要显示与骰子数量相对应的骰子。 (在 CSS 文件中,我们创建了一个名为 hidden 的类,它将在游戏开始时最初隐藏骰子)但是现在我们有一个骰子编号以骰子图像的形式显示,我们必须删除隐藏类。这是通过行diceE1.classList.remove(‘hidden’) 实现的,然后将正确的骰子图像呈现到 UI。
- 第三步。现在根据游戏规则,我们必须检查骰子上的数字。因此,如果骰子数不是 1,则更新当前分数。如果骰子数为 1,则调用switchPlayer() 。
Javascript
const switchPlayer = function () {
document.getElementById(`current--${activePlayer}`).textContent = 0;
currentScore = 0;
activePlayer = activePlayer === 0 ? 1 : 0;
player0El.classList.toggle('player--active');
player1El.classList.toggle('player--active');
};
根据规则: “如果玩家掷出 1,那么他将失去所有当前得分” 。此功能正在实现相同的函数。
activePlayer = activePlayer === 0 ? 1 : 0 {这是一个三元运算符,其中我们说的是,如果 activeplayer 为 0,则将其设为 1,如果是,则将其设为 0。
2. btnHold 事件处理程序
Javascript
btnHold.addEventListener('click', function () {
if (playing) {
// 1. Add current score to active player's score
scores[activePlayer] += currentScore;
// scores[1] = scores[1] + currentScore
document.getElementById(`score--${activePlayer}`)
.textContent = scores[activePlayer];
// 2. Check if player's score is >= 100
if (scores[activePlayer] >= 100) {
// Finish the game
playing = false;
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();
}
}
});
每当玩家点击 HOLD 按钮时,此事件处理程序就会触发。以下是此处理程序涉及的步骤:
- 第 1 步:一旦玩家点击保持,当前分数就会被添加到该玩家的总分中。
- Step2:在该步骤之后完成对总分的评估。如果发现总分大于 100,则游戏结束,然后玩家获胜者类别(使背景颜色为黑色并更改颜色和字体粗细)并删除活跃玩家类别。
3. btnNew 事件处理程序:
btnNew.addEventListener(‘click’,init):每当一个新游戏被初始化时,这个事件处理程序就会触发。它只初始化Init()函数。 Init() 类将游戏重置为开始,即它执行以下操作:
- 使双方球员的得分为 0。
- 使播放器 1 成为活动/当前播放器。
- 隐藏类隐藏骰子。
- 从两个玩家中删除玩家-获胜者类别
- 将玩家活动类添加到玩家 1
Javascript
// Starting conditions
const init = function () {
scores = [0, 0];
currentScore = 0;
activePlayer = 0;
playing = true;
score0El.textContent = 0;
score1El.textContent = 0;
current0El.textContent = 0;
current1El.textContent = 0;
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();
注意: init()函数也在加载游戏时初始化。
输出:
切块图像参考:
- 骰子-1.png
- 骰子-2.png
- 骰子-3.png
- 骰子-4.png
- 骰子-5.png
- 骰子-6.png