Великий Путь Вебмастера от идеи до интернет бизнеса
Блог Романа Чуешова
Начни зарабатывать в интернете на создании сайтов и блогов

Создаем игру — змейка на языке javascript и наслаждаемся игрой в браузере

Приветствую всех, кто читает данную статью и загорелся желанием написать свою собственную игру. Сегодня я расскажу вам, как создается игра змейка на JavaScript. Я приведу код для html-разметки, после мы проработаем с вами стили оформления элементов и в конце пропишем логику работы приложения при помощи JavaScript. Давайте приступим!

Создаем свою игру «Змейка»

Займемся разметкой игрового поля

Для начала необходимо прописать разметку игры. В первую очередь на странице выделим отдельное пространство под рабочую область:

<div class="border"></div>

Я хочу, чтобы в моем приложении было несколько уровней сложности: легкий, средний и сложный. Также я хочу обеспечить пользователя возможностью сбросить игру и выбранный уровень сложности для того, чтобы он смог начать игру заново. Поэтому я создаю четыре кнопки, которые помещаю в отдельный блок buttons.

1
2
3
4
5
6
<div class="buttons">
    <button id="easy" onclick="EasyStart()">Простой</button>
    <button id="medium" onclick="MediumStart()">Средний</button>
    <button id="hard" onclick="HardStart()">Сложный</button>
    <button onclick="reload()">Сбросить</button>
</div>

Как вы уже заметили, на каждую кнопку я навешиваю событие. Поэтому при нажатии на какую-либо из них будет запускаться определенная функция обработки.

Ну и в конце я хочу, чтобы у меня выводился счет.

<div class = «score»>Ваш счет: 0</div>

Зададим правильное отображение элементов

Пока что ничего симпатичного в редакторах кода не отображается. Для этого стоит задать стилевые правила. Если вы пишете программу полотном, то внутри тега <head> пропишите парный элемент <style> </style> и далее в него вносите css.

Или же создайте файл style.css и без указания style вставляйте описание стилей.

Итак, для начала сбросим стандартные параметры браузера, т.е. обнулим внутренние и внешние отступы:

body{

margin: 0;

padding: 0;

border: 0;

}

Теперь создадим подложку под игровое поле:

1
2
3
4
5
6
7
8
9
10
        .border{
            z-index: -15;
            position: absolute;
            top: 9px;
            background-color: #556B2F;
            left: 39px;
            width: 510px;
            height: 559px;
            border: 2px solid #001100;
        }

Перейдем к кнопкам. Я хочу сделать их объемными и разместить сверху по центру поля. Поэтому для соответствующего класса я описываю внешние отступы. А после для самого элемента <button> определяю стилевые характеристики.

