javascript - Re: Hangman Using Modules, How to draw out the Hangman using plain css, html, and javascript
问题描述
我正在开发一个简单的刽子手应用程序,并且我已经完成了大部分功能,我遇到的一点问题实际上是在错误的猜测中绘制出刽子手。我已将所有组件分成模块并在下面列出。如果我能得到一些想法或例子来说明如何让我的错误响应来激活相应的 div 以拉出绞刑架和绞刑人,我将不胜感激。
索引.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="src/styles/hangman.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
<title>JavaScript | Hangman</title>
</head>
<body>
<header class="header col-lg-12">
<h1>JavaScript Hangman Game</h1>
</header>
<div id="gallows col-lg-4">
<div class="right-bar"></div>
<div class="top-bar"></div>
<div class="left-bar"></div>
<div class="base"></div>
<div class="head"></div>
<div class="body"></div>
<div class="left-arm"></div>
<div class="right-arm"></div>
<div class="left-leg"></div>
<div class="right-leg"></div>
<div class="clearfix"></div>
</div>
<div id="hangman col-log-8">
<div id="display-status"></div>
<div id="letter-slots"></div>
<div id="keyboard"></div>
<button id="restart">Restart</button>
</div>
<script src="dist/build.js" defer></script>
</body>
</html>
入口点-> hangman.js
import "regenerator-runtime/runtime";
//Bring in the modules being used
import getRandomWord from './words_list';
import { isStillPlaying } from './game_status';
import letterSlots from './letter_slots';
import keyboard from './keyboard_layout';
import displayStatus from './game_display_status';
import restartGame from './new_game';
//Start and play
function drawGame(word, letters) {
document.querySelector('#display-status').innerHTML = displayStatus(word, letters);
document.querySelector('#letter-slots').innerHTML = letterSlots(word, letters);
document.querySelector('#keyboard').innerHTML = keyboard(letters);
}
getRandomWord(word => {
const letters = [];
document.addEventListener('click', event => {
if(isStillPlaying(word, letters) && event.target.tagName === 'BUTTON') {
letters.push(event.target.dataset.character);
drawGame(word, letters);
}
});
drawGame(word, letters);
restartGame();
});
words_list.js
import newHttpRequest from './send_http_request';
//Use fetch API via Send Http Request
async function getWords(cb) {
try {
cb(await newHttpRequest(
'GET',
'https://random-word-api.herokuapp.com/word?number=50'
));
} catch(error) {
alert(error.message);
}
}
//Select a random word
export default async function getRandomWord(cb) {
try {
await getWords(words => {
const randomWord = words[Math.floor(Math.random() * words.length)];
cb(randomWord.toUpperCase());
});
} catch(error) {
alert(error);
}
}
send_http_request.js
//Create an http request
export default function newHttpRequest(method, url, data) {
return fetch(url, {
method: method,
body: data
}).then(response => {
if(response.status >= 200 && response.status < 300) {
return response.json();
} else {
return response.json().then(errorData => {
console.log(errorData);
throw new Error('Something went wrong server-side! Please try again later.')
})
}
}).catch(error => {
console.log(error);
throw new Error('Something went wrong! Please try again later.')
})
}
new_game.js
function newGame() {
document.location.reload(window);
}
export default function restartGame() {
const restart = document.getElementById('restart');
restart.addEventListener('click', newGame);
}
letter_slots.js
//Create spans that are empty or contain a letter
function letterSlot(letter, letters) {
if(letters.includes(letter)) {
return `<span>${letter}</span>`
} else {
return `<span> </span>`
}
}
//Export the function to use
export default function letterSlots(word, letters) {
const slots = word.split('').map(letter => letterSlot(letter, letters));
return `<div>${ slots.join('') }</div>`
}
键盘布局.js
//Store the letters
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split("");
//Divide the letters into three rows
const row1 = alphabet.slice(0, 10);
const row2 = alphabet.slice(10, 19);
const row3 = alphabet.slice(19, 26);
//Show or hide buttons
function key(letter, letters) {
if(letters.includes(letter)) {
return `<span>${letter}</span>`
} else {
return `<button data-character=${letter}>${letter}</button>`
}
}
//Export keyboard and map letters to buttons
export default function keyboard(letters) {
return `
<div>${ row1.map(character => key(character, letters)).join('') }</div>
<div>${ row2.map(character => key(character, letters)).join('') }</div>
<div>${ row3.map(character => key(character, letters)).join('') } </div>
`
}
game_status.js
//Set wrong guesses
const MAX_WRONG_LETTERS = 15;
//Find all the letters
export function lettersRemaining(word, letters) {
const wrongLetters = letters.filter((character) => !word.includes(character));
return MAX_WRONG_LETTERS - wrongLetters.length;
}
//Are the letters guessed
export function isGameWon(word, letters) {
return !word.split("").find(letter => !letters.includes(letter));
}
//If no letters and game not won, game over
export function isGameOver(word, letters) {
return !lettersRemaining(word, letters) && !isGameWon(word, letters);
}
//Still in play
export function isStillPlaying(word, letters) {
return (
lettersRemaining(word, letters) &&
!isGameOver(word, letters) &&
!isGameWon(word, letters)
);
}
game_display_status.js
import * as status from './game_status';
//invoke imported functions
function getMessage(word, letters) {
if(status.isGameWon(word, letters)) {
return "You Win!"
} else if(status.isGameOver(word, letters)) {
return 'Game Over!'
} else {
return `Chances remaining: ${status.lettersRemaining(word, letters)}`
}
}
//Export what to display
export default function displayStatus(word, letters) {
return `<div> ${getMessage(word, letters)}</div>`
}
刽子手.css
body {
margin: 0;
background: gainsboro;
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
.header {
padding: 1px;
text-align: center;
background: slateblue;
color: white;
}
#hangman {
margin: 100px 0;
text-align: center;
}
#hangman > div {
margin: 50px;
}
#display-status {
color: black;
font-family: Georgia, "Times New Roman", Times, serif;
font-weight: bold;
font-size: 30px;
}
#letter-slots span {
color: black;
border-bottom: 3px solid black;
text-transform: uppercase;
font-size: 24px;
margin: 5px;
width: 2em;
display: inline-block;
}
#keyboard button,
#keyboard span {
background: darkslateblue;
color: gainsboro;
border: 3px outset darkslategrey;
border-radius: 4px;
padding: 10px;
font-size: 18px;
display: inline-block;
margin: 5px;
cursor: pointer;
width: 2.5em;
}
#keyboard span {
opacity: 0.3;
}
.logo {
color: black;
}
#restart {
color: gainsboro;
background-color: darkslateblue;
border: 3px outset darkslategrey;
border-radius: 6px;
padding: 12px 20px;
font-size: 20px;
}
.name {
color: blue;
}
.page-footer {
display: flex;
justify-content: space-around;
position: fixed;
left: 0;
bottom: 0;
width: 100%;
height: auto;
background-color: slateblue;
color: white;
text-align: center;
}
a {
text-decoration: none;
}
p {
font-size: 19px;
font-family: Georgia, "Times New Roman", Times, serif;
font-weight: bold;
color: black;
}
#gallows {
height: 405px;
margin: 0 auto;
width: 300px;
}
#gallows div {
background: #FFF;
}
#gallows .base {
height: 2px;
width: 300px;
}
#gallows .left-bar {
height: 400px;
width: 2px;
}
#gallows .top-bar {
height: 2px;
width: 200px;
}
#gallows .right-bar {
float: left;
height: 30px;
margin-left: 200px;
width: 2px;
}
#gallows .head {
background: none;
border-radius: 100%;
float: left;
margin-left: 175px;
margin-top: -375px;
height: 50px;
width: 50px;
}
#gallows .body {
float: left;
height: 140px;
margin-top: -321px;
margin-left: 200px;
width: 2px;
}
#gallows .left-arm,
#gallows .right-arm,
#gallows .left-leg,
#gallows .right-leg {
float: left;
height: 90px;
margin-top: -321px;
margin-left: 173px;
transform: rotate(35deg);
width: 2px;
}
#gallows .right-arm,
#gallows .right-leg {
margin-left: 230px;
margin-top: -324px;
transform: rotate(140deg);
}
#gallows .left-leg,
#gallows .right-leg {
margin-top: -192px;
}
#gallows.lifes-10 .base {
background: #000;
}
#gallows.lifes-9 .left-bar {
background: #000;
}
#gallows.lifes-8 .top-bar {
background: #000;
}
#gallows.lifes-7 .right-bar {
background: #000;
}
#gallows.lifes-6 .head {
border: 2px solid #000;
}
#gallows.lifes-5 .body {
background: #000;
}
#gallows.lifes-4 .left-arm {
background: #000;
}
#gallows.lifes-3 .right-arm {
background: #000;
}
#gallows.lifes-2 .left-leg {
background: #000;
}
#gallows.lifes-1 .right-leg {
background: #000;
}
谢谢大家。我正在学习,尽管速度很慢。
解决方案
推荐阅读
- opencv - 我的 OpenCV 4.2.0 源代码中的 CMAKE 找不到我的机器中安装的任何 cuDNN
- logging - 已解决:如何在运行时重新路由 Arduino/ESP 串行输出?
- loops - 如何降低嵌套循环算法的时间复杂度?我的示例伪代码附在下面
- c# - 如何获取 Virtualize 组件子项的元素引用?
- excel - 在 Excel 的数据透视表中添加计算项目会在行中对我的字段进行交叉乘积
- python - 为 seaborn 子图创建 forloop 的问题
- angular - 使用 Angular 获取 firebase 对象
- pandas - 在 pandas groupby 中查找过去 30 天和 60 天的 Quantity 平均值
- php - php发布网页并返回值
- ruby-on-rails - 在两个模型中使用 accept_nested_attributes_for 时出现重复的验证错误。我可以避免这种情况吗?