вступление
Сегодня мы рассмотрим, как использовать HTML5 Canvas и JavaScript, чтобы сделать простую игру, которую я создал. Теперь я уверен, что это не полностью оригинальная игра, но это просто и просто. Основы игры заключаются в том, что у вас есть неопределенный график узлов. Один узел начинается со всех ценностей (допустим, это кислые конфеты из вишни – это совершенно произвольно), и нам нужно равномерно распределить все конфеты по каждому узлу графика. Например, если у нас есть 8 узлов и 16 конфет, нам нужно будет убедиться, что каждый узел будет получать по двум конфетам.
Начиная
Я взял на себя свободу создать для вас какой -то стартовый код, чтобы нам не приходилось работать над всеми самыми маленькими деталями, и мы можем быстрее сделать игру на мой GitHub.
git clone https://github.com/alexei-dulub/canvas_demo_starter.git
Мы будем использовать http-server Чтобы помочь нам обслуживать наши файлы. Если у вас его еще нет, вы можете использовать следующее для его установки:
npm install http-server -g
Примечание. Если у вас нет NPM, вы можете узнать, как Здесь Анкет
Это установит все необходимое. Теперь, чтобы запустить это может просто бежать
http-server -p 80
Теперь вы должны иметь возможность подключиться к Localhost В вашем браузере, который должен отображать печально известный «Hello World»
Но подождите … что это делает?
Рад, что ты спросил. Давайте начнем с основания всего – HTML.
Здесь мы видим, у нас есть очень простой HTML -скелет, который действительно имеет только одну линию импорта:
Эта строка позволяет веб -странице использовать сценарии, которые мы будем писать на протяжении всего этого учебника. Должны ли мы посмотреть на них сейчас? Начнем с Game.js Файл, так как это тот, который мы призываем в HTML:
import { Logic } from './Logic.js'
const l = new Logic()
Все, что делает этот файл, это начинает логику нашей программы, используя ES6 импорт чтобы мы могли создать новый экземпляр Логика учебный класс. Мы посмотрим, что это значит здесь через секунду, но да, мы могли бы сделать это в Logic.js Файл импортирован здесь; Однако, если у нас был более сложный использование, это хорошая идея, чтобы разделить нашу настройку и нашу основную игровую логику. Итак, посмотрим, что мы здесь импортируем:
export class Logic {
constructor() {
this.lastUpdate = performance.now()
this.updateRate = 32
this.canvas = document.createElement('canvas')
this.ctx = this.canvas.getContext('2d')
this.canvas.width = window.innerWidth
this.canvas.height = window.innerHeight
this.update = this.update.bind(this)
document.body.insertBefore(this.canvas, document.body.childNodes[0])
this.rAF = requestAnimationFrame(this.update)
}
update() {
if (this.lastUpdate < performance.now() - this.updateRate) {
this.lastUpdate = performance.now()
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.font = '90px Arial'
this.ctx.fillStyle = 'black'
this.ctx.fillText('hello world', 0, 90)
}
this.rAF = requestAnimationFrame(this.update)
}
}
Примечание: this.update.update.bind (this) позволяет нам позвонить это Внутри Обновить()
Здесь первое, что вы можете увидеть, это то, что мы экспортируем этот класс. Это то, что позволяет нам импортировать его, как мы видели, было так, как в Game.js Анкет Далее у нас есть Constructor () Функция, которая выполняет всю инициализацию игровой логики для запуска. На самом деле следует отметить, что следующая строка:
this.canvas = document.createElement('canvas')
this.ctx = this.canvas.getContext('2d')
this.canvas.width = window.innerWidth
this.canvas.height = window.innerHeight
То, что мы видим в этих нескольких строках, – это, во -первых, создание холста HTML5, которое мы будем использовать в качестве наша художественная среда на время этого учебника (и если я сделаю свою часть должным образом для будущего времени). Если вы помните, не было Tag в HTML, который мы сделали. Это потому, что мы сделали это здесь!
Далее вы увидите, что мы используем наш недавно созданный холст, чтобы GetContext и сказал, что контекст будет 2 -го размера. Часть «2D» сейчас не важна, но я уверен, что вы, вероятно, можете Угадай, что он делает Анкет Затем мы используем некоторые встроенные атрибуты JavaScript, установив ширину и высоту холста на ширину нашего браузера.
Примечание: мы не будем покрывать изменение размера здесь, поэтому убедитесь, что вы перезагружаете, если ваш холст когда -нибудь выглядит смешно.
Наконец, нам нужно вставить новый элемент в HTML, и мы делаем это со следующим:
document.body.insertBefore(this.canvas, document.body.childNodes[0])
Теперь, когда у нас есть холст, с которым мы можем начать изучать, как мы можем напечатать «Hello Pixelplex» на холст.
update() {
if (this.lastUpdate < performance.now() - this.updateRate) {
this.lastUpdate = performance.now()
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.font = '90px Arial'
this.ctx.fillStyle = 'black'
this.ctx.fillText('Hello PixelPlex', 0, 90)
}
this.rAF = requestAnimationFrame(this.update)
}
Это Update () Функция – это общеизвестное сердце нашей логики, так как это то, что перекачивает жизнь в любые игры или анимации, которые мы создаем на холсте. Хотя в игре, которую мы делаем сегодня, не имеет большой анимации (на самом деле нет), которую можно легко изменить, так как мы уже дали нашу игру в этот цикл.
Что здесь происходит, у нас есть Если Заявление, которое проверяет, настало ли время для сценария, чтобы холст вирировал все вещи, которые мы хотим сделать. Вот как мы можем управлять плавностью и сроками вещей в холсте, и вы можете просто думать об этом как на данный момент как о наших «кадрах в секунду». Таким образом, когда утверждение оценивается в True, это когда мы можем отображать новые вещи. Это когда на самом деле начинается учебник Canvas!
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.ctx.font = '90px Arial'
this.ctx.fillStyle = 'black'
this.ctx.fillText('hello PixelPlex', 0, 90)
Давайте начнем с рассмотрения, что мы используем контекст Мы получили ранее в конструкторе, чтобы выполнить нашу работу. Любые изменения, которые вы хотите внести на холст, действительно сделаны с его контекст и не к холсту напрямую. И вы можете видеть, что первое, что мы делаем, – это очистить прямоугольник, начиная с точек (0, 0) И размер его такого же размера, как и холст. Другими словами, мы очистили весь экран. Это очень важно, так как холст не делает этого для вас. Если вы пренебрегаете этой линией, вы заметите много совпадений элементов и вещей, особенно когда вы делаете более сложные вещи.
Следующие несколько строк более просты. Вы можете видеть, что мы устанавливаем шрифт а затем FillStyle (Что на самом деле просто означает, какой цвет вы хотите заполнить), и в конце концов мы используем FillText функция, которая дана то, что будет текстом, а также (x, y) поместить нижний левый угол текста. Обратите внимание на жирную жирку там. Размещение вещей в холст – это искусство, и сначала оно будет запутанным, когда вы используете эту функцию, но она может не отображаться. Это может произойти из -за того, что часть использования текста в деталях для того, чтобы поместить в желаемое (x, y) Так что просто будь осторожен.
Последнее, что можно покрыть, прежде чем мы сможем начать, – это последняя строка, которую мы видим в нашем Update () Функция:
this.rAF = requestAnimationFrame(this.update)
Резкое зрение может заметить, что эта линия не только исходит от Update () функция, но и Constructor () также… Причина, по которой мы находим это в Constructor () потому что эта линия начинает весь процесс цикла. Вот почему мы передаем это this.update Поскольку мы хотим использовать эту функцию для каждой анимационной кадры. Это также та же причина, по которой это называется каждый раз в конце Update () функция (независимо от оценки оператора if ). Мы называем это петлей анимации, и это не может быть петлей, если он не цикл, верно? В основном нам нужно позвонить Update () Функция в конце Update () функционируйте так, чтобы это было вызывалось снова и снова до конца времени или мы покидаем страницу. Все это объединено, что дает нам эту основу игры с использованием HTML Canvas!
Теперь … это было много, если вы никогда не делали ничего из этого и все еще со мной. Поххайте себя по спине и сделайте быстрый перерыв, сыграв с некоторыми ценностями в либо в Update () (Например, поиграйте с тем, где визуализируется текст или что он говорит, или какой он цвет!) И, возможно, поиграйте с чем -то в конструкторе (например, что произойдет, если вы измените обновления выше или ниже?). Попробуйте некоторые из этих вещей, и я увижу вас во второй половине учебника!
Мы начнем делать игру сейчас, Обещаю
В качестве резюме мы работаем над созданием игры, которая включает в себя распределение стоимости среди набора узлов (в нашем случае 8). Узлы подключены для того, чтобы сделать неизорированный график, что означает, что значение может течь из любого подключенного узла. Итак, давайте начнем с получения некоторых узлов на нашем холсте, не так ли?
export class Node {
constructor(ctx, x, y) {
this.ctx = ctx
this.x = x
this.y = y
this.fill = 'red'
this.size = 50
}
draw() {
this.ctx.fillStyle = this.fill
this.ctx.beginPath()
this.ctx.rect(this.x, this.y, this.size, this.size)
this.ctx.fill()
}
}
Мы начнем с создания нового Узел класс для использования. Этот класс послужит для нас местом для реализации любых функций, которые мы хотим, чтобы узлы имели позже. Мы видим знакомые элементы, такие как Constructor () Но что -то немного другое здесь, это Draw () функция Это то, что должно быть названо внутри Update () Функция в нашей анимационной петле. Draw () Это то, где мы определяем, как мы хотим, чтобы узел выглядел, и если мы хотим, чтобы это выглядело динамично, мы используем множество переменных и вызовов для атрибутов это Итак, как Узел Изменения экземпляра будут отражаться каждый раз, когда производится новая кадр. В нашей розыгрыше мы рисуем красный прямоугольник. Процесс похож на рисование «Hello World» из раньше. Поскольку это должно быть вызвано в Update () Функция нашего Логика Давайте добавим это сейчас.
update() {
if (this.lastUpdate < performance.now() - this.updateRate) {
this.lastUpdate = performance.now()
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
let node = new Node(this.ctx, 200, 200)
node.draw()
}
this.rAF = requestAnimationFrame(this.update);
}
Update () функция в Logic.js заменил текст созданием нового Узел пример А потом вызов этого экземпляра Draw () функция Теперь мы должны увидеть один единственный узел (красный прямоугольник) в (200, 200) Анкет Но нам нужно еще 7 узлов, чтобы сделать наш график, поэтому давайте изменим это.
import { Node } from './Node.js'
constructor() {
...;
this.nodes = []
...;
this.makeGraph()
...;
}
makeGraph() {
for(let x = 0; x < 8; x++) {
this.nodes.push(new Node(this.ctx, 100*x, 100))
}
}
Примечание: только изменения в Constructor () показаны в фрагменте выше.
В Constructor () Мы добавили новый узлы атрибут для Логика Чтобы отслеживать, а затем мы сделали новую функцию, которая вызывается после создания массива. В MakeGraph () Мы используем для Цикл, чтобы добавить 8 узлов в массив, используя счетчик, чтобы изменить местоположение каждого для визуальной проверки (мы видим их все). Теперь мы можем изменить рисунок одного узла, чтобы нарисовать все восемь наших свежеприготовленных узлов следующим образом:
update() {
...;
this.nodes.forEach(node => {
node.draw()
return
})
...;
}
Помните кружок подразделения?
Таким образом, я не буду опросить на круге подразделения как такового, но мы будем отряжать некоторую тригонометрию и использовать встроенный JavaScript Математика библиотека. Формирование, которое мы имеем для узлов прямо сейчас, все в порядке и тщательно, но на самом деле она не сделает хороший график, поэтому давайте поработаем над расположением узлов в кругу, чтобы мы могли сделать несколько крутых шаблонов позже.
makeGraph() {
let x = this.canvas.width/2
let y = this.canvas.height/2
let angle = 360/8
for(let i = 1; i <= 8; i++) {
let nX = x + this.radius * Math.cos((angle*i)*Math.PI/180)
let nY = y + this.radius * Math.sin((angle*i)*Math.PI/180)
this.nodes.push(new Node(this.ctx, nX, nY))
}
}
Примечание: this.radius определено в Constructor () как this.radius = 200
Выше является нашим новым примером MakeGraph () найдено в Logic.js Анкет Это будет равномерно распределять 8 узлов по кругу (и с некоторыми незначительными модификациями он может потребовать динамического количества узлов и при этом равномерно распространять их равномерно!). Мы начнем с поиска центра холста. Затем мы делим 360 (градусы) на количество узлов, которые мы хотели бы создать. Тогда у нас есть для петля, как и раньше, но на этот раз мы угол соответствующего узла ( angle *i ) преобразованы в радианы ( *Math. Пи/180 ) и затем найдите COS/SIN и умножьте его на радиус 200. Затем мы добавляем это значение в x/y, чтобы компенсировать его из центра. Эти рассчитанные значения затем используются в качестве местоположения для каждого узла. Эти функции станут действительно знакомыми, если вы продолжите делать более сложные вещи на холсте, особенно в том, что он включает в себя вращение, и это облегчало то, что на холсте было легко отслеживать игрока, такой как враг, если он знает угол между Игрок и сам. Но это что -то для другого дня.
Соединение точек, я имею в виду, узлы …
Потрясающе, теперь, когда у нас есть наши узлы, отображающиеся в несколько интересной формировании, давайте подключим их как визуально, так и в памяти. Мы начнем с добавления следующего в Constructor () :
this.connections = []
Это поможет нам отслеживать соединения каждого узла позже, когда мы начнем передавать значения. Чтобы начать использовать это, мы сделаем следующую функцию в нашем Узел учебный класс:
addConnection(connection) {
this.connections.push(connection)
}
Просто, но такой элегантный. Все, что мы делаем здесь, – это добавление Узел к нашей коллекции соединений (скажем, в пять раз быстрее), чтобы мы могли работать позже. Теперь, когда у нас есть Узлы Подключен через память, давайте начнем визуально подключать их к холстам для нашего игрока.
getX() {
return this.x
}
getY() {
return this.y
}
drawConnection(connection) {
this.ctx.beginPath()
this.ctx.moveTo(this.x+(this.size/2), this.y+(this.size/2))
this.ctx.lineTo(connection.getX()+(this.size/2), connection.getY()+(this.size/2))
this.ctx.stroke()
}
drawNode() {
this.ctx.beginPath()
this.ctx.rect(this.x, this.y, this.size, this.size)
this.ctx.fill()
}
ПРИМЕЧАНИЕ: изменение заполнения придет сразу после этой части
В этом раунде мы добавили четыре новых функции в нашем Узел учебный класс. Первые два просто возвращают x или y соответствующего узла, и вы можете понять, почему, когда мы рассмотрим третью функцию DrawConnection () Анкет Это использует тот же рисунок рисования, который мы уже видели с холстом, но все, что он рисует, – это прямая черная линия от нашего узла до подключенного узла. И, как вы можете видеть, использует getX () и gety () Мы тоже сделали. Аккуратный!
Наконец, это DrawNode () функция, которая предназначена исключительно для последовательности и ясности. Поскольку мы рисуем соединения в их собственной функции, я думал, что это будет иметь смысл, а также выглядеть лучше, чтобы узел был нарисован в отдельной функции. Вы обнаружите, что когда вы будете работать над более сложными проектами, которые складывают наше рендеринг ты ищешь. Извините за бег на предложении, и нет, я никогда не писал ничего грязного …
Это затем приводит нас к тому, что меняется в главном Draw () функционируйте сейчас. С приведенными выше изменениями это выглядит следующим образом:
draw() {
this.connections.forEach(connection => {
this.drawConnection(connection)
})
this.drawNode()
}
Это сводится к простому foreach петля на всех Узел Подключения, а затем вызов нашего недавно созданного DrawNode () функция Итак, теперь, когда мы дали узлам возможность устанавливать связи и нарисовать их, давайте используем это в нашем Логика Анкет
constructor() {
...;
for(let i = 0; i < 8; i++) {
this.nodes[i].addConnection(this.nodes[1])
this.nodes[1].addConnection(this.nodes[i])
this.nodes[i].addConnection(this.nodes[2])
this.nodes[2].addConnection(this.nodes[i])
}
}
То, что у нас есть, это для петля в конце нашего Constructor () и это звонит AddConnection функция, которую мы только что сделали. Вы можете заметить, что мы называем это дважды для каждого отношения (просто заменив индекс на массиве). Это связано с тем, что мы делаем неправомерный график, поэтому нам нужно оба узла, чтобы осознавать их взаимные отношения; это важно. Теперь мы должны увидеть, что у нас есть наши узлы, и они связаны по линиям. Не волнуйтесь на данный момент, если некоторые из строк, кажется, закончились или под узлами. Это связано с порядок рендеринга, и мы не сосредоточимся на нем сегодня.
Красный свет, зеленый свет
Хорошо, у нас есть график. Как насчет того, чтобы дать узлам немного больше функциональности, так как это должна быть игра в конце концов. Мы начнем с того, что дадим игроку какую -то указание на то, что они движутся в правильном направлении? Давайте заставим узлы изменить цвет, когда они приближаются к решению головоломки.
constructor(ctx, x, y, ideal) {
...;
this.value = 0
this.idealValue = ideal
}
Здесь мы меняем Constructor () Немного, чтобы мы могли рассказать узлам, каково их идеальное значение, и мы также должны отслеживать путешествие узла к этому идеальному значению, имея значение Атрибут, который является представителем того, что игрок пытается сбалансировать. И проницательный там заметит, что это также означает, что нам придется изменить то, как мы возвращаем узлы в Logic.js файл.
this.nodes.push(new Node(this.ctx, nX, nY, 2))
Итак, теперь, когда у нас есть представление о том, какую ценность мы хотим, а также, какую ценность мы в настоящее время находимся, давайте изменить заполнение узла на основе этой новой информации:
setFill() {
if(this.value/this.idealValue < 0.33) {
this.ctx.fillStyle = 'red'
}
else if(this.value/this.idealValue > 0.33 && this.value/this.idealValue < 0.66) {
this.ctx.fillStyle = 'orange'
}
else if(this.value/this.idealValue > 0.66 && this.value/this.idealValue < 1) {
this.ctx.fillStyle = 'yellow'
}
else if(this.value/this.idealValue === 1) {
this.ctx.fillStyle = 'green'
}
else if(this.value/this.idealValue > 1) {
this.ctx.fillStyle = 'purple'
}
}
То, что мы делаем здесь, это серия Если Заявления, которые стремятся увидеть, какое значение соотношение значения узла сравнивается с его идеальным значением. Таким образом, если он ниже 33%, узел красный, от 33% до 66% оранжевый, от 66% до 100% желтого (вы приближаетесь), и если это на 100%, что означает, что значение это Идеальное значение, тогда он станет зеленым. Если это более 100%, что означает, что узел имеет слишком большое значение, он фиолетовый. Не стесняйтесь делать свою собственную цветовую схему или даже исследовать способ сделать окраску более постепенным.
Теперь, чтобы использовать все, что нам нужно сделать, это позвонить setFill () в DrawNode () функция
drawNode() {
this.setFill()
...;
}
То, как все настраивается прямо сейчас, игра никогда не может быть выиграна (если идеал не нулевой, то ¯ \ _ (ツ) _/¯), но нам понадобится функция, чтобы мы могли хотя бы установить значение одного узла иметь достаточную ценность, чтобы решить головоломку. В Узел Класс Мы делаем следующее:
setValue(val) {
this.value = val
}
Тогда в Логика класс Constructor () У нас есть следующая линия после цикла, создающего соединения:
this.nodes[0].setValue(16)
Теперь со всем этим у нас должны быть в основном красные узлы, но один из них будет фиолетовым, так как это 800% от стоимости.
console.log (‘click!’)
Теперь, когда у нас есть большинство наших визуальных эффектов, мы можем начать добавлять элементы управления для игрока, чтобы взаимодействовать с нашим шедевром. Начнем с редактирования Логика учебный класс. Давайте добавим следующие два элемента в конструктор( ) :
this.selectedNode = null
this.handleClick = this.handleClick.bind(this)
window.addEventListener('click', this.handleClick)
this.canvas.addEventListener('contextmenu', this.handleClick)
Мы видели привязку к это , но что -то новое – это addEventListener . Это встроенный JavaScript, и он позволяет нам делать то, что JavaScript лучше всего делает: ответьте на события. На что мы отвечаем здесь, так это событие «клик», как в щелчке мыши на нашей мышью в окне браузера. Точно так же мы слушаем событие «Contextmenu» на холсте. Что это за событие, спросите вы? Это просто означает щелчок правой кнопкой мыши на холсте. Если бы мы этого не сделали, мы не сможем щелкнуть правой кнопкой мыши. Хорошо, круто, но Handleclick Разве не функция Логика … пока что.
handleClick(e) {
let x = e.clientX
let y = e.clientY
if (e.button === 0) {
this.nodes.forEach(node => {
if (node.wasClicked(x, y)) {
let selected = this.nodes.filter(n => n.isSelected)
let toDeselect = selected[0] ? selected[0] : null
if (toDeselect) toDeselect.deselect()
node.select()
this.selectedNode = node
}
})
}
else if (e.button === 2) {
this.nodes.forEach(node => {
if (node.wasClicked(x, y)) {
if (this.selectedNode.getValue() > 0 &&
this.selectedNode.isConnection(node)) {
node.incrementValue()
this.selectedNode.decrementValue()
}
}
})
}
}
В этой функции мы используем объект события, переданный нашей функции (эффект добавления прослушивателя событий), чтобы мы могли точно знать, где пользователь щелкнул в окно. Затем у нас есть Если оператор, который проверит, где это был левый (0) или правый (2) нажмите. Если это щелчок слева, мы проверяем, был ли выбран какой -либо из узлов (более позднее). Если кто -то был нажат, то мы отменили выбор в настоящее время выбранного узла и сделаем щелкенный узел выбранным узлом. Это наша функциональность для выбора, из какого узла для передачи значения!
Когда это щелкнет правой кнопкой мыши, мы видим, нажимали ли узел узел. Если кто -то был нажат, мы затем проверяем, есть ли выбранное узел даже для предоставления, и если это так, это нажатый узел является подключением выбранного узла. Если узел передает все это, проверьте, что значение щелченого узла увеличивается, а значение выбранного узла уменьшится. Передача значений!
У нас эта логика реализована, ну, в общем, Логика Класс, но там было много функций, которые Узел нет. Давайте изменим это. Мы начнем с изменения Узел S Constructor () еще раз.
constructor(id, ctx, x, y, ideal) {
this.id = id
this.isSelected = false
...;
}
getId() {
return this.id
}
deselect() {
this.isSelected = false
}
Чтобы лучше отслеживать наши связи, нам нужно будет дать узлы идентификаторы, и мы увидим немного. И, естественно, это означает, что нам придется также изменить там, где мы создаем все узлы
this.nodes.push(new Node(i, this.ctx, nX, nY, 2))
Примечание: помните, что это в для цикл, который объявляет все узлы так я это значение из петли.
Далее в основном простые функции манипуляции с данными:
getValue() {
return this.value
}
decrementValue() {
this.value -= 1
console.log(this.value)
}
incrementValue() {
this.value += 1
console.log(this.value)
}
isConnection(node) {
return this.connections.filter(c => c.getId() === node.getId()).length === 1
}
Единственное, что стоит отметить из этого блока, это isConnection () Функция, где мы возвращаем логический Отфильтровывая соединения, у узла есть узел, который вернет новый массив с любыми значениями, которые оцениваются на истину на основе оператора, приведенного в качестве параметра. Затем мы сравниваем длину этого «возвращаемого» массива (из которого мы на самом деле не присваиваем его), и этой длины – 1, это означает, что узел, переданный к функции, действительно является подключением текущего узла, что приводит к Возврат истинный в противном случае a ложный возвращается.
Но как мне выиграть?
Мы почти на месте! Но мы должны убедиться, что игрок знает, что он выиграл. Мы начнем с добавления одной окончательной функции в нашу Узел учебный класс:
isSatisfied() {
return this.value/this.idealValue === 1
}
Это убедится, что мы сможем проверить, что все наши узлы счастливы, потому что, когда они есть, мы достигли состояния победы. Давайте сделаем Логика Знает об этом сейчас, изменив Update () Функция:
update() {
let playerWon = true
if (this.lastUpdate < performance.now() - this.updateRate) {
this.lastUpdate = performance.now()
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
this.nodes.forEach(node => {
if (playerWon) {
playerWon = node.isSatisfied()
}
node.draw()
})
if (!playerWon) {
this.ctx.fillStyle = 'black'
this.ctx.font = "90px Arial"
this.ctx.fillText("You Won!", this.canvas.width*.41, this.canvas.height*.1)
}
this.ctx.fillStyle = 'black'
this.ctx.font = "30px Arial"
this.ctx.fillText("Left Click to select a node. Right Click on a node to transfer value from the selected node. Try to turn all of the nodes green.", this.canvas.width*.18, this.canvas.height*.95)
}
this.rAF = requestAnimationFrame(this.update);
}
Вы можете видеть, что когда мы рендерируем каждый узел, мы также проверяем, удовлетворены ли они. Если один узел не соответствует этой квалификации, он сделает Playerwon переменная ложный Это означает, что он не будет отображать сообщение о победе. И наоборот, если все узлы будут удовлетворены, это останется Верно позволяя представить сообщение, информируя пользователя о своей победе. Вы также заметите сообщение, которое Allway, отображаемое внизу, чтобы мы могли дать пользователю немного руководства по элементам управления. Не стесняйтесь изменить сообщение на то, что вам нравится.
Вывод
И это это! Мы сделали игру, используя JavaScript и холст HTML5, и это было на самом деле только поверхность. Мы рассмотрели дизайн, триг, методы программирования и множество других битов Javascripts. Я надеюсь, что это был веселый и приятный опыт для вас, и что вы также были успешными и вдохновлены в создании этого наряду с учебником. Если были некоторые удары, вы всегда можете проверить готовую версию на моем GitHub Анкет Вы также можете проверить историю коммита, чтобы изучить мой мыслительный процесс, и вы обнаружите, что она очень напоминает этот учебник.
Оригинал: “https://dev.to/pixelplex/making-a-simple-game-using-html-canvas-and-javascript-2p96”