Найти тему
ZDG

Пишу игру Robots на JavaScript и Python. Часть 4: Расстановка объектов

Предыдущие части: Инициализация, Функции и библиотеки, Проектирование

В предыдущей части я подготовил пустое поле 22*22 со стенками по краям. Теперь я должен расставить в нём роботов, препятствия и игрока.

Сколько их должно быть? Ну пусть пока роботов будет 10, а препятствий 5. Игрок, конечно, один.

Чтобы создать хотя бы одного робота, для начала мне нужно получить случайные координаты X и Y. Роботы не должны попасть на стенки, поэтому диапазон координат будет не 0-21, а 1-20.

На Python:

x = randint(1, 20)
y = randint(1, 20)

На JavaScript:

var x = Math.floor(1 + Math.random() * 19);
var y = Math.floor(1 + Math.random() * 19);

Я сразу встречаю некоторое неудобство: получение случайного числа на JavaScript выглядит слишком громоздко. Это всё потому, что в JavaScript нет функции получения целого случайного числа, как в Питоне. Но... я могу её написать!

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

Что произошло: я создал функцию с именем randint. В круглых скобках в функцию передаются два числа: минимальное и максимальное (min, max). Замечу, это не сами числа, а как бы коробочки с названиями min и maх, куда будут положены реальные числа при вызове функции. Тело функции находится между фигурными скобками "{" и "}". В этом теле вычисляется случайное число на основе min и max и возвращается мне с помощью инструкции return. Теперь я могу вызывать эту функцию когда захочу:

var x = randint(1, 20);

И теперь всё выглядит и работает точно так же, как в Питоне. Что делает транслятор языка:

"Переменной x присваивается значение randint(1, 20). Это выглядит как функция. В языке нет такой функции, но я вижу, что программист сам написал её. Я также вижу, что туда надо передать два числа, которые называются min и max. Программист написал 1, 20, значит я передам 1 как min и 20 как max."

Что делает функция:

"Мне должны передать min и мах. Я вижу, что передали 1 и 20, значит min это 1, а max это 20. У меня тут записано: min + Math.random() * (max - min), значит получается так: 1 + Math.random() * (20-1). Всё, можно это дело вычислить и вернуть."

Вычислив случайные координаты x и y, я преобразую их в адрес внутри массива, и запишу по этому адресу константу ROBOT. Всё, я поставил робота в клетку!

на Питоне:

на JavaScript:

Как я вычисляю адрес? Элементарно. Так как массив у меня размером 22*22, то через каждые 22 элемента начинается новая строка. Y*22 указывает на адрес начала строки с номером Y, к которому прибавляется координата X.

Можно написать всё и в одну строчку, не создавая лишних переменных. Это сделает код более эффективным, но менее читабельным:

field[randint(1, 20) * 22 + randint(1, 20)] = ROBOT

Хорошо, но мне нужно 10 роботов. Могу ли я написать вот так?

Несомненно, я могу так написать. Повторив одну строчку 10 раз, я создам 10 роботов. Но так сделал бы программист, который не знает о циклах. А я лучше напишу цикл:

На JavaScript:

На Питоне:

Циклы выглядят по-разному, но делают одно и то же. Разберем по частям: цикл for в Javascript имеет три параметра, указанные в круглых скобках:

  1. с чего начать: var i = 0;
  2. при каких условиях повторять: i < 10;
  3. что делать в каждом повторении: i++

Развернем это человеческим языком:

  1. перед началом цикла надо завести переменную i и присвоить ей 0;
  2. цикл надо повторять, пока i < 10;
  3. при каждом повторении цикла нужно увеличить i на 1.

Ключевым здесь является третий пункт. Так как при каждом повторении i увеличивается на 1, то цикл отработает ровно 10 раз.

Cамо тела цикла находится между фигурными скобками "{" и "}". Все инструкции, которые там написаны, будут повторены столько раз, сколько раз выполнится цикл.

На Питоне всё несколько иначе:

for i in range(10) значит уже почти человеческим языком:

"для i в пределах 10" (включая 0, но не включая 10, не спрашивайте пока об этом :)

То есть фактически мы просто сообщили, что нам нужно 10 повторений, а транслятор языка Питон сам присвоит i=0 в начале, сам будет прибавлять единицу к i и сам будет проверять, чтобы i было меньше 10.

А тело цикла записано без фигурных скобок, но каждая строчка сдвинута вправо на одинаковое расстояние. Так Python определяет, что это отдельный блок кода (тоже не спрашивайте). Короче говоря, в цикле повторится всё, что сдвинуто вправо относительно первой строчки for.

Ну вот, я создал 10 роботов. Но нужно ещё создать 5 препятствий. Проблем нет – координаты вычисляются так же, цикл повторяется 5 раз, только нужно записывать в массив не константу ROBOT, а константу HAZARD.

Тут я вдруг замечаю, что имею два одинаковых цикла, только с разным числом повторений и с разными константами. Может быть, я напишу функцию, которая будет делать цикл для меня? Я передам в функцию 2 числа: сколько раз повторить и какую константу записать.

Как это делается на JavaScript, мы уже в курсе. Замечу, что эта функция ничего не возвращает в ответ, так тоже можно.

Теперь посмотрим, как сделать функцию в Питоне:

Всё. Функция в Питоне задается не словом function, а словом def (define). Дальше вы можете догадаться – тело функции ограничено не фигурными скобками, а отступом. Тело цикла внутри функции также имеет свой отступ.

Наконец, запишу финальный код генерации 10 роботов и 5 препятствий:

Нужно ещё поставить на поле игрока. Это однократное действие, поэтому ему не нужен ни цикл, ни функция:

Отмечу, что я отдельно сохранил адрес игрока в переменной player_addr, потому что мне нужно будет постоянно с ней работать.

Всё, я получил полностью готовое игровое состояние: в памяти сейчас лежит поле со стенками, роботами, препятствиями и игроком.

Следующим этапом нужно будет отобразить это всё на экране.

Вот пока что полный текущий код на Python и на JavaScript. (Вставить не удалось, не помещается).

Читайте дальше: Графический контекст

Наука
7 млн интересуются