Добавлен: 29.04.2024
Просмотров: 7
Скачиваний: 0
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
М ИНИСТЕРСТВО НАУКИ И ВЫСШЕГО ОБРАЗОВАНИЯ РОССИЙСКОЙ ФЕДЕРАЦИИ
федеральное государственное бюджетное образовательное учреждение высшего образования
«МОСКОВСКИЙ АВТОМОБИЛЬНО-ДОРОЖНЫЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ (МАДИ)»
Кафедра: «Автоматизированные системы управления»
Курсовая раБота
«Лабиринт»
Выполнил: | |
| Никитин Н.А. |
(подпись) | |
..2023 | |
Проверено (принято): | |
| Пахунов А. В. |
(подпись) | |
..2023 |
Москва, 2023 г.
Оглавление
Введение 3
HTML файл 4
CSS файл 7
JavaScript файл 12
Заключение 26
Введение
Цель курсовой работы – создать лабиринт с использованием HTML, CSS и JavaScript, современных технологий и сети Интернет.
Требования:
-
При генерации самого лабиринта результат всегда должен быть различным; -
Игрок всегда может достигнуть финиша; -
Должен быть счётчик жизней; -
Столкновение со стеной – потеря жизни; -
Счётчик жизней равен нулю – проигрыш и появляется уведомление; -
Игрок дошёл до цели – выигрыш и соответствующее уведомление;
HTML файл
Код:
html>
Количество жизней:
предназначен для хранения содержания веб-страницы (тела сайта), отображаемого в окне браузера.
Чтобы обратиться из скрипта из head к элементам страницы, надо дождаться отлавливания одного из событий: DomContentLoaded, Load. Затем же к скрипту можно обратиться по объекту document.
Элемент
является блочным элементом и предназначен для выделения фрагмента документа с целью изменения вида содержимого. Чтобы не описывать каждый раз стиль внутри тега, можно выделить стиль во внешнюю таблицу стилей, а для тега добавить атрибут class или id с именем селектора.
Элемент <input> с типом button отображаются как простые кнопки, которые можно запрограммировать для управления пользовательскими функциями в любом месте веб-страницы, например, назначить функцию обработки события. Хотя элементы с типом button по-прежнему являются абсолютно корректными в HTML, новый элемент теперь является предпочтительным способом создания кнопок. Учитывая, что текст элемента вставлен между открывающим и закрывающим тегами, вы можете включить в тег HTML, даже изображения.Атрибут значения элементов value содержит строку DOMString, которая используется в качестве метки кнопки. В данном случае это Reset, то есть перезапуск.
CSS файл
Код:
.cont{
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-items: center;
}
#test{
text-align: center;
width:420px;
font-size: 25px;
}
#maze {
border-style: solid;
}
.block {
float: left;
height: 20px;
width: 20px;
}
.wall {
background-color: black;
}
.me {
position: relative;
}
.me:after {
background-color: red;
border-radius: 100%;
content: '';
height: 20px;
position: absolute;
top: 0;
width: 20px;
}
.finish {
background-color: red;
}
body{
background: no-repeat center fixed;
background-size: cover;
}
::after создаёт псевдоэлемент, который является последним потомком выбранного элемента. Часто используется для добавления косметического содержимого в элемент с помощью свойства content. По умолчанию является инлайновым.
#name - базовый селектор, который выбирает элементы, основываясь на значении их id атрибута.
.name - базовый селектор, который выбирает элементы, основываясь на значении их атрибута class.
display: flex - многоцелевое свойство, которое определяет, как элемент должен быть показан в документе.
После установки данных значений, каждый дочерний элемент автоматически становится flex-элементом, выстраиваясь в один ряд (вдоль главной оси). При этом блочные и строчные дочерние элементы ведут себя одинаково, то есть ширина блоков равна ширине их содержимого с учетом внутренних полей и рамок элемента.
flex-direction: column
flex-direction - CSS свойство, указывающее на то, как flex-элементы располагаются во flex-контейнере по главной оси и направлению (нормальное или обратное).
column - Главная ось располагается вертикально и направлена сверху вниз. Точки main-start и main-end такие же, как точки before и after режима записи (writing-mode).
flex-wrap: wrap
Свойство CSS flex-wrap задаёт правила вывода flex-элементов — в одну строку или в несколько, с переносом блоков. Если перенос разрешён, то возможно задать направление, в котором выводятся блоки.
wrap - расположение в несколько линий. Свойство cross-start эквивалентно start или before в зависимости от значения flex-direction и свойство cross-end противоположно cross-start.
align-items: center - Центрирует элементы в поперечной оси.
Свойство align-items выравнивает флекс-элементы внутри контейнера в перпендикулярном направлении.
В программе же элементы центрируются по горизонтали.
text-align: center - выравнивание текста по центру. Текст помещается по центру горизонтали окна браузера или контейнера, где расположен текстовый блок.
text-align - определяет горизонтальное выравнивание текста в пределах элемента.
width - Устанавливает ширину блочных или заменяемых элементов
font-size определяет размер шрифта.
border-style: solid – отображает одну прямую сплошную линию.
Устанавливает стиль границы вокруг элемента.
float: left
Свойство float CSS указывает, что элемент должен быть взят из нормального потока и помещён вдоль левой или правой стороны его контейнера, где текст и встроенные элементы будут обтекать его.
left - ключевое слово, указывающее, что элемент должен находиться в левой части содержащего его блока.
height -устанавливает высоту элемента.
background-color - устанавливает цвет фона элемента.
position: relative
Свойство css position указывает, как элемент позиционируется в документе.
relative - элемент позиционируется в соответствии с нормальным потоком документа, а затем смещается относительно себя на основе значений top, right, bottom и left. Смещение не влияет на положение любых других элементов; таким образом, пространство, заданное для элемента в макете страницы, такое же, как если бы позиция была static.
border-radius - это CSS-свойство, позволяющее разработчикам определять, как скругляются границы блока. Закруглённость каждого угла определяется с помощью одного или двух радиусов, определяя его форму: круг или эллипс.
content - заменяет элемент сгенерированным значением. Применяется ко все элементам, древовидным псевдоэлементам и полям страницы.
top - для позиционированного элемента определяет расстояние от верхнего края родительского элемента до верхнего края дочернего элемента
Сокращённое CSS свойство background устанавливает сразу все свойства стиля фона, такие как цвет, изображение, источник и размер, или метод повтора.
Свойство background: no-repeat устанавливает, как фоновые изображения будет повторяться. Они могут повторяться по горизонтальной и вертикальной оси или не повторяться вовсе.
Свойство background: center размещает изображения по центру веб-страницы (тела сайта). Положение относительно уровня положения, установленного background-origin.
background: fixed - фон фиксируется относительно области просмотра. Даже если элемент имеет механизм прокрутки, фон не перемещается вместе с элементом.
Универсальное свойство background позволяет установить одновременно до пяти характеристик фона. Значения могут идти в любом порядке, браузер сам определит, какое из них соответствует нужному свойству. Для подробного ознакомления смотрите информацию о каждом свойстве отдельно. В CSS3 допустимо указывать параметры сразу нескольких фонов, перечисляя их через запятую.
background-size в CSS масштабирует фоновое изображение согласно заданным размерам. Изображение может быть оставлено в исходном размере, растянуто, или подогнано под размеры доступного пространства. Задает размер в любых доступных для CSS единицах — пикселы (px), сантиметры (cm), em и др.
cover - Ключевое слово, обратное contain. Масштабирует изображение как можно больше c сохранением пропорций изображения (изображение не становится сплющенным). Когда изображение и контейнер имеют разные размеры, изображение обрезается либо влево / вправо, либо сверху / снизу.
contain - масштабирует картинку так, чтобы она максимально накрыла собой весь блок. Картинка при этом не обрезается, а вписывается в блок с сохранением пропорций. Это свойство полезно на страницах, содержащих много независимых виджетов, так как его можно использовать для предотвращения побочных эффектов внутренних элементов каждого виджета за пределами ограничивающей рамки виджета.
JavaScript файл
Код:
document.addEventListener("DOMContentLoaded",gen)
function gen(){
main(20, 20, [], [], [0, 0]);
document.querySelector('.reset').addEventListener('click', function(){location.reload()});
}
function main(height, width, maze, walls, currentPosition) {
count = 3;
height = height % 2 === 0 ? height + 1 : height; //Условный оператор
width = width % 2 === 0 ? width + 1 : width;
document.getElementById('test').innerHTML = 'Жизни:'+ `♥ `.repeat(count); //Отображение счета
document.getElementById('maze').setAttribute('style', 'height:' + height * 20
+ 'px; width:' + width * 20 + 'px');
//Устанавливает атрибуты
for (let y = 0; y < height; y++) {
maze[y] = [];
for (let x = 0; x < width; maze[y][x++] = 'wall') { //заполнение массива значением 'wall'
let el = document.getElementById('maze').appendChild(document.createElement("div"));
el.className = 'block wall';
el.setAttribute('id', y + '-' + x);
}
} //Генерация div'ов вначале по высоте, потом по ширине и заполнение лабиринта стенами
function amaze(y, x, addBlockWalls) {
maze[y][x] = 'maze';
document.getElementById(y + '-' + x).classList.remove('wall'); //присвоение класса
if (addBlockWalls && valid(y + 1, x) && (maze[y + 1][x] === 'wall')) walls.push([y + 1, x, [y, x]]);
if (addBlockWalls && valid(y - 1, x) && (maze[y - 1][x] === 'wall')) walls.push([y - 1, x, [y, x]]);
if (addBlockWalls && valid(y, x + 1) && (maze[y][x + 1] === 'wall')) walls.push([y, x + 1, [y, x]]);
if (addBlockWalls && valid(y, x - 1) && (maze[y][x - 1] === 'wall')) walls.push([y, x - 1, [y, x]]);
//заполнение новыми значениями и актуальными
}
function valid(a, b) {
return (a < height && a >= 0 && b < width && b >= 0);
}
amaze(currentPosition[0], currentPosition[1], true);
while (walls.length !== 0) {
let randomWall = walls[Math.floor(Math.random() * walls.length)], //получение случайной стенки
host = randomWall[2],//смотрит на актуальные координаты
opposite = [(host[0] + (randomWall[0] - host[0]) * 2), (host[1] + (randomWall[1] - host[1]) * 2)];
if (valid(opposite[0], opposite[1])) {
if (maze[opposite[0]][opposite[1]] === 'maze') walls.splice(walls.indexOf(randomWall), 1);
else amaze(randomWall[0], randomWall[1], false), amaze(opposite[0], opposite[1], true);
} else walls.splice(walls.indexOf(randomWall), 1);
}
document.getElementById('0-0').classList.add('me');
//Реализация точки старта
document.getElementById((parseInt(height) - 1) + '-' + (parseInt(width) - 1)).classList.add('finish');
//Реализация точки финиша
onkeydown = function(e) {
let x = e.key
if ((currentPosition[0] !== height - 1) || (currentPosition[1] !== width - 1)) {
if (count > 0) {
if (x === 'ArrowLeft' || x === 'ArrowRight' || x === 'ArrowUp' || x === 'ArrowDown') {
const mass = new Map([
['ArrowLeft', 1],
['ArrowRight', 3],
['ArrowUp', 2],
['ArrowDown',4]
])
let newPosition = [currentPosition[0] + ((mass.get(x) - 3) % 2), currentPosition[1] + ((mass.get(x) - 2) % 2)];
if (valid(newPosition[0], newPosition[1]) && maze[newPosition[0]][newPosition[1]] !== 'wall') {
document.getElementById(currentPosition[0] + '-' + currentPosition[1]).classList.remove('me');
currentPosition = newPosition;
document.getElementById(currentPosition[0] + '-' + currentPosition[1]).classList.add('me');
if (currentPosition[0] === height - 1 && currentPosition[1] === width - 1) {
document.body.innerHTML = "";
document.body.style.backgroundImage = 'url(win.jpg)';
}
} else {
if(x!=='f' && x!=='а') {
count -= 1
document.getElementById('test').innerHTML = 'Жизни:' + `♥ `.repeat(count);
}
if (count === 0) {
document.body.innerHTML = "";
document.body.style.backgroundImage = 'url(lose.jpg)';
}
}
}
}
}
if ((currentPosition[0] === height - 1) || (currentPosition[1] === width - 1)) {
if (x==='f' || x==='а') document.location.reload()
}
if (count===0 && (x==='f' || x==='а')) document.location.reload()
}
}
Const
Значение констант не может быть изменено новым присваиванием, а также не может быть переопределено. Константы (const) подчиняются области видимости уровня блока так же, как переменные, объявленные с использованием ключевого слова let.
nameN
Имя константы. Подчиняется тем же правилам, что и идентификаторы обычных переменных.
valueN
Значение константы. Может быть любым из тех типов, которые могут быть для переменных, включая функцию.
Интерфейс EventTarget реализуется объектами, которые могут принимать и обрабатывать события, например, такими как Element, Document, Window и XMLHttpRequest.
JavaScript метод addEventListener() объекта EventTarget позволяет зарегистрировать обработчик событий определенного типа для конкретной цели.
В качестве цели могут выступать как такие объекты как Element, Document, Window, или любые другие объекты, которые поддерживают события, например, такой объект как XMLHttpRequest, который широко используется в асинхронных запросах AJAX (от англ. Asynchronous Javascript and XML — "асинхронный JavaScript и XML"), что позволяет конкретной странице обновлять только её часть, не нарушая при этом работу пользователя.
Обратим внимание на то, что можно использовать метод removeEventListener() для удаления обработчика событий, присоединенного с помощью метода addEventListener().
Некоторые варианты событий:
События загрузки документа. Пример: событие load происходит, когда ресурс и его зависимые ресурсы закончили загружаться.
События мыши. Пример: click - высокоуровневое событие, возбуждаемое, когда пользователь нажимает и отпускает кнопку мыши или иным образом активирует элемент.
События ввода текста. Пример: Событие input срабатывает тут же при изменении значения текстового элемента и поддерживается всеми браузерами, кроме IE8.
События клавиатуры. Пример: события keydown и keyup возбуждаются, когда пользователь нажимает или отпускает клавишу на клавиатуре.
Событие DOMContentLoaded происходит, когда весь HTML был полностью загружен и пройден парсером, не дожидаясь окончания загрузки таблиц стилей, изображений и фреймов. Разница между DOMContentLoaded и load заключается в том, что событие load происходит, когда браузер загрузил HTML и внешние ресурсы (картинки, стили и т.д.)
В данном случае вызывается функция gen.
Функция в JavaScript - это специальный тип объектов, позволяющий формализовать средствами языка определённую логику поведения и обработки данных. Это фрагмент программного кода (подпрограмма), в большинстве случаев связанный с идентификатором, к которому можно обратиться из другого места программы. После выполнения функции управление возвращается обратно в точку программы, где данная функция была вызвана.
Функции позволяют не повторять один и тот же код во многих местах программы и являются основными «строительными блоками» программ.
Функция gen, которая вызывает функцию main с передачей указанных параметров, тут же и создаются массивы maze, walls и currentPosition.
Document метод querySelector() возвращает первый элемент документа, который соответствует указанному селектору или группе селекторов. Если совпадений не найдено, возвращает значение null.
Метод location.reload() перезагружает ресурс из текущего URL подобно кнопке обновления браузера.
Содержимое функции main:
Директива let объявляет переменную с блочной областью видимости с возможностью инициализировать её значением.
Оператор var объявляет переменную, инициализируя её, при необходимости.
Объявление переменной всегда обрабатывается до выполнения кода, где бы она ни находилась. Область видимости переменной, объявленной через var, это её текущий контекст выполнения. Который может ограничиваться функцией или быть глобальным, для переменных, объявленных за пределами функции.
Присвоение значения необъявленной переменной подразумевает, что она будет создана как глобальная переменная (переменная становится свойством глобального объекта) после выполнения присваивания значения. Различия между объявленной и необъявленной переменными следующие:
Директива let позволяет объявить локальную переменную с областью видимости, ограниченной текущим блоком кода. В отличие от ключевого слова var, которое объявляет переменную глобально или локально во всей функции, независимо от области блока.
Если объявлять переменную, не используя "var", то она всегда будет глобальной.
Переменная count отвечает за количество жизней.
В переменные height и width всегда записывается нечетное значение.
Проверка значений происходит с помощью условного оператора. Условный (тернарный) оператор - единственный оператор в JavaScript, принимающий три операнда: условие, за которым следует знак вопроса (?), затем выражение, которое выполняется, если условие истинно, сопровождается двоеточием (:), и, наконец, выражение, которое выполняется, если условие ложно. Он часто используется в качестве укороченного варианта условного оператора if.
document.getElementById() - возвращает ссылку на элемент по его идентификатору (id). Идентификатор является строкой, которая может быть использована для идентификации элемента; она может быть определена при помощи атрибута id в HTML или из скрипта.
Element.innerHTML - свойство интерфейса, которое устанавливает или получает HTML или XML разметку дочерних элементов.
Метод repeat() конструирует и возвращает новую строку, содержащую указанное количество соединённых вместе копий строки, на которой он был вызван.
Element.setAttribute() - добавляет новый атрибут или изменяет значение существующего атрибута у выбранного элемента.
В данном случае атрибуту style задаем параметры высоты и ширины элементов.
Выражение for создаёт цикл, состоящий из 3 необязательных выражений в круглых скобках, разделённых точками с запятой.
Синтаксис: for ([инициализация]; [условие]; [финальное выражение]) выражение.
В данном случае цикл работает, пока значение y меньше значения переменной height.
Формат maze[y] означает, что мы обращаемся к элементу массива с индексом y.
Метод appendChild позволяет вставить в конец какого-либо другой элемент. Чаще всего используется после создания элемента с помощью createElement.
document.createElement(tag) - создаёт новый элемент с заданным тегом.
Свойство className отвечает за значение атрибута class элемента.
Функция amaze – генерирует пути по лабиринту
Свойство classList возвращает псевдомассив DOMTokenList, содержащий все классы элемента.
Метод Element.remove() удаляет элемент из DOM-дерева, в котором он находится.
Метод remove позволяет удалить элемент. Применяется к тому элементу, который нужно удалить. Используется в коде для того, чтобы удалять объекты wall.
Инструкция if выполняет инструкцию, если указанное условие выполняется (истинно). Если условие не выполняется (ложно), то может быть выполнена другая инструкция.
По данным условиям отбираются элементы формата [y, x].
&& - логическое И
Метод push() добавляет один или более элементов в конец массива и возвращает новую длину массива.
Функция проверяет, чтобы переданный значения не выходили за рамки ограничений.
Оператор return завершает выполнение текущей функции и возвращает её значение.
Вначале вызывается функция amaze, чтобы в дальнейшем запустился цикл.
Оператор while создаёт цикл, выполняющий заданную инструкцию, пока истинно проверяемое условие. Логическое значение условия вычисляется перед исполнением тела цикла.
Данный цикл работает до тех пор, пока длинна массива больше 0.
Свойство length объекта, который является экземпляром типа Array, устанавливает число элементов этого массива.
Объект Math является встроенным объектом, хранящим в своих свойствах и методах различные математические константы и функции.
Math.floor(x) - возвращает значение числа, округлённое к меньшему целому.
В данной программе создаёт случайную длину стенки.
Math.random() - возвращает псевдослучайное число в диапазоне от 0 до 1.
В переменную randomWall записываются координаты случайной стенки и координаты созданной, существующей стенки, а так же ее длина
В переменную host записываются актуальные координаты
В переменную opposite записываются новые возможные координаты.
Далее в условии проверяется актуальность этих значений.
Если же данные координаты уже встречались, то они удаляются из массива.
Метод splice() изменяет содержимое массива, удаляя существующие элементы и/или добавляя новые. В программе осуществляет добавление стенок в массив, если выполнены все условия
Метод indexOf() возвращает первый индекс, по которому данный элемент может быть найден в массиве или -1, если такого индекса нет.
Если данные координаты не встречались ранее, то обновляется значение по актуальным координатам и добавляются новые с обновлением значений.
Если же координаты не являются валидными, то также удаляются координаты.
Add - Этот метод объекта classList используется для добавления класса к элементу. В качестве аргументов нужно передавать строку с именем класса.
Функция parseInt() принимает строку в качестве аргумента и возвращает целое число в соответствии с указанным основанием системы счисления.
Событие onkeydown происходит, когда пользователь нажимает клавишу на клавиатуре.
Далее проверяется, что координаты не выходят за рамки лабиринта
Count > 0, иначе говоря, жизней больше 0, значит игра продолжается
В переменную x записывается значение нажатой кнопки и проверяется в следующем условии значение данной переменной.
Используется оператор сравнения “===” – строгое равенство (или "тройное равно" или "идентично"). Строгое равно проверяет на равенство две величины, при этом тип каждой из величин перед сравнением не изменяется (не приводится). Если значения имеют различающиеся типы, то они не могут быть равными.
В JavaScript есть также ещё один оператор сравнения “==” – равенство ("двойное равно"). Перед сравнением оператор равенства приводит обе величины к общему типу. После приведений (одного или обоих операндов), конечное сравнение выполняется также как и для ===. Операция сравнения симметрична: A == B возвращает то же значение, что и B == A для любых значений A и B.
Map – это коллекция ключ/значение, как и Object. Но основное отличие в том, что Map позволяет использовать ключи любого типа.
Методы и свойства:
Каждой клавише стрелка вверх, стрелка вниз, стрелка влево, стрелка вправо задаётся определённое числовое значение 2, 4, 1, 3 соответственно.
В переменную newPosition записываются координаты перемещения.
Программа высчитывает новое положение с помощью следующий формулы:
currentPosition[0] + ((mass.get(x) - 3) % 2), currentPosition[1] + ((mass.get(x) - 2) % 2)
map.get(key) – возвращает значение по ключу или undefined, если ключ key отсутствует.
currentPosition – текущая позиция игрока
Далее проверяется валидность новых значений, и что новые координаты не находятся в стене. Если это не так, то уменьшается счетчик count и уменьшается отображение жизней.
Далее удаляется класс фигурки на текущих координатах и создается в новых, таким образом происходит перемещение.
В переменную currentPosition записываются новая позиция игрока на карте (newPosition).
Проще говоря, в переменную currentPosition записывается значение старой позиции плюс значение новой позиции
Если фигурка дошла до финиша, то появляется соответствующее изображение.
Функция указанная ниже отображает количество жизней.
document.getElementById('test').innerHTML = 'Жизни:' + `♥ `.repeat(count);
Если count стал равен 0, то игра заканчивается и теперь игру можно только начать сначала по нажатию кнопки reset, f5 или же “f” на английской раскладке и “а” – на русской.
Метод Location.reload() перезагружает ресурс из текущего URL подобно кнопке обновления браузера. Данный метод срабатывает при нажатии клавиши f в случае победы и в случае поражения.
Функция GameRestart позволяет вывести надпись после победы или поражения с инструкцией для перезапуска игры и кликабельную надпись для перезапуска игры.
Заключение
Один из множества вариантов генерации лабиринта:
Цель работы достигнута, данная программа может быть использована в качестве развлечения на сайте, или в качестве самостоятельного продукта.
Во время написания программы можно научится использовать массивы, а также научится их редактировать и вносить в них изменения с помощью команд пользователя
Источники
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/const
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/var
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
https://doka.guide/js/element-classlist/
Элемент <input> с типом button отображаются как простые кнопки, которые можно запрограммировать для управления пользовательскими функциями в любом месте веб-страницы, например, назначить функцию обработки события. Хотя элементы с типом button по-прежнему являются абсолютно корректными в HTML, новый элемент теперь является предпочтительным способом создания кнопок. Учитывая, что текст элемента вставлен между открывающим и закрывающим тегами, вы можете включить в тег HTML, даже изображения.Атрибут значения элементов value содержит строку DOMString, которая используется в качестве метки кнопки. В данном случае это Reset, то есть перезапуск.
CSS файл
Код:
.cont{
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-items: center;
}
#test{
text-align: center;
width:420px;
font-size: 25px;
}
#maze {
border-style: solid;
}
.block {
float: left;
height: 20px;
width: 20px;
}
.wall {
background-color: black;
}
.me {
position: relative;
}
.me:after {
background-color: red;
border-radius: 100%;
content: '';
height: 20px;
position: absolute;
top: 0;
width: 20px;
}
.finish {
background-color: red;
}
body{
background: no-repeat center fixed;
background-size: cover;
}
::after создаёт псевдоэлемент, который является последним потомком выбранного элемента. Часто используется для добавления косметического содержимого в элемент с помощью свойства content. По умолчанию является инлайновым.
#name - базовый селектор, который выбирает элементы, основываясь на значении их id атрибута.
.name - базовый селектор, который выбирает элементы, основываясь на значении их атрибута class.
display: flex - многоцелевое свойство, которое определяет, как элемент должен быть показан в документе.
После установки данных значений, каждый дочерний элемент автоматически становится flex-элементом, выстраиваясь в один ряд (вдоль главной оси). При этом блочные и строчные дочерние элементы ведут себя одинаково, то есть ширина блоков равна ширине их содержимого с учетом внутренних полей и рамок элемента.
flex-direction: column
flex-direction - CSS свойство, указывающее на то, как flex-элементы располагаются во flex-контейнере по главной оси и направлению (нормальное или обратное).
column - Главная ось располагается вертикально и направлена сверху вниз. Точки main-start и main-end такие же, как точки before и after режима записи (writing-mode).
flex-wrap: wrap
Свойство CSS flex-wrap задаёт правила вывода flex-элементов — в одну строку или в несколько, с переносом блоков. Если перенос разрешён, то возможно задать направление, в котором выводятся блоки.
wrap - расположение в несколько линий. Свойство cross-start эквивалентно start или before в зависимости от значения flex-direction и свойство cross-end противоположно cross-start.
align-items: center - Центрирует элементы в поперечной оси.
Свойство align-items выравнивает флекс-элементы внутри контейнера в перпендикулярном направлении.
В программе же элементы центрируются по горизонтали.
text-align: center - выравнивание текста по центру. Текст помещается по центру горизонтали окна браузера или контейнера, где расположен текстовый блок.
text-align - определяет горизонтальное выравнивание текста в пределах элемента.
width - Устанавливает ширину блочных или заменяемых элементов
font-size определяет размер шрифта.
border-style: solid – отображает одну прямую сплошную линию.
Устанавливает стиль границы вокруг элемента.
float: left
Свойство float CSS указывает, что элемент должен быть взят из нормального потока и помещён вдоль левой или правой стороны его контейнера, где текст и встроенные элементы будут обтекать его.
left - ключевое слово, указывающее, что элемент должен находиться в левой части содержащего его блока.
height -устанавливает высоту элемента.
background-color - устанавливает цвет фона элемента.
position: relative
Свойство css position указывает, как элемент позиционируется в документе.
relative - элемент позиционируется в соответствии с нормальным потоком документа, а затем смещается относительно себя на основе значений top, right, bottom и left. Смещение не влияет на положение любых других элементов; таким образом, пространство, заданное для элемента в макете страницы, такое же, как если бы позиция была static.
border-radius - это CSS-свойство, позволяющее разработчикам определять, как скругляются границы блока. Закруглённость каждого угла определяется с помощью одного или двух радиусов, определяя его форму: круг или эллипс.
content - заменяет элемент сгенерированным значением. Применяется ко все элементам, древовидным псевдоэлементам и полям страницы.
top - для позиционированного элемента определяет расстояние от верхнего края родительского элемента до верхнего края дочернего элемента
Сокращённое CSS свойство background устанавливает сразу все свойства стиля фона, такие как цвет, изображение, источник и размер, или метод повтора.
Свойство background: no-repeat устанавливает, как фоновые изображения будет повторяться. Они могут повторяться по горизонтальной и вертикальной оси или не повторяться вовсе.
Свойство background: center размещает изображения по центру веб-страницы (тела сайта). Положение относительно уровня положения, установленного background-origin.
background: fixed - фон фиксируется относительно области просмотра. Даже если элемент имеет механизм прокрутки, фон не перемещается вместе с элементом.
Универсальное свойство background позволяет установить одновременно до пяти характеристик фона. Значения могут идти в любом порядке, браузер сам определит, какое из них соответствует нужному свойству. Для подробного ознакомления смотрите информацию о каждом свойстве отдельно. В CSS3 допустимо указывать параметры сразу нескольких фонов, перечисляя их через запятую.
background-size в CSS масштабирует фоновое изображение согласно заданным размерам. Изображение может быть оставлено в исходном размере, растянуто, или подогнано под размеры доступного пространства. Задает размер в любых доступных для CSS единицах — пикселы (px), сантиметры (cm), em и др.
cover - Ключевое слово, обратное contain. Масштабирует изображение как можно больше c сохранением пропорций изображения (изображение не становится сплющенным). Когда изображение и контейнер имеют разные размеры, изображение обрезается либо влево / вправо, либо сверху / снизу.
contain - масштабирует картинку так, чтобы она максимально накрыла собой весь блок. Картинка при этом не обрезается, а вписывается в блок с сохранением пропорций. Это свойство полезно на страницах, содержащих много независимых виджетов, так как его можно использовать для предотвращения побочных эффектов внутренних элементов каждого виджета за пределами ограничивающей рамки виджета.
JavaScript файл
Код:
document.addEventListener("DOMContentLoaded",gen)
function gen(){
main(20, 20, [], [], [0, 0]);
document.querySelector('.reset').addEventListener('click', function(){location.reload()});
}
function main(height, width, maze, walls, currentPosition) {
count = 3;
height = height % 2 === 0 ? height + 1 : height; //Условный оператор
width = width % 2 === 0 ? width + 1 : width;
document.getElementById('test').innerHTML = 'Жизни:'+ `♥ `.repeat(count); //Отображение счета
document.getElementById('maze').setAttribute('style', 'height:' + height * 20
+ 'px; width:' + width * 20 + 'px');
//Устанавливает атрибуты
for (let y = 0; y < height; y++) {
maze[y] = [];
for (let x = 0; x < width; maze[y][x++] = 'wall') { //заполнение массива значением 'wall'
let el = document.getElementById('maze').appendChild(document.createElement("div"));
el.className = 'block wall';
el.setAttribute('id', y + '-' + x);
}
} //Генерация div'ов вначале по высоте, потом по ширине и заполнение лабиринта стенами
function amaze(y, x, addBlockWalls) {
maze[y][x] = 'maze';
document.getElementById(y + '-' + x).classList.remove('wall'); //присвоение класса
if (addBlockWalls && valid(y + 1, x) && (maze[y + 1][x] === 'wall')) walls.push([y + 1, x, [y, x]]);
if (addBlockWalls && valid(y - 1, x) && (maze[y - 1][x] === 'wall')) walls.push([y - 1, x, [y, x]]);
if (addBlockWalls && valid(y, x + 1) && (maze[y][x + 1] === 'wall')) walls.push([y, x + 1, [y, x]]);
if (addBlockWalls && valid(y, x - 1) && (maze[y][x - 1] === 'wall')) walls.push([y, x - 1, [y, x]]);
//заполнение новыми значениями и актуальными
}
function valid(a, b) {
return (a < height && a >= 0 && b < width && b >= 0);
}
amaze(currentPosition[0], currentPosition[1], true);
while (walls.length !== 0) {
let randomWall = walls[Math.floor(Math.random() * walls.length)], //получение случайной стенки
host = randomWall[2],//смотрит на актуальные координаты
opposite = [(host[0] + (randomWall[0] - host[0]) * 2), (host[1] + (randomWall[1] - host[1]) * 2)];
if (valid(opposite[0], opposite[1])) {
if (maze[opposite[0]][opposite[1]] === 'maze') walls.splice(walls.indexOf(randomWall), 1);
else amaze(randomWall[0], randomWall[1], false), amaze(opposite[0], opposite[1], true);
} else walls.splice(walls.indexOf(randomWall), 1);
}
document.getElementById('0-0').classList.add('me');
//Реализация точки старта
document.getElementById((parseInt(height) - 1) + '-' + (parseInt(width) - 1)).classList.add('finish');
//Реализация точки финиша
onkeydown = function(e) {
let x = e.key
if ((currentPosition[0] !== height - 1) || (currentPosition[1] !== width - 1)) {
if (count > 0) {
if (x === 'ArrowLeft' || x === 'ArrowRight' || x === 'ArrowUp' || x === 'ArrowDown') {
const mass = new Map([
['ArrowLeft', 1],
['ArrowRight', 3],
['ArrowUp', 2],
['ArrowDown',4]
])
let newPosition = [currentPosition[0] + ((mass.get(x) - 3) % 2), currentPosition[1] + ((mass.get(x) - 2) % 2)];
if (valid(newPosition[0], newPosition[1]) && maze[newPosition[0]][newPosition[1]] !== 'wall') {
document.getElementById(currentPosition[0] + '-' + currentPosition[1]).classList.remove('me');
currentPosition = newPosition;
document.getElementById(currentPosition[0] + '-' + currentPosition[1]).classList.add('me');
if (currentPosition[0] === height - 1 && currentPosition[1] === width - 1) {
document.body.innerHTML = "";
document.body.style.backgroundImage = 'url(win.jpg)';
}
} else {
if(x!=='f' && x!=='а') {
count -= 1
document.getElementById('test').innerHTML = 'Жизни:' + `♥ `.repeat(count);
}
if (count === 0) {
document.body.innerHTML = "";
document.body.style.backgroundImage = 'url(lose.jpg)';
}
}
}
}
}
if ((currentPosition[0] === height - 1) || (currentPosition[1] === width - 1)) {
if (x==='f' || x==='а') document.location.reload()
}
if (count===0 && (x==='f' || x==='а')) document.location.reload()
}
}
Const
Значение констант не может быть изменено новым присваиванием, а также не может быть переопределено. Константы (const) подчиняются области видимости уровня блока так же, как переменные, объявленные с использованием ключевого слова let.
nameN
Имя константы. Подчиняется тем же правилам, что и идентификаторы обычных переменных.
valueN
Значение константы. Может быть любым из тех типов, которые могут быть для переменных, включая функцию.
Интерфейс EventTarget реализуется объектами, которые могут принимать и обрабатывать события, например, такими как Element, Document, Window и XMLHttpRequest.
JavaScript метод addEventListener() объекта EventTarget позволяет зарегистрировать обработчик событий определенного типа для конкретной цели.
В качестве цели могут выступать как такие объекты как Element, Document, Window, или любые другие объекты, которые поддерживают события, например, такой объект как XMLHttpRequest, который широко используется в асинхронных запросах AJAX (от англ. Asynchronous Javascript and XML — "асинхронный JavaScript и XML"), что позволяет конкретной странице обновлять только её часть, не нарушая при этом работу пользователя.
Обратим внимание на то, что можно использовать метод removeEventListener() для удаления обработчика событий, присоединенного с помощью метода addEventListener().
Некоторые варианты событий:
События загрузки документа. Пример: событие load происходит, когда ресурс и его зависимые ресурсы закончили загружаться.
События мыши. Пример: click - высокоуровневое событие, возбуждаемое, когда пользователь нажимает и отпускает кнопку мыши или иным образом активирует элемент.
События ввода текста. Пример: Событие input срабатывает тут же при изменении значения текстового элемента и поддерживается всеми браузерами, кроме IE8.
События клавиатуры. Пример: события keydown и keyup возбуждаются, когда пользователь нажимает или отпускает клавишу на клавиатуре.
Событие DOMContentLoaded происходит, когда весь HTML был полностью загружен и пройден парсером, не дожидаясь окончания загрузки таблиц стилей, изображений и фреймов. Разница между DOMContentLoaded и load заключается в том, что событие load происходит, когда браузер загрузил HTML и внешние ресурсы (картинки, стили и т.д.)
В данном случае вызывается функция gen.
Функция в JavaScript - это специальный тип объектов, позволяющий формализовать средствами языка определённую логику поведения и обработки данных. Это фрагмент программного кода (подпрограмма), в большинстве случаев связанный с идентификатором, к которому можно обратиться из другого места программы. После выполнения функции управление возвращается обратно в точку программы, где данная функция была вызвана.
Функции позволяют не повторять один и тот же код во многих местах программы и являются основными «строительными блоками» программ.
Функция gen, которая вызывает функцию main с передачей указанных параметров, тут же и создаются массивы maze, walls и currentPosition.
Document метод querySelector() возвращает первый элемент документа, который соответствует указанному селектору или группе селекторов. Если совпадений не найдено, возвращает значение null.
Метод location.reload() перезагружает ресурс из текущего URL подобно кнопке обновления браузера.
Содержимое функции main:
Директива let объявляет переменную с блочной областью видимости с возможностью инициализировать её значением.
Оператор var объявляет переменную, инициализируя её, при необходимости.
Объявление переменной всегда обрабатывается до выполнения кода, где бы она ни находилась. Область видимости переменной, объявленной через var, это её текущий контекст выполнения. Который может ограничиваться функцией или быть глобальным, для переменных, объявленных за пределами функции.
Присвоение значения необъявленной переменной подразумевает, что она будет создана как глобальная переменная (переменная становится свойством глобального объекта) после выполнения присваивания значения. Различия между объявленной и необъявленной переменными следующие:
Директива let позволяет объявить локальную переменную с областью видимости, ограниченной текущим блоком кода. В отличие от ключевого слова var, которое объявляет переменную глобально или локально во всей функции, независимо от области блока.
Если объявлять переменную, не используя "var", то она всегда будет глобальной.
Переменная count отвечает за количество жизней.
В переменные height и width всегда записывается нечетное значение.
Проверка значений происходит с помощью условного оператора. Условный (тернарный) оператор - единственный оператор в JavaScript, принимающий три операнда: условие, за которым следует знак вопроса (?), затем выражение, которое выполняется, если условие истинно, сопровождается двоеточием (:), и, наконец, выражение, которое выполняется, если условие ложно. Он часто используется в качестве укороченного варианта условного оператора if.
document.getElementById() - возвращает ссылку на элемент по его идентификатору (id). Идентификатор является строкой, которая может быть использована для идентификации элемента; она может быть определена при помощи атрибута id в HTML или из скрипта.
Element.innerHTML - свойство интерфейса, которое устанавливает или получает HTML или XML разметку дочерних элементов.
Метод repeat() конструирует и возвращает новую строку, содержащую указанное количество соединённых вместе копий строки, на которой он был вызван.
Element.setAttribute() - добавляет новый атрибут или изменяет значение существующего атрибута у выбранного элемента.
В данном случае атрибуту style задаем параметры высоты и ширины элементов.
Выражение for создаёт цикл, состоящий из 3 необязательных выражений в круглых скобках, разделённых точками с запятой.
Синтаксис: for ([инициализация]; [условие]; [финальное выражение]) выражение.
В данном случае цикл работает, пока значение y меньше значения переменной height.
Формат maze[y] означает, что мы обращаемся к элементу массива с индексом y.
Метод appendChild позволяет вставить в конец какого-либо другой элемент. Чаще всего используется после создания элемента с помощью createElement.
document.createElement(tag) - создаёт новый элемент с заданным тегом.
Свойство className отвечает за значение атрибута class элемента.
Функция amaze – генерирует пути по лабиринту
Свойство classList возвращает псевдомассив DOMTokenList, содержащий все классы элемента.
Метод Element.remove() удаляет элемент из DOM-дерева, в котором он находится.
Метод remove позволяет удалить элемент. Применяется к тому элементу, который нужно удалить. Используется в коде для того, чтобы удалять объекты wall.
Инструкция if выполняет инструкцию, если указанное условие выполняется (истинно). Если условие не выполняется (ложно), то может быть выполнена другая инструкция.
По данным условиям отбираются элементы формата [y, x].
&& - логическое И
Метод push() добавляет один или более элементов в конец массива и возвращает новую длину массива.
Функция проверяет, чтобы переданный значения не выходили за рамки ограничений.
Оператор return завершает выполнение текущей функции и возвращает её значение.
Вначале вызывается функция amaze, чтобы в дальнейшем запустился цикл.
Оператор while создаёт цикл, выполняющий заданную инструкцию, пока истинно проверяемое условие. Логическое значение условия вычисляется перед исполнением тела цикла.
Данный цикл работает до тех пор, пока длинна массива больше 0.
Свойство length объекта, который является экземпляром типа Array, устанавливает число элементов этого массива.
Объект Math является встроенным объектом, хранящим в своих свойствах и методах различные математические константы и функции.
Math.floor(x) - возвращает значение числа, округлённое к меньшему целому.
В данной программе создаёт случайную длину стенки.
Math.random() - возвращает псевдослучайное число в диапазоне от 0 до 1.
В переменную randomWall записываются координаты случайной стенки и координаты созданной, существующей стенки, а так же ее длина
В переменную host записываются актуальные координаты
В переменную opposite записываются новые возможные координаты.
Далее в условии проверяется актуальность этих значений.
Если же данные координаты уже встречались, то они удаляются из массива.
Метод splice() изменяет содержимое массива, удаляя существующие элементы и/или добавляя новые. В программе осуществляет добавление стенок в массив, если выполнены все условия
Метод indexOf() возвращает первый индекс, по которому данный элемент может быть найден в массиве или -1, если такого индекса нет.
Если данные координаты не встречались ранее, то обновляется значение по актуальным координатам и добавляются новые с обновлением значений.
Если же координаты не являются валидными, то также удаляются координаты.
Add - Этот метод объекта classList используется для добавления класса к элементу. В качестве аргументов нужно передавать строку с именем класса.
Функция parseInt() принимает строку в качестве аргумента и возвращает целое число в соответствии с указанным основанием системы счисления.
Событие onkeydown происходит, когда пользователь нажимает клавишу на клавиатуре.
Далее проверяется, что координаты не выходят за рамки лабиринта
Count > 0, иначе говоря, жизней больше 0, значит игра продолжается
В переменную x записывается значение нажатой кнопки и проверяется в следующем условии значение данной переменной.
Используется оператор сравнения “===” – строгое равенство (или "тройное равно" или "идентично"). Строгое равно проверяет на равенство две величины, при этом тип каждой из величин перед сравнением не изменяется (не приводится). Если значения имеют различающиеся типы, то они не могут быть равными.
В JavaScript есть также ещё один оператор сравнения “==” – равенство ("двойное равно"). Перед сравнением оператор равенства приводит обе величины к общему типу. После приведений (одного или обоих операндов), конечное сравнение выполняется также как и для ===. Операция сравнения симметрична: A == B возвращает то же значение, что и B == A для любых значений A и B.
Map – это коллекция ключ/значение, как и Object. Но основное отличие в том, что Map позволяет использовать ключи любого типа.
Методы и свойства:
-
new Map() – создаёт коллекцию. -
map.set(key, value) – записывает по ключу key значение value. -
map.get(key) – возвращает значение по ключу или undefined, если ключ key отсутствует. -
map.has(key) – возвращает true, если ключ key присутствует в коллекции, иначе false. -
map.delete(key) – удаляет элемент по ключу key. -
map.clear() – очищает коллекцию от всех элементов. -
map.size – возвращает текущее количество элементов.
Каждой клавише стрелка вверх, стрелка вниз, стрелка влево, стрелка вправо задаётся определённое числовое значение 2, 4, 1, 3 соответственно.
В переменную newPosition записываются координаты перемещения.
Программа высчитывает новое положение с помощью следующий формулы:
currentPosition[0] + ((mass.get(x) - 3) % 2), currentPosition[1] + ((mass.get(x) - 2) % 2)
map.get(key) – возвращает значение по ключу или undefined, если ключ key отсутствует.
currentPosition – текущая позиция игрока
Далее проверяется валидность новых значений, и что новые координаты не находятся в стене. Если это не так, то уменьшается счетчик count и уменьшается отображение жизней.
Далее удаляется класс фигурки на текущих координатах и создается в новых, таким образом происходит перемещение.
В переменную currentPosition записываются новая позиция игрока на карте (newPosition).
Проще говоря, в переменную currentPosition записывается значение старой позиции плюс значение новой позиции
Если фигурка дошла до финиша, то появляется соответствующее изображение.
Функция указанная ниже отображает количество жизней.
document.getElementById('test').innerHTML = 'Жизни:' + `♥ `.repeat(count);
Если count стал равен 0, то игра заканчивается и теперь игру можно только начать сначала по нажатию кнопки reset, f5 или же “f” на английской раскладке и “а” – на русской.
Метод Location.reload() перезагружает ресурс из текущего URL подобно кнопке обновления браузера. Данный метод срабатывает при нажатии клавиши f в случае победы и в случае поражения.
Функция GameRestart позволяет вывести надпись после победы или поражения с инструкцией для перезапуска игры и кликабельную надпись для перезапуска игры.
Заключение
Один из множества вариантов генерации лабиринта:
Цель работы достигнута, данная программа может быть использована в качестве развлечения на сайте, или в качестве самостоятельного продукта.
Во время написания программы можно научится использовать массивы, а также научится их редактировать и вносить в них изменения с помощью команд пользователя
Источники
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/const
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/let
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Statements/var
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
https://doka.guide/js/element-classlist/