Введя Король - игра на JavaScript, вписав


Это то, что я сделал сегодня и я хочу пересмотреть мой код, чтобы увидеть, какие вещи я могу сделать лучше или умнее. Я не знаю, если его соответствующие, но потребовалось 2 часа, чтобы код.

Разумно ли использовать ООП для подобного проекта?

Я включил весь код в сниппет.

var inGame = false;
var currentWord, amountOfErrors, goodAnswers, previousWord;
var timer, time;


$(document).ready(function() {
  //Check if enter is pressed
  $(document).keypress(function(e) {
      if(e.which == 13) {
          enterWord();
      }
  });

  $("#startBtn").click(function () {
    //Start the game when user clicks
    startGame();
    $("#startBtn").hide();
  })

});


function startGame() {
  //Initialize start
  inGame = true;
  document.getElementById("wordField").focus();

  //Reset all variables
  amountOfErrors = 0;
  corrections = 0;
  goodAnswers = 0;
  $("#currentWord").html("");
  $("#errors").html("");
  $("#wpm").html("");

  pickWord();

  //start the timer
  $("#timer").show();
  startTimer();


}

function stopGame () {

  //Stop the timer
  clearInterval(timer);
  $("#timer").hide();
  $("#startBtn").show();
  $("#wordField").val("");

  //Set game to stopped
  inGame = false;

  //Show player his results
  $("#currentWord").html("<strong>Done...</strong>");
  $("#errors").html('<strong>Amount of errors: '+amountOfErrors+'</strong>');
  $("#wpm").html('<strong>Words per minute: '+goodAnswers+'</strong>');

}

function startTimer() {

  //Reset timer back to 60 seconds
  time = 60;

  //Every 100ms the timer gets updated
  timer = setInterval(function () {
    if (time <= 0) {
      stopGame();
    }
    time = time +- 0.1;
    $("#timer").html("<strong>"+time.toFixed(2)+"</strong>")
  },100);

}

function enterWord () {
  //If player is not in game
  if (inGame == false) {
    //Do nothing
  } else if (inGame == true) { //Is in game
    
    checkWord();
  }
}

function checkWord () {
    var enteredWord = $("#wordField").val();

    //Check if the player typed the correct string
    if (enteredWord == currentWord) {
      //if true
      fadeColor("wordField", "backgroundColor", "rgb(43,234,81)");
      $("#wordField").val("");
      pickWord();
      goodAnswers++;
      previousWord = currentWord;

    } else {
      //if false
      amountOfErrors++;
      fadeColor("wordField", "backgroundColor", "rgb(234,43,43)");
    }
}
function pickWord () {

  //Checking how many words ther are in the array
  var aantalWoorden = woorden.length;
  //Amount of words + 1
  aantalWoorden = aantalWoorden + 1;

  //Pick a random number between the amount of words and 0
  var randomWord = Math.floor((Math.random() * aantalWoorden) + 0);

  //Select a random word from the array
  currentWord = woorden[randomWord];

  //Check if its not the same as previous word
  if (currentWord == previousWord || currentWord == undefined) {
    pickWord();
  } else {
    //Show the word
    $("#currentWord").html("<strong>"+currentWord+"</strong>");
  }
}

var woorden = ["value" , "meanwhile", "finally" , "base" , "spikes" ,"creature", "comforts" , "advanced" , "the snout" , "opposite", "the spoon" , "the dust cloud" , "scrape" , "natural" , "significantly" , "the hedgehog" , "create" , "offset" , "enlarge" , "treacherous" , "the direction" , "the culture" , "the territory", "the timetable"];


function fadeColor(id, property, color) {
    var oProperty = $('#'+id+'').css(property);

    $('#'+id+'').css(property, color);
    setTimeout(function() {
      $('#'+id+'').css(property, oProperty);
    },300);
}
@import url('https://fonts.googleapis.com/css?family=IBM+Plex+Mono');

