Визуализация «похождений» робота
Пришло время посмотреть на нашего робота симпатичным образом. Мы создадим уже более сложное приложение, которое сначала «выгуляет» нашего робота, а потом нарисует его путь на форме. Думаю, что это будет неплохой иллюстрацией отношений между классами и примером использования классов. Для реализации мы создадим следующие классы:
- Robot — класс робота, который будет передвигаться и поворачиваться. Но что важно отметить — робот будет запоминать весь путь, который он проходил — т.е. будет вести список прямых, которые он проезжал. Для хранения списка мы используем стандартный класс Java ArrayList. Этот класс мы будем рассматривать более подробно позже при изучении коллекций, а сейчас мы просто будем его использовать «вслепую» — просто знайте, что у него есть метод add, который позволяет добавить в список объект. Также список объектов можно «просмотреть» с помощью конструкции for, которая приведена в классе RobotPathComponent.
- RobotLine — класс для хранения координат одного отрезка пути. Это простой класс, который включает 4 числа — координаты начальной точки (X1, Y1) и координаты конечной точки (X2, Y2).
- RobotPathComponent — этот класс наследуется от уже знакомого нам класса JComponent. Этому классу передается робот со своим списком отрезков пути. В методе paintComponent путем перебора всех отрезков мы получаем координаты каждого и рисуем линию вызовом метода drawLine класса Graphics.
- RobotFrame — класс для отображения формы. Мы уже встречались с подобной реализацией.
- RobotManager — класс для запуска всего приложения. В его методе main мы сначала создаем робота и указываем ему нарисовать 12-ти угольник. Вы можете задать другое количество, изменив значение переменной COUNT. После «прогулки» мы создаем форму и передаем ей нашего робота для отрисовки его пути. Если задать большое количество сторон, то из-за округлений наш многоугольник не замкнется. Можете попробовать это исправить.
Думаю, что комментариев должно быть достаточно — теперь вы можете посмотреть код наших классов и скачать проект для запуска — Robot4.
Класс Robot
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 |
package edu.javacourse.robot; import java.util.ArrayList; import java.util.List; public class Robot { private double x = 0; private double y = 0; protected double course = 0; // Список для хранения линий, по которым перемещался робот // Пока будем использовать его без подробностей private ArrayList<RobotLine> lines = new ArrayList<RobotLine>(); public Robot(double x, double y) { this.x = x; this.y = y; } public void forward(int distance) { // Запоминаем координаты робота перед перемещением final double xOld = x; final double yOld = y; // Меняем координаты x += distance * Math.cos(course / 180 * Math.PI); y += distance * Math.sin(course / 180 * Math.PI); // Запоминаем координаты пройденного пути в списке // Класс List позволяет добавить объект и хранить его lines.add(new RobotLine(xOld, yOld, x, y)); } public double getX() { return x; } public double getY() { return y; } public double getCourse() { return course; } public void setCourse(double course) { this.course = course; } public ArrayList<RobotLine> getLines() { return lines; } } |
Класс RobotLine
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 |
package edu.javacourse.robot; // Класс для хранения одной линии, которую проехал робот public class RobotLine { private double x1; private double y1; private double x2; private double y2; public RobotLine(double x1, double y1, double x2, double y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } public double getX1() { return x1; } public double getY1() { return y1; } public double getX2() { return x2; } public double getY2() { return y2; } } |
Класс RobotPathComponent
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 |
package edu.javacourse.robot.ui; import edu.javacourse.robot.Robot; import edu.javacourse.robot.RobotLine; import java.awt.Graphics; import javax.swing.JComponent; public class RobotPathComponent extends JComponent { private Robot robot; public RobotPathComponent(Robot robot) { this.robot = robot; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Перебираем все линии, которые сохранились у робота // Несколько позже мы разберем эту конструкицю подробно for (RobotLine rl : robot.getLines()) { // Для каждой линии получаем координаты int x1 = (int) Math.round(rl.getX1()); int y1 = (int) Math.round(rl.getY1()); int x2 = (int) Math.round(rl.getX2()); int y2 = (int) Math.round(rl.getY2()); // И рисуем линию с координатами g.drawLine(x1, y1, x2, y2); } } } |
Здесь мы видим конструкцию, которая может вас озадачить — у нее даже комментарии такие Вот эта
for (RobotLine rl : robot.getLines()).
Давайте пока примем ее как есть. Чтобы не было совсем непонятно — эта конструкция перебирает каждый элемент внутри списка и помещает ее в переменную rl. Т.е. внутри цикла эта переменная указывает на элемент списка и тип этого элемента RobotLine. Можно себе представить как будто мы просматриваем кадры кинопленки. На каждом шаге мы перемещаем окошко просмотра на следующий кадр. Окошко просмотра — это переменная rl. С помощью этой переменной мы можем посмотреть параметры конкретного кадра — с нашем случае линии с координатами начала и конца (X1, Y1, X2, Y2).
Класс RobotFrame
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package edu.javacourse.robot.ui; import edu.javacourse.robot.Robot; import javax.swing.JFrame; public class RobotFrame extends JFrame { public RobotFrame(Robot robot) { // Устанавливаем заголовок окна setTitle("Robot Frame"); // Добавляем компонент для рисования пути робота add(new RobotPathComponent(robot)); // Устанавливаем размеры окна setBounds(100, 100, 500, 500); } } |
Класс RobotManager
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 |
package edu.javacourse.robot; import edu.javacourse.robot.ui.RobotFrame; import javax.swing.JFrame; public class RobotManager { public static void main(String[] args) { // Количество сторон многоугольника final int COUNT = 12; // Длина стороны final int SIDE = 100; Robot robot = new Robot(200, 50); // Создаем замкнутую фигуру с количеством углов COUNT for (int i = 0; i < COUNT; i++) { robot.forward(SIDE); robot.setCourse(robot.getCourse() + 360 / COUNT); } // Создаем форму для отрисовки пути нашего робота RobotFrame rf = new RobotFrame(robot); rf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); rf.setVisible(true); } } |
Можете поиграть с нашим роботом. Учтите, что координаты отсчитываются от верхнего левого угла. Хотелось бы заострить ваше внимание на следующем моменте — по коду уже можно видеть, что мы создавая объекты по сути «играем» с ними, указывая, что им делать и в каком порядке. Большинство программ именно так и создаются — просто классов больше, отношения более сложные. Но идея одна — создать объекты нужных классов и заставить их работать в кооперации. Это требует умения и мастерства, которое надо накапливать создавая программы — другого пути пока не придумали.
Попробуйте в качестве маршрута нарисовать какую-нибудь сложную фигуру — например пятиконечную звезду. Или сделать квадратную спираль от самых краев к центру — каждый квадрат все меньше и меньше.
И теперь нас ждет следующая статья: Пример — очередь объектов.