Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>robots</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>

</dependencies>
</project>
294 changes: 145 additions & 149 deletions robots/src/gui/GameVisualizer.java
Original file line number Diff line number Diff line change
@@ -1,210 +1,206 @@
package gui;
package src.gui;

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.*;
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.*;

import javax.swing.JPanel;
public class GameVisualizer extends JPanel {

private static final double MAX_VELOCITY = 0.1;
private static final double MAX_ANGULAR_VELOCITY = 0.001;

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 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()
{

public GameVisualizer() {
initializeTimer();
addMouseListener(new MouseClickListener());
setDoubleBuffered(true);
setPreferredSize(new Dimension(400, 400));
setSize(500, 500);
}
public double getM_robotPositionX(){
return m_robotPositionX;
}

public double getM_robotPositionY() {
return m_robotPositionY;
}

private void initializeTimer() {
Timer timer = new Timer("events generator", true);
timer.schedule(new TimerTask() {
@Override
public void run()
{
public void run() {
onRedrawEvent();
}
}, 0, 50);
m_timer.schedule(new TimerTask()
{

timer.schedule(new TimerTask() {
@Override
public void run()
{
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;
private class MouseClickListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
setTargetPosition(e.getPoint());
repaint();
}
}

public void setTargetPosition(Point point) {
System.out.println("Click at: (" + point.x + ", " + point.y + ")");
m_targetPositionX = point.x;
m_targetPositionY = point.y;
System.out.println("Target set at: (" + m_targetPositionX + ", " + m_targetPositionY + ")");
repaint();
}
protected void onRedrawEvent()
{


private void onRedrawEvent() {
EventQueue.invokeLater(this::repaint);
}

private static double distance(double x1, double y1, double x2, double y2)
{
public void onModelUpdateEvent() {
double distanceToTarget = calculateDistance(m_targetPositionX, m_targetPositionY, m_robotPositionX, m_robotPositionY);
if (distanceToTarget < 0.5) {
return;
}

double angleToTarget = calculateAngleToTarget(m_robotPositionX, m_robotPositionY, m_targetPositionX, m_targetPositionY);
double angularVelocity = calculateAngularVelocity(angleToTarget, m_robotDirection);

moveRobot(MAX_VELOCITY, angularVelocity, 10);
}

private double calculateDistance(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)
{

private double calculateAngleToTarget(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;
return normalizeAngle(Math.atan2(diffY, diffX));
}

private double calculateAngularVelocity(double angleToTarget, double currentDirection) {
if (angleToTarget > currentDirection) {
return MAX_ANGULAR_VELOCITY;
} else if (angleToTarget < currentDirection) {
return -MAX_ANGULAR_VELOCITY;
}

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))
{
return 0;
}

private void moveRobot(double velocity, double angularVelocity, double duration) {
velocity = applyLimits(velocity, 0, MAX_VELOCITY);
angularVelocity = applyLimits(angularVelocity, -MAX_ANGULAR_VELOCITY, MAX_ANGULAR_VELOCITY);

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))
{

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);
}

int width = getWidth();
int height = getHeight();

if (newX < 0) {
newX = width + newX;
} else if (newX > width) {
newX = newX - width;
}

if (newY < 0) {
newY = height + newY;
} else if (newY > height) {
newY = newY - height;
}

m_robotPositionX = newX;
m_robotPositionY = newY;
double newDirection = asNormalizedRadians(m_robotDirection + angularVelocity * duration);
m_robotDirection = newDirection;
m_robotDirection = normalizeAngle(m_robotDirection + angularVelocity * duration);
}

private double applyLimits(double value, double min, double max) {
return Math.max(min, Math.min(max, value));
}

private static double asNormalizedRadians(double angle)
{
while (angle < 0)
{
angle += 2*Math.PI;
private double normalizeAngle(double angle) {
while (angle < 0) {
angle += 2 * Math.PI;
}
while (angle >= 2*Math.PI)
{
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);

private 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)
{
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);

private void drawRobot(Graphics2D g, int x, int y, double direction) {
AffineTransform transform = AffineTransform.getRotateInstance(direction, x, y);
g.setTransform(transform);

g.setColor(Color.MAGENTA);
fillOval(g, robotCenterX, robotCenterY, 30, 10);
fillOval(g, x, y, 30, 10);

g.setColor(Color.BLACK);
drawOval(g, robotCenterX, robotCenterY, 30, 10);
drawOval(g, x, y, 30, 10);

g.setColor(Color.WHITE);
fillOval(g, robotCenterX + 10, robotCenterY, 5, 5);
fillOval(g, x + 10, y, 5, 5);

g.setColor(Color.BLACK);
drawOval(g, robotCenterX + 10, robotCenterY, 5, 5);
drawOval(g, x + 10, y, 5, 5);
}
private void drawTarget(Graphics2D g, int x, int y)
{
AffineTransform t = AffineTransform.getRotateInstance(0, 0, 0);
g.setTransform(t);

private void drawTarget(Graphics2D g, int x, int y) {
AffineTransform transform = AffineTransform.getRotateInstance(0, 0, 0);
g.setTransform(transform);

g.setColor(Color.GREEN);
fillOval(g, x, y, 5, 5);

g.setColor(Color.BLACK);
drawOval(g, x, y, 5, 5);
}
}

private void fillOval(Graphics g, int centerX, int centerY, int width, int height) {
g.fillOval(centerX - width / 2, centerY - height / 2, width, height);
}

private void drawOval(Graphics g, int centerX, int centerY, int width, int height) {
g.drawOval(centerX - width / 2, centerY - height / 2, width, height);
}
}
Loading