body {
  margin: 0;
  background-color: rgb(234,43,43);
  color: white;
  font-family: IBM Plex Mono;
}

.centerDiv {
  display: flex;
  flex-direction: column;
  margin: auto;
  width: 100%;
  height: 100%;
  align-items: center;
  text-align: center;
}

.headerDiv {
  display: flex;
  flex-direction: column;
  margin: auto;
  width: 100%;
  height: 100%;
  align-items: center;
  text-align: center;
  margin: 10px;
  margin-bottom: 10%;
}

.header {
  font-size: 25px;
}

.textfield {
  padding: 10px;
  border-radius: 3px;
  background-color: white;
  color: black;
  text-decoration: none;
  border: none;
  margin: 10px;
  font-size: 25px;
  transition: all 0.15s ease;
}

.textToType {
  font-size: 25px;
  margin: 10px;
}

.button {
  padding: 10px;
  border-radius: 3px;
  background-color: white;
  color: rgb(234,43,43);
  text-decoration: none;
  border: none;
  margin: 10px;
  font-size: 25px;
  transition: all 0.15s ease;
}
.button:hover {
  cursor: pointer;
  transform: scale(1.05);
}
<!DOCTYPE html>
<html>
<head>
<title>Typing King</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/style.css">
<link rel="icon" href="css/favicon.png" type="image/png">
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="js/typing.js"></script>
</head>
<body>

<div class="centerDiv">

  <div class="headerDiv">
    <a class="header">Typing King</a>
    <a>Are you the next typing king?</a>
  </div>

  <div class="centerDiv">
    <a class="textToType" id="currentWord"></a>
    <input class="textfield" id="wordField" placeholder="Your input"/>
    <a class="button" id="startBtn">Start</a>
    <a id="timer"></a>
    <a id="wpm"></a>
    <a id="corrections"></a>
    <a id="errors"></a>
  </div>

</div>

</body>
</html>



322
7
задан 27 марта 2018 в 05:03 Источник Поделиться
Комментарии
2 ответа

Я должен начать с того, что игра достаточно интересная, и для новичка код-это хорошо, но, конечно, есть много возможностей для совершенствования.

Мелкие детали

