From d61570fe20c1b803db02d58a8a9f346e07af3455 Mon Sep 17 00:00:00 2001 From: balashov Date: Tue, 9 Apr 2024 12:59:52 +0500 Subject: [PATCH] task3 --- robots/src/main/gui/AbstractWindow.java | 2 +- robots/src/main/gui/CoordinatsWindow.java | 40 ++++ robots/src/main/gui/GameVisualizer.java | 191 +++++------------- robots/src/main/gui/GameWindow.java | 26 +-- robots/src/main/gui/LogWindow.java | 2 +- robots/src/main/gui/MainApplicationFrame.java | 13 +- robots/src/main/model/Robot.java | 101 +++++++++ 7 files changed, 211 insertions(+), 164 deletions(-) create mode 100644 robots/src/main/gui/CoordinatsWindow.java create mode 100644 robots/src/main/model/Robot.java diff --git a/robots/src/main/gui/AbstractWindow.java b/robots/src/main/gui/AbstractWindow.java index 820ccca..f9d3927 100644 --- a/robots/src/main/gui/AbstractWindow.java +++ b/robots/src/main/gui/AbstractWindow.java @@ -19,7 +19,7 @@ public abstract class AbstractWindow extends JInternalFrame implements WithState prefixWindowSizeHeight = formatTitle("size height"); } - public AbstractWindow() { + public AbstractWindow(String окноСостоянияРобота) { super(); } diff --git a/robots/src/main/gui/CoordinatsWindow.java b/robots/src/main/gui/CoordinatsWindow.java new file mode 100644 index 0000000..e317823 --- /dev/null +++ b/robots/src/main/gui/CoordinatsWindow.java @@ -0,0 +1,40 @@ +package gui; + +import model.Robot; + +import java.awt.*; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.*; + +public class CoordinatsWindow extends AbstractWindow implements Observer { + private Robot robot; + private JTextArea textField; + + public CoordinatsWindow(Robot robot){ + super("Окно состояния робота"); + JPanel panel = new JPanel(new BorderLayout()); + + textField = new JTextArea(); + panel.add(textField, BorderLayout.CENTER); + + getContentPane().add(panel); + pack(); + + this.robot = robot; + robot.addObserver(this); + } + + @Override + public void update(Observable o, Object arg) { + if (o.equals(robot)) { + if (arg.equals("robot moved")) + onRobotMoved(); + } + } + + private void onRobotMoved() { + textField.setText(robot.getInfo()); + } +} diff --git a/robots/src/main/gui/GameVisualizer.java b/robots/src/main/gui/GameVisualizer.java index f82cfd8..af81954 100644 --- a/robots/src/main/gui/GameVisualizer.java +++ b/robots/src/main/gui/GameVisualizer.java @@ -1,5 +1,7 @@ package gui; +import model.Robot; + import java.awt.Color; import java.awt.EventQueue; import java.awt.Graphics; @@ -8,185 +10,97 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; + +import java.util.Observer; +import java.util.Observable; import java.util.Timer; import java.util.TimerTask; import javax.swing.JPanel; -public class GameVisualizer extends JPanel +public class GameVisualizer extends JPanel implements Observer { - private final Timer m_timer = initTimer(); - - private static Timer initTimer() - { - Timer timer = new Timer("events generator", true); - return timer; - } - private volatile double m_robotPositionX = 100; - private volatile double m_robotPositionY = 100; - private volatile double m_robotDirection = 0; + private volatile double m_robotPositionY = 100; + private volatile double m_robotDirection = 0; private volatile int m_targetPositionX = 150; private volatile int m_targetPositionY = 100; - - private static final double maxVelocity = 0.1; - private static final double maxAngularVelocity = 0.001; - - public GameVisualizer() + + private final Robot robot; + + public GameVisualizer(Robot robot) { - m_timer.schedule(new TimerTask() - { + Timer m_timer = new Timer("events generator", true); + + m_timer.schedule(new TimerTask() { @Override - public void run() - { + public void run() { onRedrawEvent(); } }, 0, 50); - m_timer.schedule(new TimerTask() - { + m_timer.schedule(new TimerTask() { @Override - public void run() - { - onModelUpdateEvent(); + public void run() { + robot.update(m_targetPositionX, m_targetPositionY); } }, 0, 10); - addMouseListener(new MouseAdapter() - { + addMouseListener(new MouseAdapter() { @Override - public void mouseClicked(MouseEvent e) - { + public void mouseClicked(MouseEvent e) { setTargetPosition(e.getPoint()); repaint(); } }); setDoubleBuffered(true); + + this.robot = robot; + robot.addObserver(this); } - protected void setTargetPosition(Point p) - { + protected void setTargetPosition(Point p) { m_targetPositionX = p.x; m_targetPositionY = p.y; } - - protected void onRedrawEvent() - { + + protected void onRedrawEvent() { EventQueue.invokeLater(this::repaint); } - private static double distance(double x1, double y1, double x2, double y2) - { - double diffX = x1 - x2; - double diffY = y1 - y2; - return Math.sqrt(diffX * diffX + diffY * diffY); - } - - private static double angleTo(double fromX, double fromY, double toX, double toY) - { - double diffX = toX - fromX; - double diffY = toY - fromY; - - return asNormalizedRadians(Math.atan2(diffY, diffX)); - } - - protected void onModelUpdateEvent() - { - double distance = distance(m_targetPositionX, m_targetPositionY, - m_robotPositionX, m_robotPositionY); - if (distance < 0.5) - { - return; - } - double velocity = maxVelocity; - double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, m_targetPositionX, m_targetPositionY); - double angularVelocity = 0; - if (angleToTarget > m_robotDirection) - { - angularVelocity = maxAngularVelocity; - } - if (angleToTarget < m_robotDirection) - { - angularVelocity = -maxAngularVelocity; - } - - moveRobot(velocity, angularVelocity, 10); - } - - private static double applyLimits(double value, double min, double max) - { - if (value < min) - return min; - if (value > max) - return max; - return value; - } - - private void moveRobot(double velocity, double angularVelocity, double duration) - { - velocity = applyLimits(velocity, 0, maxVelocity); - angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); - double newX = m_robotPositionX + velocity / angularVelocity * - (Math.sin(m_robotDirection + angularVelocity * duration) - - Math.sin(m_robotDirection)); - if (!Double.isFinite(newX)) - { - newX = m_robotPositionX + velocity * duration * Math.cos(m_robotDirection); - } - double newY = m_robotPositionY - velocity / angularVelocity * - (Math.cos(m_robotDirection + angularVelocity * duration) - - Math.cos(m_robotDirection)); - if (!Double.isFinite(newY)) - { - newY = m_robotPositionY + velocity * duration * Math.sin(m_robotDirection); - } - m_robotPositionX = newX; - m_robotPositionY = newY; - double newDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration); - m_robotDirection = newDirection; + @Override + public void update(Observable o, Object arg){ + if (o.equals(robot)) + if (arg.equals("robot moved")){ + m_robotPositionX = robot.getRobotPositionX(); + m_robotPositionY = robot.getRobotPositionY(); + m_robotDirection = robot.getRobotDirection(); + } } - private static double asNormalizedRadians(double angle) - { - while (angle < 0) - { - angle += 2*Math.PI; - } - while (angle >= 2*Math.PI) - { - angle -= 2*Math.PI; - } - return angle; - } - - private static int round(double value) - { + private static int round(double value) { return (int)(value + 0.5); } - + @Override - public void paint(Graphics g) - { + public void paint(Graphics g) { super.paint(g); - Graphics2D g2d = (Graphics2D)g; + Graphics2D g2d = (Graphics2D)g; drawRobot(g2d, round(m_robotPositionX), round(m_robotPositionY), m_robotDirection); drawTarget(g2d, m_targetPositionX, m_targetPositionY); } - - private static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) - { + + private static void fillOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); } - - private static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) - { + + private static void drawOval(Graphics g, int centerX, int centerY, int diam1, int diam2) { g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); } - - private void drawRobot(Graphics2D g, int x, int y, double direction) - { - int robotCenterX = round(m_robotPositionX); - int robotCenterY = round(m_robotPositionY); - AffineTransform t = AffineTransform.getRotateInstance(direction, robotCenterX, robotCenterY); + + private void drawRobot(Graphics2D g, int x, int y, double direction) { + int robotCenterX = round(x); + int robotCenterY = round(y); + AffineTransform t = AffineTransform.getRotateInstance(direction, robotCenterX, robotCenterY); g.setTransform(t); g.setColor(Color.MAGENTA); fillOval(g, robotCenterX, robotCenterY, 30, 10); @@ -197,14 +111,13 @@ private void drawRobot(Graphics2D g, int x, int y, double direction) g.setColor(Color.BLACK); drawOval(g, robotCenterX + 10, robotCenterY, 5, 5); } - - private void drawTarget(Graphics2D g, int x, int y) - { - AffineTransform t = AffineTransform.getRotateInstance(0, 0, 0); + + private void drawTarget(Graphics2D g, int x, int y) { + AffineTransform t = AffineTransform.getRotateInstance(0, 0, 0); g.setTransform(t); g.setColor(Color.GREEN); fillOval(g, x, y, 5, 5); g.setColor(Color.BLACK); drawOval(g, x, y, 5, 5); } -} +} \ No newline at end of file diff --git a/robots/src/main/gui/GameWindow.java b/robots/src/main/gui/GameWindow.java index b3bb917..34382e1 100644 --- a/robots/src/main/gui/GameWindow.java +++ b/robots/src/main/gui/GameWindow.java @@ -1,33 +1,21 @@ package gui; -import java.awt.BorderLayout; + +import java.awt.*; import javax.swing.JPanel; +import model.Robot; public class GameWindow extends AbstractWindow { private final GameVisualizer m_visualizer; - - public GameWindow() { - super(); - - setTitle("Игровое окно"); - setResizable(true); - setClosable(true); - setMaximizable(true); - setIconifiable(true); - - m_visualizer = new GameVisualizer(); + public GameWindow(Robot robot) + { + super("Игровое поле"); + m_visualizer = new GameVisualizer(robot); JPanel panel = new JPanel(new BorderLayout()); panel.add(m_visualizer, BorderLayout.CENTER); getContentPane().add(panel); pack(); } - - @Override - public void dispose() { -// m_visualizer.stopTimer(); - - super.dispose(); - } } diff --git a/robots/src/main/gui/LogWindow.java b/robots/src/main/gui/LogWindow.java index 015a6c0..a536903 100644 --- a/robots/src/main/gui/LogWindow.java +++ b/robots/src/main/gui/LogWindow.java @@ -15,7 +15,7 @@ public class LogWindow extends AbstractWindow implements LogChangeListener private final TextArea m_logContent; public LogWindow(LogWindowSource logSource) { - super(); + super("Окно состояния робота"); setTitle("Окно логов"); setResizable(true); diff --git a/robots/src/main/gui/MainApplicationFrame.java b/robots/src/main/gui/MainApplicationFrame.java index b1e0412..e514174 100644 --- a/robots/src/main/gui/MainApplicationFrame.java +++ b/robots/src/main/gui/MainApplicationFrame.java @@ -1,6 +1,7 @@ - package gui; +import model.Robot; + import java.awt.*; import java.awt.event.*; import java.util.ResourceBundle; @@ -39,9 +40,10 @@ public void windowClosing(WindowEvent e) { } private JDesktopPane createDesktopPane() { desktopPane = new JDesktopPane(); - + Robot robot = new Robot(100, 100); addWindow(createLogWindow(), 300, 800); - addWindow(new GameWindow(), 400, 400); + addWindow(new GameWindow(robot), 400, 400); + addWindow(new CoordinatsWindow(robot), 200, 200); for (JInternalFrame frame : desktopPane.getAllFrames()) { ((AbstractWindow) frame).loadWindow(); @@ -82,11 +84,14 @@ private JMenu createFileMenu() { menu.setMnemonic(KeyEvent.VK_D); menu.add(createMenuItem(messages.getString("NewGameWindow"), KeyEvent.VK_N, KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK), (event) -> { - GameWindow window = new GameWindow(); + Robot robot = new Robot(100, 100); + GameWindow window = new GameWindow(robot); addWindow(window, 400, 400); + addWindow(new CoordinatsWindow(robot), 200, 200); })); + menu.add(createMenuItem(messages.getString("LogsWindow"), KeyEvent.VK_L, KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.ALT_MASK), (event) -> { LogWindow window = new LogWindow(Logger.getDefaultLogSource()); addWindow(window, 150, 350); diff --git a/robots/src/main/model/Robot.java b/robots/src/main/model/Robot.java new file mode 100644 index 0000000..8ad6e5a --- /dev/null +++ b/robots/src/main/model/Robot.java @@ -0,0 +1,101 @@ +package model; + +import java.util.Observable; + +public class Robot extends Observable { + private volatile double m_robotPositionX; + private volatile double m_robotPositionY; + private volatile double m_robotDirection = 0; + + private static final double maxVelocity = 0.1; + private static final double maxAngularVelocity = 0.003; + + public Robot(int x, int y){ + super(); + m_robotPositionX = x; + m_robotPositionY = y; + } + + public double getRobotPositionX() { + return m_robotPositionX; + } + + public double getRobotPositionY() { + return m_robotPositionY; + } + + public double getRobotDirection() { + return m_robotDirection; + } + + public String getInfo(){ + return String.format("X: %.2f\nY: %.2f", m_robotPositionX, m_robotPositionY); + } + + public void update(double targetPositionX, double targetPositionY){ + double distance = distance(targetPositionX, targetPositionY, m_robotPositionX, m_robotPositionY); + if (distance < 0.5) return; + + double angleToTarget = angleTo(m_robotPositionX, m_robotPositionY, targetPositionX, targetPositionY); + double angularVelocity = 0; + + double diff = asNormalizedRadians(angleToTarget - m_robotDirection); + + if (diff < Math.PI) angularVelocity = maxAngularVelocity; + if (diff > Math.PI) angularVelocity = -maxAngularVelocity; + + moveRobot(maxVelocity, angularVelocity, 10); + + setChanged(); + notifyObservers("robot moved"); + clearChanged(); + } + + private static double distance(double x1, double y1, double x2, double y2) { + double diffX = x1 - x2; + double diffY = y1 - y2; + return Math.sqrt(diffX * diffX + diffY * diffY); + } + + private static double angleTo(double fromX, double fromY, double toX, double toY) { + double diffX = toX - fromX; + double diffY = toY - fromY; + return asNormalizedRadians(Math.atan2(diffY, diffX)); + } + + private static double asNormalizedRadians(double angle) { + while (angle < 0) angle += 2*Math.PI; + while (angle >= 2*Math.PI) angle -= 2*Math.PI; + return angle; + } + + private void moveRobot(double velocity, double angularVelocity, double duration) { + velocity = applyLimits(velocity, 0, maxVelocity); + angularVelocity = applyLimits(angularVelocity, -maxAngularVelocity, maxAngularVelocity); + + double newX = m_robotPositionX + velocity / angularVelocity * + (Math.sin(m_robotDirection + angularVelocity * duration) - Math.sin(m_robotDirection)); + + if (!Double.isFinite(newX)) { + newX = m_robotPositionX + velocity * duration * Math.cos(m_robotDirection); + } + + double newY = m_robotPositionY - velocity / angularVelocity * + (Math.cos(m_robotDirection + angularVelocity * duration) - Math.cos(m_robotDirection)); + + if (!Double.isFinite(newY)) { + newY = m_robotPositionY + velocity * duration * Math.sin(m_robotDirection); + } + + m_robotPositionX = newX; + m_robotPositionY = newY; + double newDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration); + m_robotDirection = newDirection; + } + + private static double applyLimits(double value, double min, double max) { + if (value < min) return min; + if (value > max) return max; + return value; + } +} \ No newline at end of file