Предыдущие части: Чёрный квадрат, Графический контекст, Расстановка объектов, Инициализация, Функции и библиотеки, Проектирование
В предыдущих частях я разобрался с нюансами графики, написал функцию для рисования квадрата, чтобы пользоваться ею одинаково в обоих языках, и теперь подхожу к своей главной цели: нарисовать наконец-таки это несчастное поле 22*22 с объектами в нём.
Метод рисования будет простой: раз у меня есть массив 22*22 клетки, то я и буду рисовать на экране каждую клетку в соответствующем порядке.
Например, первая клетка в массиве имеет координаты 0,0. Значит, на экране надо нарисовать квадрат с координатами 0,0. Вторая клетка имеет координаты 1,0. Значит, на экране надо нарисовать квадрат с координатами 1,0.
Но есть небольшой нюанс: клетка в памяти компьютера не имеет физических размеров, это лишь мысленное понятие. А квадрат на экране должен иметь размер, причем такой, чтобы на него было комфортно смотреть. Я путем небольших экспериментов выбрал размер квадрата 16*16.
Поэтому, если я нарисую второй квадрат на расстоянии 1 пиксел от первого, то просто перекрою один квадрат другим. Чтобы они не перекрывались, а стояли рядом, надо второй квадрат отодвинуть на ширину квадрата, то есть на 16 пикселов.
Значит, координаты клеток x, y транслируются в координаты квадратов так: x*16, y*16.
Кроме того, я не хочу, чтобы моё игровое поле рисовалось начиная прямо с левого верхнего угла окна. Я хочу сделать вокруг него отступы. Так как ширина поля получится 22*16=352 пиксела, а ширина моего холста 400 пикселов, то я сделаю отступ в 24 пиксела. Этот отступ надо будет прибавить к каждой координате моих квадратов:
24 + x * 16
24 + y * 16
Теперь меня всё устраивает. Я начну перебирать все клетки массива, и если клетка не пустая, то я буду рисовать квадрат. Если же клетка пустая, я не буду делать ничего. Я сразу напишу отдельную функцию для рисования поля, которую назову draw_field.
Код на JavaScript:
Функция принимает от меня параметр ctx, чтобы в свою очередь передать его в draw_rect().
Первым делом я рисую большой белый квадрат, который стирает всё, что до этого было на холсте.
Затем я делаю цикл for, который прогоняет переменную addr от значения 0 до значения field.length. Это длина моего массива. Хотя я знаю её и мог бы написать просто 484, но в будущем длина может измениться, или я использую тот же самый код с другим массивом. Короче, чтобы каждый раз не исправлять длину, я использовал атрибут length массива field. Такой атрибут есть у каждого массива в JavaScript и равен он, конечно же, длине массива.
Внутри цикла я проверяю, что находится в массиве field по текущему адресу addr, с помощью блока if. Условие, которое записано в скобках, обозначает: "если содержимое field[addr] не равно нулю". Если вам интересно, почему там написано "!=", посмотрите на такой знак: ≠. Это его имитация доступными средствами. Так вот, если содержимое не равно нулю, это значит, что по данному адресу в массиве находится непустая клетка, и следовательно надо выполнить блок if {}.
А в этом блоке я как раз и буду рисовать. Cначала я получу координаты клетки x, y из её адреса. Как? Если адрес получался так: y * 22 + x, то координаты из адреса получаются обратным преобразованием. Если каждое полное число 22 в адресе это 1 шаг по координате y, то y = Math.floor(addr / 22). С помощью Math.floor() я получил целое количество после деления. А любой остаток от деления – это координата x. Он получается через операцию взятия остатка от деления на 22: addr % 22. Тут не про проценты, тут "%" означает именно взятие остатка.
Добыв из адреса координаты x и y, я теперь могу нарисовать квадрат по нужным координатам, учитывая те преобразования, которые я делал до этого (размеры и отступы). Я рисую квадраты шириной и высотой не 16, а 15, чтобы между ними оставалась тонкая линия – так их легче различать.
Код рисования на Python. Я не буду его комментировать, потому что он состоит из тех же самых шагов, и просто по его внешнему виду должно быть уже всё понятно.
Вот что получилось в результате:
Зашибись! Но я нарисовал все квадраты черным цветом. Мне нужно нарисовать их разными цветами.
Ну, пусть стенки остаются черными. Роботы будут "стального" цвета (100,118,135), опасные трансформаторы – оранжевого (250,104,0), а игрок – телесного (255,180,88), так как он кожаный мешок. Теперь надо доработать функцию: перед рисованием квадрата поставить ещё одно условие: что именно находится в клетке? И выбрать соответствующий цвет.
Напишу это пока отдельно, чтобы было нагляднее:
До сих пор такая запись не встречалась, поэтому поясню. Чтобы узнать, равно ли одно значение другому, мы должны написать не "=", а "==". Это потому что если мы напишем "=", то получится не сравнение, а присваивание.
- field[addr] = PLAYER – записать константу PLAYER в массив field по адресу addr
- field[addr] == PLAYER – проверить содержимое массива field по адресу addr на равенство с константой PLAYER
Путать нельзя!
Соответственно, если field[addr] == PLAYER, то выполнится блок if {}, где мы присвоим переменной color значение цвета, выбранного для игрока.
А вот если не выполнится... Раньше в аналогичных случаях ничего не происходило. Но у блока if теперь есть продолжение – else, то есть "иначе", и оно должно сработать, если не сработало условие if. Получается так: "если выполнилось это условие, выполни этот блок, а иначе..." а иначе мы можем написать ещё одно условие, а потом иначе ещё одно и так далее. В конце концов, когда мы перебрали все условия и все они не сработали, у нас остался финальный вариант else, в котором мы просто уже без проверок присвоим черный цвет. Потому что это стенка, иначе быть уже не может.
Теперь на Питоне:
Фактически то же самое, только в Питоне для else if придумали мерзейший вариант elif. Зачем – не знаю. Хотели сэкономить пару букв?
Осталось добавить этот код в функцию рисования, и вот что получилось:
Теперь игрок видит cитуацию и готов на неё реагировать. Значит, в следующей части надо будет заняться обработкой ввода от игрока.
А пока, полный текущий код на Питоне
И живая версия Javascript, которую можно смотреть и менять.
Читайте дальше: Обработка действий игрока