У вас много небольших вещей, которые могут немного странным или ненужным даже, таких как:


  • В inGame проверить

    if (inGame == false) {

    //Do nothing
    } else if (inGame == true) { //Is in game
    checkWord();
    }

    Не использовать if или else блок у вас нет кода для этого. Он не только делает код более как это создает путаницу как к тому, что является его целью. В этом случае вы можете вырезать сначала if и оставить только то, что вы имели в else:

    if (inGame == true) { //Is in game  
    checkWord();
    }

    Вы можете даже использовать строгое равенство , если вы хотите, чтобы убедиться, что оба операнда матч в тип, который стал бы if (inGame === true). Как Примечание стороны, нет особого смысла в принятии такого очевидного комментария, как "в игре". Сохранить ваши замечания на более актуальные вещи.


  • Добавление время:

    time = time +- 0.1;

    Нет никаких оснований для + чтобы быть там, и это делает инструкция труднее читать. Просто вычесть напрямую: time = time - 0.1;


  • Генерация случайных слов:

    Math.floor((Math.random() * aantalWoorden) + 0);

    Добавление 0 здесь ничего не меняется и снова добавляет беспорядка в коде, и лишние ( и ) что изолировать Math.random и aantalWoorden также нет необходимости.


  • Потертости элементов:

    var oProperty = $('#'+id+'').css(property);

    Больше или меньше, как некоторые другие вещи, которые я уже заявил. В + '' является избыточной и должна быть удалена.


  • corrections не похоже, чтобы использоваться на всех:

    function startGame() {
    ...
    corrections = 0;

    Хотя есть <a> тег для этого название, он не кажется, чтобы быть использованы в любом месте.


  • Смешанные языки и случайная генерация

    var aantalWoorden = woorden.length;
    aantalWoorden = aantalWoorden + 1;
    var randomWord = Math.floor((Math.random() * aantalWoorden) + 0);

    Некоторые переменные в голландский в то время как другие на английском. Старайтесь быть последовательными и придерживаться одного языка.

    Случайная генерация-это не правильно. Математика.случайным образом генерирует число от 0 до 1, так 1 никогда не генерируется. Это означает, что при Math.floor применяется он округляет значение и как таковое length значение никогда не генерируется, в результате точных измерений.

    Возьмите этот простой пример:

    const nums = [10, 20, 30];
    const randIndex = Math.floor(Math.random() * nums.length);

    nums.length это 3 так Math.random() * 3 генерирует значение от 0 для 3 исключительное, что когда пол будет в диапазоне от 0 для 2 включительно. Это предполагаемый диапазон для выбора в вопросе.


Рефакторинг

Когда вы видите, что делаете то же самое много раз, пора уже одуматься и попытаться реструктурировать эту часть, потому что там конечно лучше. У вас очень мало кода, который повторяется логика, но давайте взглянем на fadeColor функции:

function fadeColor(id, property, color) {
var oProperty = $('#'+id+'').css(property);

$('#'+id+'').css(property, color);
setTimeout(function() {
$('#'+id+'').css(property, oProperty);
},300);
}

Обратите внимание, как вы строите тот же селектор в 3 раза с $('#'+id+''). Так что это не только повторяет селектор строительства, а также выбирает элемент из несколько раз дом. Сохранить извлечена элемент в переменную, а затем использовать его:

function fadeColor(id, property, newColor) {
const element = $('#'+id);
const oldColor = element.css(property);

element.css(property, newColor);
setTimeout(function() {
element.css(property, oldColor);
},300);
}

Обратите внимание, как я использовал const вместо var. С ЕС6 теперь у вас обоих const и let как и другие способы объявления переменных. В этом случае я знаю, что я не хочу меняться element или oldColorи с const это даст мне ошибку, если я случайно их менять. Это основывается на написании защитной код, который дает вам ошибки скорее раньше, чем позже.

В setTimeout сама по себе может быть сокращен с помощью стрелки функции:

setTimeout(() => element.css(property, oldColor), 300);

Что делает его очень компактным и легким для чтения.

Объекты

Один недостаток, как вы получили код структурированной, что у вас есть несколько глобальных переменных. Это создает трудности в управлении государством, а также открывает возможность столкновения с уже существующими глобальными переменными. Это могут быть либо из window объект или даже какой-то другой плагин/библиотеку, которая включается наверху.

Вся логика игры может быть перенесен на один или несколько объектов/классов, который поможет вам отделяя ее от презентации на странице. Конечно, вы можете это многовато считаю для такой простой игры, но это, безусловно, способ для улучшения, особенно если вы хотите продолжать добавлять функции.

В качестве первого шага вы могли бы рассмотреть следующий подход:

function Game(){
this.inGame = false;
this.amountOfErrors = 0;
this.goodAnswers = 0;
this.time = 60;

this.words = ["value" , "meanwhile", "finally" , "base" , "spikes" ,
"creature", "comforts" , "advanced" , "the snout" , "opposite",
"the spoon" , "the dust cloud" , "scrape" , "natural" ,
"significantly" , "the hedgehog" , "create" , "offset" ,
"enlarge" , "treacherous" , "the direction" , "the culture" ,
"the territory", "the timetable"];

this.pickWord = function() {
const randomIndex = Math.floor(Math.random() * this.words.length);
return this.words[randomIndex];
};

...
}

Объект игра теперь будет инстанцирован с:

let game = new Game();

В то время как весь код теперь будет больше, так как вам придется управлять как страницы визуальных элементов, а также сама логика, она также будет более модульной, организованной и проще в обслуживании или добавить функциональных возможностей. Он будет по-прежнему необходимо для какой-либо другой функции, чтобы вызывать игровые функции и обновления соответствующих элементов страницы в зависимости от состояния игры.

Более современный способ делать то, что я сделал выше, используя на ES6 классы:

class Game {
constructor() {
this.inGame = false;
this.amountOfErrors = 0;
this.goodAnswers = 0;
this.time = 60;

this.words = ["value" , "meanwhile", "finally" , "base" , "spikes" ,
"creature", "comforts" , "advanced" , "the snout" , "opposite",
"the spoon" , "the dust cloud" , "scrape" , "natural" ,
"significantly" , "the hedgehog" , "create" , "offset" ,
"enlarge" , "treacherous" , "the direction" , "the culture" ,
"the territory", "the timetable"];
}

pickWord() {
const randomIndex = Math.floor(Math.random() * this.words.length);
return this.words[randomIndex];
}

...
}

3
ответ дан 28 марта 2018 в 03:03 Источник Поделиться

Комментарий код

Развертывание


Я включил весь код в сниппет.

Да, насколько я могу сказать. Лучший способ убедиться, чтобы запустить код и проверить все его части.

Кстати ООП


Разумно ли использовать ООП для подобного проекта?

Да всегда умное, но потом все JavaScript-это ОО так немного трудно, чтобы избежать ООП при написании кода JavaScript.

Что вы должны спросить "я умный и используя передовой практики ООП", для которых ответом является. Вам нужно, чтобы начать создание объектов, которые определяют и воплощают в различных частях вашего приложения. В настоящее время вы используете только объекты и косвенно, создавая их (функции объекта)

JavaScript-это очень гибкий в этом отношении, есть много способов создания и использования объектов.

Приложения этого типа не должен быть определен как объект instanceable, как вы никогда не придется создавать более, чем одной копии игры на странице. В рерайт я обернуть весь код в onload событие функцию. Это инкапсулирует все данные и функции, эффективно делая его автономным анонимный объект.

Кроме того, я добавил объект на вершине, чтобы держать все параметры. Это позволяет легко вносить изменения, так как вам не придется пройти через код, чтобы изменить каждый параметр (особенно удобно, когда код начинает работать на 1000 линий)

Некоторые заметки


  • Всегда используйте строгого режима, добавив "use strict"; в верхней части на JavaScript.

  • Научиться использовать requestAnimationFrame чтобы обработать весь дом содержание изменения вместо того, чтобы использовать время событий. Увидеть переписать о том, как я использую его.

  • Забывать, что JavaScript имеет == и != операторов. Вы действительно не должны использовать их. Почему не использовать их утонченные и полные кодирования ошибки и ловушки для неосторожных. Используйте === и !== операторов. Для того чтобы знать больше пользоваться гуглом.

  • Избегайте устанавливать элемент стили напрямую. Используйте элемент className или classList и установить класс для изменения стиля. Увидеть переписать, например.

  • Всегда ставь пробелы между операторами. Например var sum=a+b+c; должно быть var sum = a + b + c;

  • Использовать const для переменных, которые не меняются. Например var enteredWord = $("#wordField").val(); должно быть const enteredWord = $("#wordField").val();

  • Math.random() никогда не вернуться 1. При использовании случайным образом выбрать элемент из массива вам не прибавить к длине массива. Смотрите фрагмент чуть ниже о том, как выбрать случайный элемент из массива.

    Смотрите пример для альтернативы, которая удаляет слова из woorden массив, заменив его после следующего слова была выбрана. Это гарантирует, что вы никогда не получите одно и то же слово дважды, и вам не нужно использовать рекурсивную суховато проверить.


const array = ["one","two","three"];
var randomItem = array[Math.random() * array.length | 0];

// Note that |0 is a bitwise OR and a short cut for floor when flooring
// positive numbers lower than 2 ** 31
var randomItem = array[Math.floor(Math.random() * array.length)];


  • Не загромождать свой код с шумом. Комментарии должны содержать информацию, которая не может быть выведена из кода.

    В следующем у вас есть 6 комментариев. Спросите вашей собственной личности вы должны прочитать их, чтобы знать, что делает код. Если ответ нет, то они шум и не должно быть.



   function enterWord () {
//If player is not in game
if (inGame == false) {
//Do nothing
} else if (inGame == true) { //Is in game

checkWord();
} }

function checkWord () {
var enteredWord = $("#wordField").val();

//Check if the player typed the correct string
if (enteredWord == currentWord) {
//if true
fadeColor("wordField", "backgroundColor", "rgb(43,234,81)");
$("#wordField").val("");
pickWord();
goodAnswers++;
previousWord = currentWord;

} else {
//if false
amountOfErrors++;
fadeColor("wordField", "backgroundColor", "rgb(234,43,43)");
}
}



  • Вы не должны быть запросы к DOM на одни и те же элементы снова и снова. Запрос дом-это ресурсоемкие и бессмысленно, если вы сделать это для Тот же элемент снова и снова.

    Когда ваш код начинает делать все запросы и хранить элементы для последующего использования.


const wordField = document.querySelector("#wordField");
const currentWord = document.querySelector(("#currentWord");
const errors = document.querySelector("#errors");
const wpm = document.querySelector("#wpm");
const timer = document.querySelector("#timer");
const startBtn = document.querySelector("#startBtn");

Или использовать прямой дом, обратившись по ссылке, чтобы открыть дом. Просто используйте элементы ID в качестве имени переменной. Убедитесь, что элемент с ID являются уникальными на странице.

Пример прямого опорного элемента, а чего не делать.

   <!-- the html -->
<div id = "myElementId">Content</div>

<!-- the following is malformed HTML as the ids are not unique
NEVER DO THIS!
-->
<div id = "badId">bad</div>
<div id = "badId">bad</div>

<!-- the following is malformed HTML as the id and name are not unique
NEVER DO THIS!
-->

<div id = "inputID"> <input name ="inputId></input></div>

<script>
// direct access to the object via its id
myElementId.textContent = "Hi there :)";

// direct access to the non unique badId is now more complicated
// and browser dependent
badId.addEventListeren(); // will throw an error as
</script>

В jQuery

JQuery-это обеспечить поддержку устаревших браузеров, его актуальность становится все более и более сомнительной.

Вы действительно нуждаетесь в jQuery? Большинство из того, что вы используете его для можно сделать, используя собственный API.

Самая негативная обратная сторона с помощью jQuery заключается в том, что вы не получите практику, используя родной дом АФИ. Вы можете видеть в примере, что код можно значительно упростить, не используя jQuery и навыки jQuery не будут востребованы в течение длительного времени, в то время как знания родной дом-это всегда ценность.

Рерайт

Переписывание полностью родной, не нужны дополнительные библиотеки JavaScript.

Я добавил три правила CSS с помощью классов .hide, .wordError, .wordCorrect

Все доступ к элементу осуществляется через прямую ссылку с помощью элемента уникальный идентификатор. Обратите внимание, что элемент id="currentWord" я поменял на ID = "currentWordElement"to prevent it clashing with thecurrentWord переменной определено в Кодексе.



"use strict";
addEventListener("load", () => {

var inGame = false;
var currentWord, amountOfErrors, goodAnswers, endTime;

document.addEventListener("keyup", (event) => {;
if (event.code === "Enter") { checkWord() }
});
startBtn.addEventListener("click", startGame );

const settings = {
woorden : "value,meanwhile,finally,base,spikes,creature,comforts,advanced,the snout,opposite,the spoon,the dust cloud,scrape,natural,significantly,the hedgehog,create,offset,enlarge,treacherous,the direction,the culture,the territory,the timetable".split(","),
errorClass : "wordError",
correctClass : "wordCorrect",
gameTime : 60 * 1000, // time in ms
text : {
complete : "Done...",
errors : "Amount of errors: ",
wpm : "Words per minute: ",
} ,
}

function show(element) { element.classList.remove("hide") }

function hide(element) { element.classList.add("hide") }

function flashColour(type) {
wordField.classList.add(settings[type + "Class"]);
setTimeout(() => wordField.classList.remove(settings[type + "Class"]), 300);
}

function clearWord() {
wordField.value = "";
currentWordElement.textContent = "";
if (currentWord) { settings.woorden.push(currentWord) }
currentWord = undefined;
}

function pickWord () {
const prevWord = currentWord;
currentWord = settings.woorden.splice(Math.random() * settings.woorden.length | 0, 1)[0];
wordField.value = "";
currentWordElement.textContent = currentWord;
if (prevWord) { settings.woorden.push(prevWord) }
}

function startGame() {
endTime = undefined;
inGame = true;
wordField.focus();
goodAnswers = amountOfErrors = 0;
wpm.textContent = errors.textContent = currentWordElement.textContent = "";
pickWord();
show(timer);
hide(startBtn);
displayTimer();

}

function stopGame () {
inGame = false;
hide(timer)
show(startBtn);
clearWord();
currentWordElement.textContent = settings.text.complete;
errors.textContent = settings.text.errors + amountOfErrors;
wpm.textContent = settings.text.wpm + goodAnswers;
}

function displayTimer() {
if (endTime === undefined) { endTime = performance.now() + settings.gameTime }
const remainingTime = endTime - performance.now();
if (remainingTime <= 0) {
timer.textContent = "";
stopGame();
return;
}
timer.textContent = (remainingTime / 1000).toFixed(2);
requestAnimationFrame(displayTimer);
}

function checkWord () {
if (inGame) {
if (wordField.value === currentWord) {
flashColour("correct");
pickWord();
goodAnswers ++;
} else {
amountOfErrors ++;
flashColour("error");
}
}
}
});


@import url('https://fonts.googleapis.com/css?family=IBM+Plex+Mono');

body {
margin: 0;
background-color: rgb(234,43,43);
color: white;
font-family: IBM Plex Mono;
}

.centerDiv {
display: flex;
flex-direction: column;
margin: auto;
width: 100%;
height: 100%;
align-items: center;
text-align: center;
}

.headerDiv {
display: flex;
flex-direction: column;
margin: auto;
width: 100%;
height: 100%;
align-items: center;
text-align: center;
margin: 10px;
margin-bottom: 10%;
}

.header {
font-size: 25px;
}

.textfield {
padding: 10px;
border-radius: 3px;
background-color: white;
color: black;
text-decoration: none;
border: none;
margin: 10px;
font-size: 25px;
transition: all 0.15s ease;
}

.textToType {
font-size: 25px;
margin: 10px;
}

.button {
padding: 10px;
border-radius: 3px;
background-color: white;
color: rgb(234,43,43);
text-decoration: none;
border: none;
margin: 10px;
font-size: 25px;
transition: all 0.15s ease;
}
.button:hover {
cursor: pointer;
transform: scale(1.05);
}
.hide {
display : none;
}
.wordError {
background : rgb(234,43,43);
}

.wordCorrect {
background : rgb(43,234,81);
}


<div class="centerDiv">

<div class="headerDiv">
<a class="header">Typing King</a>
<a>Are you the next typing king?</a>
</div>

<div class="centerDiv">
<a class="textToType" id="currentWordElement"></a>
<input class="textfield" id="wordField" placeholder="Your input"/>
<a class="button" id="startBtn">Start</a>
<a id="timer"></a>
<a id="wpm"></a>
<a id="corrections"></a>
<a id="errors"></a>
</div>

</div>




3
ответ дан 28 марта 2018 в 09:03 Источник Поделиться