Задание 31. Змейка и Мухоморы: начало
Общее описание игры здесь. Вторая часть игры условие. Третья часть здесь.
Коротко про классы в Java. (пишите/говорите мне, если еще что-то надо описать, или что-то описано плохо/поверхностно)
Дедлайны:
- 9-1: 31 января
- 10-1: 21 января
- 11-1: 21 января
P.S. сдавать это задание можно и после дедлайна - вместе со второй частью (отрисовка), но балл будет снижен. При сдаче вместе с третьей частью максимальное что можно получить - 3.
Создайте пустой проект в IDEA
- File->New->Project
- Сверху слева должна быть выбрана Java, сверху должен быть выбран какой-нибудь Project SDK (по умолчанию все выбрано правильно),
Next
- Поставить галку на
Create project from template
и выбратьCommand Line App
,Next
- Укажите папку для проекта (убедитесь, что у вас есть права на запись в эту папку), и в
Base package
напишитеcom.snake
,Finish
- Если появилось окошко - прочитайте что оно пишет, скорее всего оно спрашивает где открыть созданный проект - в запущенном окне IDEA или в новом окне (жмите на ваше усмотрение)
1) Режим Packages
Слева у вас окно обзора проекта (Project View
) (вызывается горячей кнопкой Alt+1
и Alt+F1 -> 1
).
Вы можете выбрать, что там показывается:
Project
- файлы проекта и библиотеки-зависимости (удобно, когда важны в т.ч. файлы, не являющиеся исходниками)Packages
- только исходники в пакетах и библиотеки-зависимости (удобно когда нужно только кодить, советую этот вариант)
В режиме Packages
вы видите только исходники, разложенные по папкам-пакетам:
- В Java действует правило
один файл - один класс
, поэтому взглянув на эти файлы уже видны основные сущности проекта - Эти классы лежат в специальных папках, которые в Java называются пакеты (packages), обычно это что-то вроде com.projectname.some.long.subnames
-
com.snake.logic
- классы ответственные за описание логики:- класс
Direction
- “направление движения” (на самом деле это специфический класс -Enum
) - класс
Snake
- описание Змейки - класс
TilePosition
- “координата клетки” - класс
World
- описание Мира
- класс
-
com.snake.gui
- классы ответственные за отрисовку:- класс
MainFrame
- Java окно - класс
Renderer
- ответственен за отрисовку нашей игры - класс
UpdateLoop
- ответственен за обновление состояния нашей игры
- класс
2) Про пакеты и классы
В каждом файле класса объявлен публичный класс, его название можно увидеть в нескольких местах (слева направо):
- Название класса-файла в
Project View
- Название в пути к текущему редактируемому файлу
- Название открытого во вкладке файла
- Название класса в его объявлении
- Название класса, ```public static void main(…)`функция которого будет вызываться
Пакет, в котором класс лежит можно увидеть (слева направо):
- Иерархия пакетов в
Project View
- Иерархия в пути к текущему редактируемому файлу
- Объявление в каком пакете должен находиться объявляемый в этом файле класс
3) Создание классов логики нашей игры
Нужно создать четыре класса в пакете com.snake.logic
, как на скриншоте выше:
- TilePosition
- Direction
- Snake
- World
3.1) Создание класса TilePosition
Для этого сначала надо создать пакет logic
в пакете snake
, который лежит в пакете com
:
Правой кнопкой по com.snake
-> New -> Package -> “logic” -> Ok
Теперь надо создать класс TilePosition
:
Правой кнопкой по пакету logic
-> New -> Java Class -> Name=”TilePosition”, Kind=Class -> Ok
Теперь описать его, в нем должны быть:
- Два поля: целые числа x и y
- Конструктор от двух целых чисел
- Функция toString, которая будет приятно для глаза печатать x и y
По аналогии с классом Human
из старого задания:
- x и y должны быть объявлены как и age, name в верхней части Human (верхний эллипс)
- Конструктор должен быть объявлен как и в Human, но называется он TilePosition (т.к. конструктор всегда называется так же, как и конструируемый им класс) и параметрами в него передаются x и y
- toString тоже очень похож, но он должен выводить координаты в удобном виде, например ввиде
Tile[10, 20]
(если x=10 и y=20)
3.2) Создание Direction (Enum)
Создается так же, как и класс, за исключением того, что когда вы указываете название класса в выпадающем списке Kind
надо выбрать вместо Class
- Enum
.
Enum
- это перечисление (сокращенное от enumeration), в нем можно перечислить направления движения, или виды животных. От вас требуется перечислить четыре направления движения - вверх, вниз, влево, вправо.
Вот пример того, как может быть объявлено перечисление пяти видов животных:
package com.zoo;
public enum Animal {
Cat,
Dog,
Narwhal,
Unicorn,
Bear
}
Пример использования:
Animal myAnimal = Animal.Cat;
if (myAnimal == Animal.Dog) {
System.out.println("Что-то не так, ведь мое животное - кошка, а не собака!");
} else if (myAnimal == Animal.Cat) {
System.out.println("Все верно! Мое животное - кошка!"); // Эта строчка исполнится
} else {
System.out.println("Что-то не так, ведь мое животное - кошка, а не что-то еще!");
}
P.S. это по сути более удобная замена константам вида:
int ANIMAL_CAT = 1;
int ANIMAL_DOG = 2;
...
3.3) Создание класса Snake
Аналогично создается класс Snake
в пакете com.snake.logic
, но в нем должно быть:
- Поле snakeParts: список элементов цепочки клеток, которые образуют змейку. Удобный класс для этого -
LinkedList
. Т.к. каждый элемент в нем - это объект классаTilePosition
, то объявление такой переменной имеет видLinkedList<TilePosition> snakeParts
- Поле направления движения:
Direction direction
- Поле длины змейки - целочисленное
- Конструктор змейки (от
TilePosition head
,Direction direction
) - создает змейку из одного звена - головы - Метод
eatApple
- удлиняет змейку на один сегмент (например можно к звеньям добавить последнее звено еще раз через методыLinkedList.peekLast
иLinkedListaddLast
) - Метод
makeStep
- убирает из звеньев последний элемент (LinkedList.pollLast
) и добавляет в начало списка звеньев новую позицию головы (по координатам текущей головы + направление движения)
3.4) Создание класса World
Создается класс World
в пакете logic
:
Поля:
- Число клеток по горизонтали и вертикали
- Змейка
- Яблоко (
TilePosition
)
Конструктор от размера игрового мира (число клеток по обеим осям).
Методы:
- getSnake - возращает змейку
- getWidth, getHeight - возвращают размеры поля
- generateApple - создает новое случайное яблоко в одной из незанятых змейкой клетке
- checkApple - проверяет, а не оказалось ли так, что голова змейки находится в той же клетке, что и яблоко
Обратите внимание, что в checkApple нельзя сравнивать TilePosition с TilePosition как можно было бы сделать с примитивными типами навроде int.
Пример:
if (new TilePosition(1, 2) == new TilePosition(1, 2)) { // логическое выражение всегда false
System.out.println("test1"); // эта ветка никогда не исполнится
} else {
System.out.println("test2"); // всегда выполнится эта ветка кода
}
В таком примере всегда выполнится вторая ветка (логическое выражение всегда false), т.к. оператор == всё кроме примитивных типов сравнивает по адресу в памяти. Т.е. просто сверяет один ли и тот же это объект (не с логической точки зрения, а с точки зрения был ли он создан оператором new в одном и том же месте).
Например в таком коде оператор == вернет true:
TilePosition tile = new TilePosition(1, 2);
if (tile == tile) { // логическое выражение всегда true
System.out.println("test1"); // всегда выполнится эта ветка кода
} else {
System.out.println("test2"); // эта ветка никогда не исполнится
}
В данном случае tile - один и тот же объект с точки зрения создания оператором new (имеет одинаковый адрес в памяти).
Поэтому чтобы сравнить голову змеи и яблоко с точки зрения логического совпадения координат - нужно это сделать более явно, чем через оператор == (например явным сравнением полей объектов - сравнинем x и y).
4) Отправка задания
У вас не должно быть нигде ничего красным подсвечено, т.е. ваш код должен компилироваться. Для убеждения в этом - попробуйте запустить Main класс, который у вас был создан вместе с проектом.
Отправляйте выполненное задание ввиде zip-архива src
папки, и пожалуйста:
- Тему письма называйте правильно (номер этого задания, как написано в самом верху - 31)
- zip-архив называйте по тем же правилам, как назывались патчи (только расширение файла теперь не
.patch
, а.zip
)
Т.е. формат такой же как и про патч, только вместо .patch
вы шлете .zip
.