1
2
3
4
5
6
7
8
9
        button {
            border-radius: 10px;
            padding: 7px;
            background: linear-gradient(to top, #FFFAFA, #8B8682);
            font-weight: 600;
        }
        .buttons{
            margin: 20px 10px 20px 140px;
        }

Что-то уже прорисовывается, но описание счета «убежало» непонятно куда. Поэтому переместим его в нужную нам позицию и облагородим.

1
2
3
4
5
6
.score{
            margin-left: 72px;
            font-size: 31px;
            color: #FF0000;
            text-shadow: 0 0 6px #010;
        }

Вот мы и описали классы и теги, которые были перечислены в гипертекстовой разметке. Однако у вас наверняка возникли вопросы: «А где же само игровое поле? Где змея и что она должна собирать?»

Остальная разметка будет добавляться в скрипте. А пока подготовим для этого стили.

Само игровое поле мы опишем при помощи класса .field, а внешний вид клеток – с помощью класса .cell.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        .field{
            z-index: 30;            
            height: 23px;
            margin-left: 53px;
        }
        .cell{
            margin: 0;
            display: inline-block;
            background-color: #7FFFD4;
            width: 22px;
            height: 22px;
            border: 1px solid #010;
            border-radius: 4px;
            z-index: 30;
            transition: background-color 0.3s;
        }

Далее нам нужна змея. Поэтому задаем ее классом .snake и указываем:

1
2
3
4
5
6
        .snake{
            box-shadow: 0 0 10px #000000 inset;
            background: linear-gradient(to right, #00FF00, #556B2F);
            z-index: 30;
            transition: background 0.2s;
        }

Ну и наконец змея должна что-то собирать. Поэтому описываем еду. В моей программе это будет квадрат красного цвета.

1
2
3
4
5
6
        .food{
            background-color:#FF0000;
            z-index: 30;
            box-shadow: 0 0 10px #000000 inset;
            transition: background-color 2s;
        }

Дизайн игры готов. Теперь переходим к самому главному!

Заставим игру работать!

Вот теперь пришло время прописать логику работы «Змейки». Для этого после разметки html вставьте ниже прикрепленный код. Внимательно просмотрите его, если хотите разобраться во всех деталях реализации игры. По мере прочтения коды вы будете находить мои комментарии.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<script type="text/javascript">
var timer;
    var directx = direct = 0;
//Указываю количество клеток по вертикали и после по горизонтали 
    var fieldSizeX = 20;
    var fieldSizeY = 20;
    var KEY = {
        'left' : 37,
        'up' : 38,
        'right' : 39,
        'down' : 40
    };
//Массив направлений
    var direction = [
        [0,1], //вправо
        [1,0], //вниз
        [0,-1], //влево
        [-1,0]]; //вверх
//Задаю начальные параметры змеи
    var snake = {
        length : 3,
        body : [[1,1],[1,2],[1,3]], //координаты расположения змеи
/* В этой функции рисую змею на экране*/
        initialisationSnake : function (){
//Цикл проходит по всем составным частям змеи
            for ( var i = 0; i < this.length; i++){
                var currentBodyPart = this.body[i];
/*Отрисовка происходит при помощи присвоения определенных стилевых правил cell и snake */
                document.getElementById(currentBodyPart.join()).className = 'cell snake';
            }
        },
        move : function (){
            direct = directx;
            var body = this.body //определяем тело ползучего животного
//Определяем его голову. В данном случае это последняя клетка
            var head = this.body[this.length-1];
            var headCell = head.map(function(value, index){ return value + direction[direct][index] });
            compareEatOrGameOver(headCell, body);
            return headCell;
        }
    };
//функция addEventListener регистрирует определенный обработчик событий
//и keyHandler сообщает какая кнопка была нажата
    window.addEventListener('keydown', keyHandler, false);
    prepareGamePane(fieldSizeX, fieldSizeY);
 
/*Подготавливаю игровое поле. Именно здесь прорисовываются клетки поля и расположение последнего */
    function prepareGamePane (fieldSizeX, fieldSizeY){
        for ( var x = 0; x < fieldSizeX; x++){
            var coordinateX = document.createElement('div');
            document.body.appendChild(coordinateX);
            coordinateX.className = 'field';
            for (var y = 0; y < fieldSizeY; y++){
                var coordinateY = document.createElement('div');
                coordinateX.appendChild(coordinateY);
                coordinateY.className = 'cell';
                coordinateY.id = x+','+y;
            }
        }
        snake.initialisationSnake();
        makeFood(fieldSizeX, fieldSizeY);
    }
 
//Генерирую случайную точку на поле, в которую и внесу еду
    function makeFood (fieldSizeX, fieldSizeY){
//Случайным образом получаю первую часть координаты по x
        var x = Math.round(Math.random() * (fieldSizeX-1));
//Случайным образом получаю первую часть координаты по y
        var y = Math.round(Math.random() * (fieldSizeY-1));
        var food = document.getElementById(x+','+y);
/*Осуществляю проверку. Если полученная координата не занята змеей, то рисую еду – красный квадрат*/
        if (food.className == 'cell'){
            food.className = "cell food";
        } else { //иначе запускаю функцию по новой
            makeFood(fieldSizeX, fieldSizeY);
        }
        return food;
    }
 
//Обработчик нажатой кнопки
    function keyHandler (event){
        switch (event.keyCode) {
            case KEY.left: //стрелка влево
                if (direct != 0){
                    directx = 2;
                }
                break;
            case KEY.right: //стрелка вправо
                if (direct != 2){
                    directx = 0;
                }
                break;
            case KEY.up: //стрелка вверх
                if (direct != 1){
                    directx = 3;
                }
                break;
            case KEY.down: //стрелка вниз
                if (direct != 3){
                    directx = 1;
                }
                break;
            default :
                return;
        }
    }
 
 
    function compareEatOrGameOver (headCell, body) {
        var tmp = document.getElementById(headCell.join());
/*Данная проверка позволяет не останавливаться ползучему существу, если оно доходит до края игрового поля*/
        if (tmp == null ) {
          if (headCell[0] == -1)
            headCell[0] = fieldSizeX - 1;
          if (headCell[0] == fieldSizeX)
            headCell[0] = 0;
          if (headCell[1] == -1)
            headCell[1] = fieldSizeY - 1;
          if (headCell[1] == fieldSizeY)
            headCell[1] = 0;
          tmp = document.getElementById(headCell.join());
        }
         //Если занята ячейка – это пустая клетка, то рисую там змею 
        if ( tmp != null && tmp.className == 'cell' ){
            var removeTail = body.shift();
            body.push(headCell);
            document.getElementById(removeTail.join()).className = 'cell';
            document.getElementById(headCell.join()).className = 'cell snake';
        } else { //если текущая клетка с едой
            if ( tmp != null && tmp.className == 'cell food'){
//увеличиваю длину змеи на 1 квадрат
                snake.length++;
                body.push(headCell);
                document.getElementById(headCell.join()).className = 'cell snake';
//генерирую еду в другой ячейке
                makeFood(fieldSizeX, fieldSizeY);
//Меняю количество очков
                var score = snake.length-3;
                document.getElementById('score').innerHTML = 'Ваш счет: '+score;
            } else { //если текущая ячейка оказалась самой змеей
                if (tmp.className == 'cell snake'){
                    clearInterval(timer);
//вывод сообщения об окончании игры
                    alert('Вы проиграли! Ваш счет: ' + (snake.length-3) + '. Нажмите кнопку «Сбросить» для начала новой игры!');
                }
            }
        }
    }
 //Функции описания режима движения змейки
    function EasyStart () { //Простой
        timer = setInterval(function(){
            snake.move();
        },400);
    }
    function MediumStart () {//средний
        timer = setInterval(function(){
            snake.move();
        },200);
    }
    function HardStart () {//сложный
        timer = setInterval(function(){
            snake.move();
        },100);
    }
    function reload () {//перегрузка параметров (кнопка «Сбросить»)
        window.location.reload();
    }
</script>

Ну вот игра готова!

Вступайте в ряды моих верных подписчиков и делитесь интересными статьями с друзьями. Приятной игры! Пока-пока!

С уважением, Роман Чуешов

Прочитано: 2647 раз
Этот блог уже читают
читай и ты!
Оставить коментарий
:p :-p 8) 8-) :lol: =( :( :-( :8 ;) ;-) :(( :o:
  • Денис

    Руслан, как и чем код компилировать? Где-то статья есть об этом? У меня не получается.

    03.01.2017 в 04:23
    • Павел

      Открой html-файл через браузер.

      14.06.2017 в 13:47
    • Денис

      Спасибо! Моя ошибка была в создании файла с расширением js, а надо было html. Невнимательно прочитал в статье, что код вставляется после разметки html. Мой косяк.

      27.06.2017 в 23:50
  • Денис

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

    03.01.2017 в 04:33
  • Цифровой

    Ну вы бы хотя бы ссылку на фиддл оставили, чтобы поиграть )

    15.06.2018 в 12:35
  • Игорь

    Не могу разобраться в этой части кодаё//Определяем его голову. В данном случае это последняя клетка

    var head = this.body[this.length-1];

    var headCell = head.map (function (value, index){ return value + direction[direct][index] });

    compareEatOrGameOver (headCell, body);

    return headCell; }

    Value и index изначально не заданы, потом принимают значения 1 и 0, далее в этой строке принимают значение 4 и 1 и в новом цикле 1 и 0 потом 5 и 1 (если мы не нажимаем стрелки) и т.д. как значения изменяются что-то не пойму. Похоже на рекурсию.

    10.11.2018 в 20:47
  • Александр

    Может кто нибудь объяснить 29-ую строчку в js.

    document.getElementById (currentBodyPart.join ())............

    Метод getElementById позволяет получить элемент (тег) страницы по его атрибуту id. Какое в данном случае id и какого элемента в HTML файле? Я так понимаю currentBodyPart.join () это просто строка из элемента массива в 22-ой строке. В первой итерации цикла она будет ровна «1,1». Но это же точно никакое не id

    23.11.2018 в 16:24
  • РКН

    Спасибо

    23.05.2019 в 11:35
    • Роман

      Пожалуйста!

      25.05.2019 в 14:21
      • Анна

        Подскажите, а как сделать, чтобы работал счет?

        05.09.2020 в 19:50
  • Maks

    у вас тут ошибка вместо

    Ваш счет: 0

    надо

    Ваш счет: 0

    10.05.2020 в 15:26
    • Maks

      там где кусок кода с выводом счета в html

      надо

      class = 'score'

      а не

      class = «score»

      10.05.2020 в 15:28