Задание 8
Настала очередь конструктора класса Snake.
Змея у нас будет поначалу состоять из одного кусочка - головы.
А что для него требуется?
Что необходимо передать в конструктор?
Координаты змеи, конечно же.
Надо:
а) Передать в конструктор координаты головы змеи (x и y)
б) создать в нем первый "кусочек змеи" (голову) и добавить его в коллекцию sections.
в) isAlive выставить в true
г) не забудь в конструкторе инициализировать переменную sections. В null не много-то и добавишь!
д) создать и реализовать метод int getX(). Метод должен вернуть координату Х головы змеи.
е) создать и реализовать метод int getY(). Метод должен вернуть координату Y головы змеи.
ё) еще добавить классу метод move()- он нам пригодится попозже.
package com.javarush.test.level23.lesson13.big01;
import java.util.ArrayList;
/**
* Created by promoscow on 22.01.17.
*/
public class Snake {
private ArrayList<SnakeSection> sections;
private boolean isAlive;
private SnakeDirection direction;
public ArrayList<SnakeSection> getSections() {
return sections;
}
public boolean isAlive() {
return isAlive;
}
public SnakeDirection getDirection() {
return direction;
}
public void setDirection(SnakeDirection direction) {
this.direction = direction;
}
public int getX(int x) {
return sections.get(0).getX();
}
public int getY(int y) {
return sections.get(0).getY();
}
public Snake(int x, int y) {
sections = new ArrayList<>();
sections.add(new SnakeSection(x, y));
isAlive = true;
}
public void move() {
}
}
Задание 9
Еще остался самый главный класс - Room.
Что нам нужно для его описания?
Размеры комнаты (width и height) - раз.
Змея - два
Мышь - три.
Надо:
а) создать в классе Room переменные width & height типа int.
б) создать в классе Room переменную snake типа Snake.
в) создать в классе Room переменную mouse типа Snake. Шучу. Типа Mouse, конечно же 🙂
г) создать для них всех геттеры и сеттеры.
д) создать конструктор. Конструктор должен принимать три параметра: width, height и ... snake!
package com.javarush.test.level23.lesson13.big01;
/**
* Created by promoscow on 22.01.17.
*/
public class Room {
private int width;
private int height;
private Snake snake;
private Mouse mouse;
public Room(int width, int height, Snake snake) {
this.width = width;
this.height = height;
this.snake = snake;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public void setSnake(Snake snake) {
this.snake = snake;
}
public void setMouse(Mouse mouse) {
this.mouse = mouse;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Snake getSnake() {
return snake;
}
public Mouse getMouse() {
return mouse;
}
public static void main(String[] args) {
}
}
Задание 10
Займемся методом main.
Для начала надо создать статическую переменную game типа Room. Доступ к переменной должен быть для всех классов.
Затем в методе main:
а) Создать змею - объект Snake
б) Создать комнату - объект типа Room и передать в него ширину, высоту и змею.
в) Установить змее direction равным SnakeDirection.DOWN
Чего еще не хватает? Собственно метода, в котором будет идти вся игровая логика.
И еще нужен метод, который бы отрисовывал все это на экране.
а) создать метод run()
б) создать метод print()
public static void main(String[] args) {
game = new Room(10, 10, new Snake(5, 5));
game.snake.setDirection(SnakeDirection.DOWN);
}
Задание 11
Теперь логика управления мышью.
С мышью у нас будут происходить две вещи.
Первая - змея съест мышь.
Вторая - появляется новая мышь в случайной точке комнаты.
Надо написать и реализовать метод createMouse() в классе Room.
В этом методе мы просто должны создавать новую мышь со случайными координатами в комнате.
Как получить случайные координаты?
Это ты уже должен был знать. На всякий случай даю подсказку:
int x = (int) (Math.random() * width);
Еще понадобится метод - eatMouse(), на случай, если мышь все-таки кто-то съест 🙂
Пока сложной логики в этом методе не будет - просто будем вызывать метод createMouse и все.
public void createMouse() {
int x = (int) (Math.random() * width);
int y = (int) (Math.random() * height);
mouse = new Mouse(x, y);
}
public void eatMouse() {
createMouse();
}
Задание 12
Добавить в метод main:
в) вызов метода createMouse().
Змея-то у нас есть, пусть и мышь будет
г) вызов метода run().
Без него ничего работать не будет. В нем вся основная логика.
Неплохо получилось, но я все-таки внесу пару правок.
Кстати, как насчет написать метод sleep?
Ты уже понял из предыдущих задач, что в методе run нужна пауза.
Но насколько я помню, скорость в змейке должна расти при росте ее длины.
Значит чем длиннее змея, тем выше скорость и меньше пауза.
public static void main(String[] args) {
game = new Room(10, 10, new Snake(5, 5));
game.snake.setDirection(SnakeDirection.DOWN);
game.createMouse();
game.run();
}
Задание 13
Предлагаю тебе в этот раз написать специальный метод sleep().
Который будет делать паузу в зависимости от длины змеи (количества элементов в sections).
Придумай какой-нибудь хитрый алгоритм. Чтобы на первом уровне пауза была 500 миллисекунд,
а к 10 уровню постепенно уменьшилась до 300.
И ниже 200 не опускалась.
/**
* Прогрмма делает паузу, длинна которой зависит от длинны змеи.
*/
public void sleep() {
try {
int pause = 500 - ((snake.getSections().size() - 1) * (200 / 9));
if (pause < 200) pause = 200;
Thread.sleep(pause);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Задание 14
Теперь поработаем над методом print().
Надо:
а) вывести на экран прямоугольник из точек размером width x height.
б) тело змеи отметить символом "x"-английское
в) голову змеи нарисовать символом X-английское.
Подсказка:
а) удобно сначала создать матрицу типа int[][] с размером (height x width)
б) затем пройтись по всем объектам и отрисовать их в матрицу.
Например, тело змеи - 1, голова змеи - 2, мышь - 3.
/**
* Выводим на экран текущее состояние игры
*/
public void print() {
//Создаем массив, куда будем "рисовать" текущее состояние игры
//Рисуем все кусочки змеи
//Рисуем мышь
//Выводим все это на экран
int[][] matrix = new int[height][width];
matrix[snake.getSections().get(0).getY()][snake.getSections().get(0).getX()] = 2;
for (int i = 1; i < snake.getSections().size(); i++) {
matrix[snake.getSections().get(i).getY()][snake.getSections().get(i).getX()] = 1;
}
matrix[mouse.getY()][mouse.getX()] = 3;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == 1) System.out.print(" x ");
else if (matrix[i][j] == 2) System.out.print(" X ");
else if (matrix[i][j] == 3) System.out.print(" * ");
else if (matrix[i][j] == 0) System.out.print(" . ");
}
}
}
Задание 15
Теперь осталось допилить змею.
Вот что я предлагаю насчет движения змеи:
Змея состоит из кусочков. Давай каждый ход просто добавлять один кусочек со стороны головы,
а самый последний - удалять. Тогда получится, что змея ползет.
Добавлять кусочек нужно рядом с текущей головой (кусочком номер 0).
С какой стороны добавлять зависит от direction (UP, DOWN, LEFT, RIGHT).
Подсказка:
а) Как добавить кусочек змеи в начало списка sections?
sections.add(0, new_section);
б) А как удалить последний?
sections.remove(sections.size()-1);
В методе move надо:
а) сделать шаг в текущем направлении (определяется direction)
б) проверить, что если змея уперлась в стену, то умереть (isAlive = false)
в) проверить, что если змея уперлась себя, то умереть (isAlive = false)
г) проверить, если змея встретила мышь - то съесть ее.
public void move() {
if (direction == SnakeDirection.UP) {
sections.add(0, new SnakeSection(sections.get(0).getY() - 1, sections.get(0).getX()));
}
else if (direction == SnakeDirection.DOWN) {
sections.add(0, new SnakeSection(sections.get(0).getY() + 1, sections.get(0).getX()));
}
else if (direction == SnakeDirection.LEFT) {
sections.add(0, new SnakeSection(sections.get(0).getY(), sections.get(0).getX() - 1));
}
else if (direction == SnakeDirection.RIGHT) {
sections.add(0, new SnakeSection(sections.get(0).getY(), sections.get(0).getX() + 1));
}
sections.remove(sections.size()-1);
if (sections.get(0).getY() > Room.game.getHeight() - 1
|| sections.get(0).getY() < 0
|| sections.get(0).getX() > Room.game.getWidth() - 1
|| sections.get(0).getX() < 0) isAlive = false;
for (SnakeSection section : sections) {
if (sections.get(0).getX() == section.getX()
&& sections.get(0).getY() == section.getY()) isAlive = false;
}
if (sections.get(0).getY() == Room.game.getMouse().getY()
&& sections.get(0).getX() == Room.game.getMouse().getX()) Room.game.eatMouse();
}
}
Задание 16
Продолжаем работать над методом move()
Для определения, не пересекается ли змея сама с собой, можно сделать очень простую проверку:
содержит ли список sections "новую голову змеи".
Код для этого будет выглядеть примерно так:
if (sections.contains(head))
При этом head должен быть еще не добавлен в список sections, иначе будет всегда true.
Но чтобы этот код работал, надо реализовать методы сравнения объектов (equals & hashCode) в классе SnakeSection.
Задание:
а) реализовать методы equals & hashCode в классе SnakeSection.
Сигнатура методов:
public boolean equals(Object o)
public int hashCode()
Подсказка:
Используй Alt+Insert в Intellij IDEA
В классе Snake:
б) в методе move(int dx, int dy) создать голову(кусочек змеи) с правильными координатами. Вызвать метод checkBody() и checkBorders()
в) реализовать метод checkBody: если голова змеи пересекается с ее телом (любым из кусочков) - змея умирает (isAlive = false)
/**
* Метод перемещает змею на один ход.
* Направление перемещения задано переменной direction.
*/
public void move() {
if (!isAlive) return;
if (direction == SnakeDirection.UP)
move(0, -1);
else if (direction == SnakeDirection.RIGHT)
move(1, 0);
else if (direction == SnakeDirection.DOWN)
move(0, 1);
else if (direction == SnakeDirection.LEFT)
move(-1, 0);
}
/**
* Метод перемещает змею в соседнюю клетку.
* Кординаты клетки заданы относительно текущей головы с помощью переменных (dx, dy).
*/
private void move(int dx, int dy) {
//Создаем новую голову - новый "кусочек змеи".
//Проверяем - не вылезла ли голова за границу комнаты
//Проверяем - не пересекает ли змея саму себя
//Проверяем - не съела ли змея мышь.
//Двигаем змею.
SnakeSection head = new SnakeSection(dx, dy);
checkBody(head);
checkBorders(head);
}
/**
* Метод проверяет - находится ли новая голова в пределах комнаты
*/
private void checkBorders(SnakeSection head) {
if (head.getY() > Room.game.getHeight() - 1
|| head.getY() < 0
|| head.getX() > Room.game.getWidth() - 1
|| head.getX() < 0) isAlive = false;
}
/**
* Метод проверяет - не совпадает ли голова с каким-нибудь участком тела змеи.
*/
private void checkBody(SnakeSection head) {
if (sections.contains(head)) isAlive = false;
}
Задание 17
Теперь закончим класс Shake
Надо:
а) реализовать метод checkBorders: если голова змеи за границами комнаты - змея умирает (isAlive = false)
Реализовать метод move(int dx, int dy):
б) проверить, не вылезла ли она за границу комнаты (если да, то змея умирает)
в) проверить, не совпадает ли она с уже существующими кусочками змеи (если да, то змея умирает)
г) добавить голову к змее (со стороны головы) и удалить последний кусочек из хвоста.
д) если змея поймала мышь (координаты головы совпадают с координатами мыши), то удалять кусок из хвоста не надо.
/**
* Метод перемещает змею на один ход.
* Направление перемещения задано переменной direction.
*/
public void move() {
if (!isAlive) return;
if (direction == SnakeDirection.UP)
move(0, -1);
else if (direction == SnakeDirection.RIGHT)
move(1, 0);
else if (direction == SnakeDirection.DOWN)
move(0, 1);
else if (direction == SnakeDirection.LEFT)
move(-1, 0);
}
/**
* Метод перемещает змею в соседнюю клетку.
* Кординаты клетки заданы относительно текущей головы с помощью переменных (dx, dy).
*/
private void move(int dx, int dy) {
//Создаем новую голову - новый "кусочек змеи".
//Проверяем - не вылезла ли голова за границу комнаты
//Проверяем - не пересекает ли змея саму себя
//Проверяем - не съела ли змея мышь.
//Двигаем змею.
SnakeSection head = new SnakeSection(sections.get(0).getX() + dx, sections.get(0).getY() + dy); //создаём новую секцию head
checkBody(head); //проверяем, не втыкается ли она в себя
checkBorders(head); //проверяем, не втыкается ли она в борт
sections.add(0, head);
if (head.getY() == Room.game.getMouse().getY()
&& head.getX() == Room.game.getMouse().getX()) {
Room.game.eatMouse();
} else sections.remove(sections.size()-1);
}
/**
* Метод проверяет - находится ли новая голова в пределах комнаты
*/
private void checkBorders(SnakeSection head) {
if (head.getY() >= Room.game.getHeight()
|| head.getY() < 0
|| head.getX() >= Room.game.getWidth()
|| head.getX() < 0) isAlive = false;
}
/**
* Метод проверяет - не совпадает ли голова с каким-нибудь участком тела змеи.
*/
private void checkBody(SnakeSection head) {
if (sections.contains(head)) isAlive = false;
}
Leave A Comment