I have a java application which simulates a robots world. It is basically a matrix in a size the user picks and it is supposed to draw the robots world as a matrix with some random robots in it (represented as circles).
In my application I try to choose a random robot and move it 30 steps in the world – meaning, move the circle 30 cells in the matrix.
For this purpose Im trying to use the JPanel feature repaint()
which doesn’t work for me very well. The call to repaint doesn’t fire the method DrawComponent
as I expected. The result Im looking for is to be able to see each move the robot makes in on the JFrame.
If someone could point me to the issue and in general give me some comments regarding my code I’d be very thankful. I add alot of code but its not as big as it looks, its actually a tiny application:
IllegalPositionException.java:
public class IllegalPositionException extends Exception{ }
Position.java:
public class Position { private int x; private int y; public Position(int x, int y){ this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public void goUp(){ y++; } public void goDown(){ y--; } public void goRight(){ x++; } public void goLeft(){ x--; } @Override public String toString() { return "(" + x + "," + y + ")"; } }
Robot.java:
public class Robot { public static final int DIRECTION_LEFT = 1; public static final int DIRECTION_UP = DIRECTION_LEFT + 1; public static final int DIRECTION_RIGHT = DIRECTION_UP + 1; public static final int DIRECTION_DOWN = DIRECTION_RIGHT + 1; public static final int NUMBER_OF_DIRECTIONS = 4; private int robotId; private Position robotPosition; private int robotDirection; public Robot(int robotId, Position robotPosition, int robotDirection) { this.robotId = robotId; this.robotPosition = robotPosition; this.robotDirection = robotDirection; } // Copy constructor public Robot(Robot other) { this.robotId = other.getRobotId(); this.robotDirection = other.getRobotDirection(); Position robotPosition = other.getRobotPosition(); this.robotPosition = new Position(robotPosition.getX(), robotPosition.getY()); } public int getRobotId() { return robotId; } public Position getRobotPosition() { return robotPosition; } public int getRobotDirection() { return robotDirection; } public void move() { if (robotDirection == DIRECTION_DOWN){ robotPosition.goDown(); } else if (robotDirection == DIRECTION_UP){ robotPosition.goUp(); } else if (robotDirection == DIRECTION_RIGHT){ robotPosition.goRight(); } else if (robotDirection == DIRECTION_LEFT){ robotPosition.goLeft(); } } public void turnRight() { robotDirection = (++robotDirection) % 4; } public void turnLeft() { robotDirection = (--robotDirection + 4) % 4; } }
RobotsWorld.java:
import java.util.Random; public class RobotsWorld { private int worldSize; Random random = new Random(); private Robot[][] robots; public RobotsWorld(int worldSize) { this.worldSize = worldSize; this.robots = new Robot[worldSize][worldSize]; } public void addRobot(Position p) throws IllegalPositionException { // Position validations if (isPositionOutsideOfBoundries(p) || robots[p.getX()][p.getY()] != null) { throw new IllegalPositionException(); } // Generates a random Id for the robot int robotId = random.nextInt(); // Generates random direction for the robot int robotDirection = random.nextInt(Robot.NUMBER_OF_DIRECTIONS) + 1; // Creates the new robot robots[p.getX()][p.getY()] = new Robot(robotId, p, robotDirection); } public Robot getRobot(Position p) { // Position validations if (isPositionOutsideOfBoundries(p) || robots[p.getX()][p.getY()] == null) { return null; } return robots[p.getX()][p.getY()]; } // Removes a robot from the world. public Robot removeRobot(Position p){ // Getting the robot Robot robotToRemove = getRobot(p); if (p == null) return null; robots[p.getX()][p.getY()] = null; return robotToRemove; } // Moves a robot in the matrix if possible public void moveRobot(Position p) throws IllegalPositionException { // Gets the robot in the wanted position Robot targetRobot = getRobot(p); if (targetRobot == null) { throw new IllegalPositionException(); } // Creates a new copy robot and moves it Robot newRobot = new Robot(targetRobot); newRobot.move(); // Getting the new position Position newPosition = newRobot.getRobotPosition(); // Checking if new position is out of boundaries if (isPositionOutsideOfBoundries(newPosition) || robots[newPosition.getX()][newPosition.getY()] != null) { throw new IllegalPositionException(); } // If movement of the copy robot was successful, remove the old robot from it's current position and move it removeRobot(p); targetRobot.move(); // Sets the matrix robots[newPosition.getX()][newPosition.getY()] = targetRobot; System.out.println("After Move: "); printAllRobots(); } // Checking if a position is a valid position on the board private boolean isPositionOutsideOfBoundries(Position p){ return (p.getY() >= worldSize || p.getX() >= worldSize || p.getY() < 0 || p.getX() < 0); } public void printAllRobots() { for (int i = 0; i < worldSize; i++){ for (int j = 0; j < worldSize; j++){ if (robots[i][j] != null){ System.out.println(i + "," + j); } } } } }
RobotsWorldPanel.java:
import javax.swing.*; import java.awt.*; import java.util.*; public class RobotsWorldPanel extends JPanel { private static final int ROBOTS_NUMBER = 5; private static final int NUMBER_OF_MOVES_TO_MOVE = 30; private RobotsWorld robotsWorld; private Random random = new Random(); // Array of positions of the robots private static Position[] robotsPositions = new Position[ROBOTS_NUMBER]; // Hashmap of the robotsId<->color private static Map<Integer, Color> robotsColors = new HashMap<>(); public RobotsWorldPanel(RobotsWorld robotsWorld) { setSize(RobotsWorldSimulator.CELL_WIDTH * RobotsWorldSimulator.robotsWorldSize, RobotsWorldSimulator.CELL_HEIGHT * RobotsWorldSimulator.robotsWorldSize ); this.robotsWorld = robotsWorld; // Initialize random robots in the world initializeRobots(); setLayout(new GridLayout(RobotsWorldSimulator.robotsWorldSize, RobotsWorldSimulator.robotsWorldSize )); setVisible(true); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); drawGameBoard(g); drawRobots(g); moveRandomRobot(); } private void drawGameBoard(Graphics g) { for (int i = 0; i <= RobotsWorldSimulator.robotsWorldSize; i++) { g.drawLine(0, i * RobotsWorldSimulator.CELL_HEIGHT, RobotsWorldSimulator.CELL_WIDTH * RobotsWorldSimulator.robotsWorldSize, i * RobotsWorldSimulator.CELL_HEIGHT); } for (int i = 0; i <= RobotsWorldSimulator.robotsWorldSize; i++) { g.drawLine(i * RobotsWorldSimulator.CELL_WIDTH, 0, i * RobotsWorldSimulator.CELL_WIDTH, RobotsWorldSimulator.CELL_HEIGHT * RobotsWorldSimulator.robotsWorldSize); } } private void drawRobots(Graphics g) { for (int robotIndex = 0; robotIndex < ROBOTS_NUMBER; robotIndex++){ Position robotPosition = robotsPositions[robotIndex]; Robot targetRobot = robotsWorld.getRobot(robotPosition); Color robotColor = robotsColors.get(targetRobot.getRobotId()); drawRobot(g, robotPosition.getX(), robotPosition.getY(), robotColor, targetRobot.getRobotDirection()); } } private void drawRobot(Graphics g, int row, int col, Color robotColor, int robotDirection) { g.setColor(robotColor); g.fillOval(row * RobotsWorldSimulator.CELL_WIDTH, col * RobotsWorldSimulator.CELL_HEIGHT, RobotsWorldSimulator.CELL_WIDTH, RobotsWorldSimulator.CELL_HEIGHT); String robotDirectionSign = ""; if (robotDirection == Robot.DIRECTION_DOWN){ robotDirectionSign = "v"; } else if (robotDirection == Robot.DIRECTION_RIGHT){ robotDirectionSign = ">"; } else if (robotDirection == Robot.DIRECTION_UP){ robotDirectionSign = "^"; } else if (robotDirection == Robot.DIRECTION_LEFT){ robotDirectionSign = "<"; } g.setColor(Color.WHITE); g.drawString(robotDirectionSign, (row * RobotsWorldSimulator.CELL_WIDTH) + RobotsWorldSimulator.CELL_WIDTH / 2, (col * RobotsWorldSimulator.CELL_HEIGHT) + RobotsWorldSimulator.CELL_HEIGHT / 2); } // Generating random color for each robot private void initializeRobots() { // Inserting new robots to the world for (int robotIndex = 0; robotIndex < ROBOTS_NUMBER; robotIndex++) { // Set random position int x = random.nextInt(RobotsWorldSimulator.robotsWorldSize); int y = random.nextInt(RobotsWorldSimulator.robotsWorldSize); Position robotPosition = new Position(x,y); robotsPositions[robotIndex] = robotPosition; try { robotsWorld.addRobot(robotPosition); } catch (IllegalPositionException ex){ return; } Robot addedRobot = robotsWorld.getRobot(robotPosition); // Adding the robot to the colors map robotsColors.put(addedRobot.getRobotId(), new Color(random.nextFloat(), random.nextFloat(), random.nextFloat())); } } // Moves a random robot a specified number of moves private void moveRandomRobot() { int randomRobot = random.nextInt(ROBOTS_NUMBER); Position robotPosition = robotsPositions[randomRobot]; int possibleWaysToMove = Robot.NUMBER_OF_DIRECTIONS; for (int moveNumber = 0; moveNumber < NUMBER_OF_MOVES_TO_MOVE && possibleWaysToMove > 0; moveNumber++){ try{ robotsWorld.moveRobot(robotPosition); repaint(); // 1 second sleep for graphics purposes. // try { // Thread.sleep(10000); // } catch (InterruptedException e) { // e.printStackTrace(); // } possibleWaysToMove = Robot.NUMBER_OF_DIRECTIONS; } catch (IllegalPositionException ex) { // Turns the robot right in case of failure. Robot targetRobot = robotsWorld.getRobot(robotPosition); targetRobot.turnRight(); possibleWaysToMove--; } } if (possibleWaysToMove == 0) { JOptionPane.showMessageDialog( this, "The robot in position" + robotPosition + "has no where left to move!"); return; } } }
RobotsWorldSimulator:
import javax.swing.*; public class RobotsWorldSimulator { public static int robotsWorldSize; public static int CELL_HEIGHT = 20; public static int CELL_WIDTH = 20; private static RobotsWorld robotsWorld; private static JFrame mainFrame; public static void main(String[] args) { inputWorldSize(); robotsWorld = new RobotsWorld(robotsWorldSize); mainFrame = new JFrame("Robots world!"); // Creates a robots world panel JPanel robotsWorldPanel = new RobotsWorldPanel(robotsWorld); mainFrame.setSize(robotsWorldPanel.getWidth() + CELL_WIDTH * 1, robotsWorldPanel.getHeight() + CELL_HEIGHT * 2); mainFrame.add(robotsWorldPanel); mainFrame.setVisible(true); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } // Gets the world input size by the user (1-99) private static void inputWorldSize() { boolean validWorldSize = false; while (!validWorldSize){ // prompt the user to enter their wanted size String worldSizeString = JOptionPane.showInputDialog(mainFrame, "Enter the robot's world size (Between 1 to 99)"); if (worldSizeString == null) break; try{ robotsWorldSize = Integer.parseInt(worldSizeString); } catch (Exception ex){ continue; } validWorldSize = robotsWorldSize > 0 && robotsWorldSize < 100; } // Creates a robot world according to the size robotsWorld = new RobotsWorld(robotsWorldSize); } }