From fa8f624e718ece949e7f7c9e75a9cb0a657ef0bd Mon Sep 17 00:00:00 2001 From: Leonid Date: Tue, 9 Apr 2024 23:15:57 +0500 Subject: [PATCH 1/3] some fix drawing --- robots/src/gui/AbstractWindowState.java | 4 + robots/src/gui/GameVisualizer.java | 122 ++++++----------------- robots/src/gui/GameWindow.java | 4 +- robots/src/gui/MainApplicationFrame.java | 4 +- robots/src/gui/Robot.java | 119 ++++++++++++++++++++++ robots/src/gui/RobotInfo.java | 32 ++++++ 6 files changed, 188 insertions(+), 97 deletions(-) create mode 100644 robots/src/gui/Robot.java create mode 100644 robots/src/gui/RobotInfo.java diff --git a/robots/src/gui/AbstractWindowState.java b/robots/src/gui/AbstractWindowState.java index 63cbed884..0f1371ba8 100644 --- a/robots/src/gui/AbstractWindowState.java +++ b/robots/src/gui/AbstractWindowState.java @@ -16,6 +16,10 @@ public AbstractWindowState(String string, boolean b1, boolean b2, boolean b3, bo super(string, b1, b2, b3, b4); } + public AbstractWindowState() { + super(); + } + private static Preferences getPreferences() { return Preferences.userRoot().node(prefixWindowPreferences); } diff --git a/robots/src/gui/GameVisualizer.java b/robots/src/gui/GameVisualizer.java index a1c8799a8..7568cc5db 100644 --- a/robots/src/gui/GameVisualizer.java +++ b/robots/src/gui/GameVisualizer.java @@ -8,32 +8,35 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; +import java.util.Observable; +import java.util.Observer; 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() - { + + 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 final Robot robot; private static final double maxVelocity = 0.1; private static final double maxAngularVelocity = 0.001; - public GameVisualizer() + public GameVisualizer(Robot robot) { m_timer.schedule(new TimerTask() { @@ -48,7 +51,7 @@ public void run() @Override public void run() { - onModelUpdateEvent(); + robot.update(m_targetPositionX, m_targetPositionY); } }, 0, 10); addMouseListener(new MouseAdapter() @@ -60,105 +63,26 @@ public void mouseClicked(MouseEvent e) repaint(); } }); + this.robot = robot; + robot.addObserver(this); + setDoubleBuffered(true); } protected void setTargetPosition(Point p) { - m_targetPositionX = p.x; - m_targetPositionY = p.y; + double rate = 3f/2f; + m_targetPositionX = (int) (p.x * rate); + m_targetPositionY = (int) (p.y * rate); } 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; - } public void stopTimer(){ m_timer.cancel(); } - 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 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) { @@ -209,4 +133,14 @@ private void drawTarget(Graphics2D g, int x, int y) g.setColor(Color.BLACK); drawOval(g, x, y, 5, 5); } + + @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(); + } + } } diff --git a/robots/src/gui/GameWindow.java b/robots/src/gui/GameWindow.java index d5d6b231b..4eb8e2a7c 100644 --- a/robots/src/gui/GameWindow.java +++ b/robots/src/gui/GameWindow.java @@ -7,10 +7,10 @@ public class GameWindow extends AbstractWindowState { private final GameVisualizer m_visualizer; - public GameWindow(String title) + public GameWindow(String title, Robot robot) { super(title, true, true, true, true); - m_visualizer = new GameVisualizer(); + m_visualizer = new GameVisualizer(robot); JPanel panel = new JPanel(new BorderLayout()); panel.add(m_visualizer, BorderLayout.CENTER); getContentPane().add(panel); diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index ffd22f0e9..16b3f361d 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -172,9 +172,11 @@ public MainApplicationFrame() { setContentPane(desktopPane); + var robot = new Robot(10, 10); + addWindow(new RobotInfo(robot), 300, 300); addWindow(createLogWindow()); - addWindow(new GameWindow(bundle.getString("gameWindow.title")), + addWindow(new GameWindow(bundle.getString("gameWindow.title"), robot), 400, 400); for (var frame : desktopPane.getAllFrames()) diff --git a/robots/src/gui/Robot.java b/robots/src/gui/Robot.java new file mode 100644 index 000000000..069112857 --- /dev/null +++ b/robots/src/gui/Robot.java @@ -0,0 +1,119 @@ +package gui; + +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 log() { + return String.format( + "Position: (%f, %f) | Direction: %f", + m_robotPositionX, m_robotPositionY, m_robotDirection + ); + } + + 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 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 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 applyLimits(double value, double min, double max) + { + if (value < min) + return min; + return Math.min(value, max); + } + + public void update(double m_targetPositionX, double m_targetPositionY) { + double distance = distance(m_targetPositionX, m_targetPositionY, m_robotPositionX, m_robotPositionY); + + if (distance < 0.5) return; + + 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(maxVelocity, angularVelocity, 10); + + setChanged(); + notifyObservers("robot moved"); + clearChanged(); + } + + 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; + } +} diff --git a/robots/src/gui/RobotInfo.java b/robots/src/gui/RobotInfo.java new file mode 100644 index 000000000..7dac11b2d --- /dev/null +++ b/robots/src/gui/RobotInfo.java @@ -0,0 +1,32 @@ +package gui; + +import java.awt.*; +import java.util.Observable; +import java.util.Observer; +import javax.swing.JLabel; + +public class RobotInfo extends AbstractWindowState implements Observer { + private final Robot robot; + private final JLabel label; + + + public RobotInfo(Robot robot) { + super(); + this.robot = robot; + this.label = new JLabel(); + + robot.addObserver(this); + setResizable(true); + setClosable(true); + setMaximizable(true); + setIconifiable(true); + + getContentPane().add(label, BorderLayout.CENTER); + pack(); + } + + @Override + public void update(Observable o, Object arg) { + label.setText(robot.log()); + } +} From 6af1181d2be8d96567b455c7248f3530a2d2643d Mon Sep 17 00:00:00 2001 From: Leonid Date: Tue, 9 Apr 2024 23:15:57 +0500 Subject: [PATCH 2/3] fix robot --- robots/src/game/GameVisualizer.java | 95 ++++++++++ robots/src/game/GameWindow.java | 39 +++++ robots/src/game/Robot.java | 38 ++++ robots/src/game/RobotInfo.java | 34 ++++ robots/src/game/RobotLogic.java | 125 +++++++++++++ robots/src/game/Target.java | 16 ++ robots/src/gui/AbstractWindowState.java | 4 + robots/src/gui/GameVisualizer.java | 212 ----------------------- robots/src/gui/GameWindow.java | 25 --- robots/src/gui/MainApplicationFrame.java | 8 +- 10 files changed, 357 insertions(+), 239 deletions(-) create mode 100644 robots/src/game/GameVisualizer.java create mode 100644 robots/src/game/GameWindow.java create mode 100644 robots/src/game/Robot.java create mode 100644 robots/src/game/RobotInfo.java create mode 100644 robots/src/game/RobotLogic.java create mode 100644 robots/src/game/Target.java delete mode 100644 robots/src/gui/GameVisualizer.java delete mode 100644 robots/src/gui/GameWindow.java diff --git a/robots/src/game/GameVisualizer.java b/robots/src/game/GameVisualizer.java new file mode 100644 index 000000000..599972a3a --- /dev/null +++ b/robots/src/game/GameVisualizer.java @@ -0,0 +1,95 @@ +package game; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.util.TimerTask; + +import javax.swing.JPanel; + +public class GameVisualizer extends JPanel +{ + private final RobotLogic logic; + + public GameVisualizer(RobotLogic logic) + { + this.logic = logic; + + logic.addActionToTimer(new TimerTask() + { + @Override + public void run() + { + repaint(); + } + }, 50); + + addMouseListener(new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + Point clickPoint = e.getPoint(); + + logic.setTarget(new Target(clickPoint.getX(), clickPoint.getY())); + logic.setWindowBounds(new Point2D.Double(getWidth(), getHeight())); + repaint(); + } + }); + + setDoubleBuffered(true); + } + + @Override + public void paint(Graphics g) + { + super.paint(g); + Graphics2D g2d = (Graphics2D) g; + drawRobot(g2d, logic.getRobot()); + drawTarget(g2d, logic.getTarget()); + } + + 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) + { + g.drawOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, diam2); + } + + private void drawRobot(Graphics2D g, Robot robot) + { + int robotCenterX = (int) Math.round(robot.getPosition().getX()); + int robotCenterY = (int) Math.round(robot.getPosition().getY()); + AffineTransform t = AffineTransform.getRotateInstance(robot.getDirection(), robotCenterX, robotCenterY); + g.setTransform(t); + + g.setColor(Color.MAGENTA); + fillOval(g, robotCenterX, robotCenterY, 30, 10); + g.setColor(Color.BLACK); + drawOval(g, robotCenterX, robotCenterY, 30, 10); + + g.setColor(Color.WHITE); + fillOval(g, robotCenterX + 10, robotCenterY, 5, 5); + g.setColor(Color.BLACK); + drawOval(g, robotCenterX + 10, robotCenterY, 5, 5); + } + + private void drawTarget(Graphics2D g, Target target) + { + AffineTransform t = AffineTransform.getRotateInstance(0, 0, 0); + g.setTransform(t); + + g.setColor(Color.GREEN); + fillOval(g, (int) target.getPosition().getX(), (int) target.getPosition().getY(), 5, 5); + g.setColor(Color.BLACK); + drawOval(g, (int) target.getPosition().getX(), (int) target.getPosition().getY(), 5, 5); + } +} diff --git a/robots/src/game/GameWindow.java b/robots/src/game/GameWindow.java new file mode 100644 index 000000000..c61421954 --- /dev/null +++ b/robots/src/game/GameWindow.java @@ -0,0 +1,39 @@ +package game; + +import gui.AbstractWindowState; + +import java.awt.BorderLayout; + +import javax.swing.JPanel; + +public class GameWindow extends AbstractWindowState +{ + private final GameVisualizer m_visualizer; + private final RobotLogic logic; + public GameWindow(String title, RobotLogic logic) + { + super(); + + this.logic = logic; + logic.startTimer(); + + setTitle(title); + setResizable(true); + setClosable(true); + setMaximizable(true); + setIconifiable(true); + + m_visualizer = new GameVisualizer(logic); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(m_visualizer, BorderLayout.CENTER); + getContentPane().add(panel); + pack(); + } + + @Override + public void dispose() { + super.dispose(); + logic.stopTimer(); + } +} diff --git a/robots/src/game/Robot.java b/robots/src/game/Robot.java new file mode 100644 index 000000000..7a60f9f98 --- /dev/null +++ b/robots/src/game/Robot.java @@ -0,0 +1,38 @@ +package game; + +import java.awt.geom.Point2D; + +public class Robot{ + private final Point2D.Double position = new Point2D.Double(100, 100); + private volatile double direction = 0; + private double angularVelocity = 0; + private final double velocity = 0.1; + + public double getVelocity() { + return velocity; + } + + public Point2D.Double getPosition() { + return position; + } + + public double getDirection() { + return direction; + } + + public void setDirection(double direction) { + this.direction = direction; + } + + public void setAngularVelocity(double angularVelocity) { + this.angularVelocity = angularVelocity; + } + + public double getAngularVelocity() { + return angularVelocity; + } + + public void move(Point2D.Double dv) { + position.setLocation(getPosition().getX() + dv.getX(), getPosition().getY() + dv.getY()); + } +} diff --git a/robots/src/game/RobotInfo.java b/robots/src/game/RobotInfo.java new file mode 100644 index 000000000..123ac9275 --- /dev/null +++ b/robots/src/game/RobotInfo.java @@ -0,0 +1,34 @@ +package game; + +import gui.AbstractWindowState; + +import java.awt.*; +import java.util.Observable; +import java.util.Observer; +import javax.swing.JLabel; + +public class RobotInfo extends AbstractWindowState implements Observer { + private final JLabel label; + + + public RobotInfo(RobotLogic logic) { + super(); + this.label = new JLabel(); + + logic.addObserver(this); + setResizable(true); + setClosable(true); + setMaximizable(true); + setIconifiable(true); + + getContentPane().add(label, BorderLayout.CENTER); + pack(); + } + + @Override + public void update(Observable o, Object arg) { + RobotLogic lg = (RobotLogic) o; + label.setText("x=%f y=%f dir=%f".formatted(lg.getRobot().getPosition().getX(), + lg.getRobot().getPosition().getY(), lg.getRobot().getDirection())); + } +} diff --git a/robots/src/game/RobotLogic.java b/robots/src/game/RobotLogic.java new file mode 100644 index 000000000..869fdfac3 --- /dev/null +++ b/robots/src/game/RobotLogic.java @@ -0,0 +1,125 @@ +package game; + +import java.awt.geom.Point2D; +import java.awt.geom.Point2D.Double; +import java.util.Observable; +import java.util.Timer; +import java.util.TimerTask; + +public class RobotLogic extends Observable { + private static final double ANGULAR_VELOCITY = 0.001; + private static final double TARGET_CLOSE_ENOUGH = 5; + private final static double EPSILON = 0.05; + + private final Robot robot; + private Target target; + + private final long dt = 5; + private Timer timer; + private Point2D.Double windowBounds = new Point2D.Double(300, 300); + + public RobotLogic() { + robot = new Robot(); + target = new Target(10, 10); + setTarget(target); + moveRobot(); + } + + public void startTimer() { + timer = new Timer("event generator", true); + addActionToTimer(new TimerTask() { + @Override + public void run() { + moveRobot(); + + setChanged(); + notifyObservers(); + } + }, dt); + } + + public void addActionToTimer(TimerTask task, long timeout) { + timer.schedule(task, 0, timeout); + } + + public void stopTimer() { + timer.cancel(); + } + + public Robot getRobot() { + return robot; + } + + public Target getTarget() { + return target; + } + + public void setTarget(Target target) { + this.target = target; + + if (RobotsMath.angleTo(robot.getPosition(), target.getPosition()) > robot.getDirection()) { + robot.setAngularVelocity(-ANGULAR_VELOCITY); + } else { + robot.setAngularVelocity(ANGULAR_VELOCITY); + } + } + + public void setWindowBounds(Point2D.Double windowBounds) { + this.windowBounds = windowBounds; + } + + public void moveRobot() { + if (robot.getPosition().distance(target.getPosition()) < TARGET_CLOSE_ENOUGH) { + return; + } + + final double angleRobotTarget = RobotsMath.angleTo(robot.getPosition(), target.getPosition()); + + if (Math.abs(robot.getAngularVelocity()) < ANGULAR_VELOCITY || + Math.abs(robot.getDirection() - angleRobotTarget) < EPSILON) { + robot.move(new Double( + robot.getVelocity() * Math.cos(robot.getDirection()) * dt, + robot.getVelocity() * Math.sin(robot.getDirection()) * dt + )); + + return; + } + + final double newAngle = RobotsMath.asNormalizedRadians( + robot.getDirection() + robot.getAngularVelocity() * dt); + + final double dx = robot.getVelocity() / robot.getAngularVelocity() * + (Math.sin(newAngle) - Math.sin(robot.getDirection())); + final double dy = robot.getVelocity() / robot.getAngularVelocity() * + (Math.cos(newAngle) - Math.cos(robot.getDirection())); + + robot.move(new Point2D.Double( + dx * RobotsMath.speedCoefficient(robot.getPosition().getX(), windowBounds.getX()), + - dy * RobotsMath.speedCoefficient(robot.getPosition().getY(), windowBounds.getY()) + )); + robot.setDirection(newAngle); + } + + private static class RobotsMath { + public static double angleTo(Point2D.Double p0, Point2D.Double p1) { + final double dx = p1.getX() - p0.getX(); + final double dy = p1.getY() - p0.getY(); + + return asNormalizedRadians(Math.atan2(dy, dx)); + } + + private static double asNormalizedRadians(double angle) { + final double TAU = 2 * Math.PI; + + if (angle < 0) { + return TAU - ((-angle) % TAU); + } + + return angle % TAU; + } + + private static double speedCoefficient(double t, double upperBoundT) { + return Math.max(1 - 2 * Math.abs((upperBoundT - t) / upperBoundT - 0.5), 0.01); + } + } +} diff --git a/robots/src/game/Target.java b/robots/src/game/Target.java new file mode 100644 index 000000000..68922e5e8 --- /dev/null +++ b/robots/src/game/Target.java @@ -0,0 +1,16 @@ +package game; + +import java.awt.geom.Point2D; + +public class Target { + private final Point2D.Double position = new Point2D.Double(); + + public Target(double x, double y) { + double rate = 3/2f; + position.setLocation(x * rate, y * rate); + } + + public Point2D.Double getPosition() { + return position; + } +} diff --git a/robots/src/gui/AbstractWindowState.java b/robots/src/gui/AbstractWindowState.java index 63cbed884..0f1371ba8 100644 --- a/robots/src/gui/AbstractWindowState.java +++ b/robots/src/gui/AbstractWindowState.java @@ -16,6 +16,10 @@ public AbstractWindowState(String string, boolean b1, boolean b2, boolean b3, bo super(string, b1, b2, b3, b4); } + public AbstractWindowState() { + super(); + } + private static Preferences getPreferences() { return Preferences.userRoot().node(prefixWindowPreferences); } diff --git a/robots/src/gui/GameVisualizer.java b/robots/src/gui/GameVisualizer.java deleted file mode 100644 index a1c8799a8..000000000 --- a/robots/src/gui/GameVisualizer.java +++ /dev/null @@ -1,212 +0,0 @@ -package gui; - -import java.awt.Color; -import java.awt.EventQueue; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.util.Timer; -import java.util.TimerTask; - -import javax.swing.JPanel; - -public class GameVisualizer extends JPanel -{ - 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 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() - { - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - onRedrawEvent(); - } - }, 0, 50); - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - onModelUpdateEvent(); - } - }, 0, 10); - addMouseListener(new MouseAdapter() - { - @Override - public void mouseClicked(MouseEvent e) - { - setTargetPosition(e.getPoint()); - repaint(); - } - }); - setDoubleBuffered(true); - } - - protected void setTargetPosition(Point p) - { - m_targetPositionX = p.x; - m_targetPositionY = p.y; - } - - 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; - } - public void stopTimer(){ - m_timer.cancel(); - } - 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 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) - { - return (int)(value + 0.5); - } - - @Override - public void paint(Graphics g) - { - super.paint(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) - { - g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, 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); - g.setTransform(t); - g.setColor(Color.MAGENTA); - fillOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.WHITE); - fillOval(g, robotCenterX + 10, robotCenterY, 5, 5); - 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); - g.setTransform(t); - g.setColor(Color.GREEN); - fillOval(g, x, y, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, x, y, 5, 5); - } -} diff --git a/robots/src/gui/GameWindow.java b/robots/src/gui/GameWindow.java deleted file mode 100644 index d5d6b231b..000000000 --- a/robots/src/gui/GameWindow.java +++ /dev/null @@ -1,25 +0,0 @@ -package gui; - -import java.awt.BorderLayout; - -import javax.swing.JPanel; - -public class GameWindow extends AbstractWindowState -{ - private final GameVisualizer m_visualizer; - public GameWindow(String title) - { - super(title, true, true, true, true); - m_visualizer = new GameVisualizer(); - JPanel panel = new JPanel(new BorderLayout()); - panel.add(m_visualizer, BorderLayout.CENTER); - getContentPane().add(panel); - pack(); - } - - @Override - public void dispose() { - super.dispose(); - m_visualizer.stopTimer(); - } -} diff --git a/robots/src/gui/MainApplicationFrame.java b/robots/src/gui/MainApplicationFrame.java index ffd22f0e9..f0a0cbfe0 100644 --- a/robots/src/gui/MainApplicationFrame.java +++ b/robots/src/gui/MainApplicationFrame.java @@ -14,6 +14,8 @@ import javax.swing.*; +import game.GameWindow; +import game.RobotLogic; import log.Logger; /** @@ -172,9 +174,11 @@ public MainApplicationFrame() { setContentPane(desktopPane); + var logic = new RobotLogic(); + addWindow(new game.RobotInfo(logic), 300, 300); addWindow(createLogWindow()); - addWindow(new GameWindow(bundle.getString("gameWindow.title")), + addWindow(new GameWindow(bundle.getString("gameWindow.title"), logic), 400, 400); for (var frame : desktopPane.getAllFrames()) @@ -205,7 +209,7 @@ public void windowClosing(WindowEvent e) { } }); } - + protected LogWindow createLogWindow() { LogWindow logWindow = new LogWindow(Logger.getDefaultLogSource(), bundle.getString("logWindow.title")); From 5f15986a8c9739617414a373613aaca479d785f3 Mon Sep 17 00:00:00 2001 From: Leonid Date: Mon, 29 Apr 2024 23:03:36 +0500 Subject: [PATCH 3/3] delete useless --- robots/src/gui/GameVisualizer.java | 146 ----------------------------- robots/src/gui/GameWindow.java | 25 ----- robots/src/gui/Robot.java | 119 ----------------------- robots/src/gui/RobotInfo.java | 32 ------- 4 files changed, 322 deletions(-) delete mode 100644 robots/src/gui/GameVisualizer.java delete mode 100644 robots/src/gui/GameWindow.java delete mode 100644 robots/src/gui/Robot.java delete mode 100644 robots/src/gui/RobotInfo.java diff --git a/robots/src/gui/GameVisualizer.java b/robots/src/gui/GameVisualizer.java deleted file mode 100644 index 7568cc5db..000000000 --- a/robots/src/gui/GameVisualizer.java +++ /dev/null @@ -1,146 +0,0 @@ -package gui; - -import java.awt.Color; -import java.awt.EventQueue; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.geom.AffineTransform; -import java.util.Observable; -import java.util.Observer; -import java.util.Timer; -import java.util.TimerTask; - -import javax.swing.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 int m_targetPositionX = 150; - private volatile int m_targetPositionY = 100; - - private final Robot robot; - - private static final double maxVelocity = 0.1; - private static final double maxAngularVelocity = 0.001; - - public GameVisualizer(Robot robot) - { - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - onRedrawEvent(); - } - }, 0, 50); - m_timer.schedule(new TimerTask() - { - @Override - public void run() - { - robot.update(m_targetPositionX, m_targetPositionY); - } - }, 0, 10); - addMouseListener(new MouseAdapter() - { - @Override - public void mouseClicked(MouseEvent e) - { - setTargetPosition(e.getPoint()); - repaint(); - } - }); - this.robot = robot; - robot.addObserver(this); - - setDoubleBuffered(true); - } - - protected void setTargetPosition(Point p) - { - double rate = 3f/2f; - m_targetPositionX = (int) (p.x * rate); - m_targetPositionY = (int) (p.y * rate); - } - - protected void onRedrawEvent() - { - EventQueue.invokeLater(this::repaint); - } - public void stopTimer(){ - m_timer.cancel(); - } - - private static int round(double value) - { - return (int)(value + 0.5); - } - - @Override - public void paint(Graphics g) - { - super.paint(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) - { - g.fillOval(centerX - diam1 / 2, centerY - diam2 / 2, diam1, 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); - g.setTransform(t); - g.setColor(Color.MAGENTA); - fillOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.BLACK); - drawOval(g, robotCenterX, robotCenterY, 30, 10); - g.setColor(Color.WHITE); - fillOval(g, robotCenterX + 10, robotCenterY, 5, 5); - 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); - g.setTransform(t); - g.setColor(Color.GREEN); - fillOval(g, x, y, 5, 5); - g.setColor(Color.BLACK); - drawOval(g, x, y, 5, 5); - } - - @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(); - } - } -} diff --git a/robots/src/gui/GameWindow.java b/robots/src/gui/GameWindow.java deleted file mode 100644 index 4eb8e2a7c..000000000 --- a/robots/src/gui/GameWindow.java +++ /dev/null @@ -1,25 +0,0 @@ -package gui; - -import java.awt.BorderLayout; - -import javax.swing.JPanel; - -public class GameWindow extends AbstractWindowState -{ - private final GameVisualizer m_visualizer; - public GameWindow(String title, Robot robot) - { - super(title, true, true, true, true); - 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() { - super.dispose(); - m_visualizer.stopTimer(); - } -} diff --git a/robots/src/gui/Robot.java b/robots/src/gui/Robot.java deleted file mode 100644 index 069112857..000000000 --- a/robots/src/gui/Robot.java +++ /dev/null @@ -1,119 +0,0 @@ -package gui; - -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 log() { - return String.format( - "Position: (%f, %f) | Direction: %f", - m_robotPositionX, m_robotPositionY, m_robotDirection - ); - } - - 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 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 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 applyLimits(double value, double min, double max) - { - if (value < min) - return min; - return Math.min(value, max); - } - - public void update(double m_targetPositionX, double m_targetPositionY) { - double distance = distance(m_targetPositionX, m_targetPositionY, m_robotPositionX, m_robotPositionY); - - if (distance < 0.5) return; - - 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(maxVelocity, angularVelocity, 10); - - setChanged(); - notifyObservers("robot moved"); - clearChanged(); - } - - 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; - } -} diff --git a/robots/src/gui/RobotInfo.java b/robots/src/gui/RobotInfo.java deleted file mode 100644 index 7dac11b2d..000000000 --- a/robots/src/gui/RobotInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package gui; - -import java.awt.*; -import java.util.Observable; -import java.util.Observer; -import javax.swing.JLabel; - -public class RobotInfo extends AbstractWindowState implements Observer { - private final Robot robot; - private final JLabel label; - - - public RobotInfo(Robot robot) { - super(); - this.robot = robot; - this.label = new JLabel(); - - robot.addObserver(this); - setResizable(true); - setClosable(true); - setMaximizable(true); - setIconifiable(true); - - getContentPane().add(label, BorderLayout.CENTER); - pack(); - } - - @Override - public void update(Observable o, Object arg) { - label.setText(robot.log()); - } -}