I am trying to create a game. In this game, the UI shows multiple paths(JPanels) with obstacles (some sort of JComponent) moving down the paths. The user (Player) must move left and right or switch paths to avoid the obstacles. This game is similar to google Pony Express.
https://www.google.com/doodles/155th-anniversary-of-the-pony-express
For now, because I am in the developing stages, I only have one path. I have a Player class that extends JComponent and overrides the paint Component method and draws a blue square. I have a Obstacle Component Class that also extends JComponent and overrides the paint Component method and draws a black circle.
In my Board class, I create a JPanel called theGame and put one path and inside of that path, one obstacle component and one player. This JPanel is put into a JFrame.
The player is free to move using a key listener. I will keep the obstacle component in one place to make debugging easier. This is not the main problem. The problem is that I want to end the game when the player intersects the obstacle. I create skeleton rectangles that resembles the body of the component. So for example the rectangle for the blue square is just the square and for the circle, a rectangle that covers the most area inside of it. So I call the intersects method on the two rectangles and if true, I game over. However, the intersect method does not work. The intersects method returns true even when the player and obstacle are not visibly touching. (No, there is no problem with misproper refreshing or anything like that). How do I intersect those two objects? Code will be provided if the answerer needs it.
Observation: I am not sure but I believe that the Graphics objects used to draw the player and obstacle are different. To test this hypothesis, I drew a green square in each of the paintComponent methods like this:
public void paintComponent(Graphics g)
{
//code to create the blue square
g2 = (Graphics2D) g;
rect = new Rectangle(x,y,w,h);
g2.setColor(Color.BLUE);
g2.fill(rect);
g2.draw(rect);
//code to see the green rectangle
Rectangle bill = new Rectangle(100,100,w,h);
g2.setColor(Color.GREEN);
g2.fill(bill);
g2.draw(bill);
}
The reasoning was that if I paint a green rectangle with seemingly same coordinates using the graphics objects of player and obstacle, they should end up in the same place on the JPanel. Instead, the green Rectangle objects showed up in two different places. This lead me to believe that the graphic objects use different coordinate systems. If so, how to use one universal coordinate system for multiple graphic objects?
MCVE: I could not make the classes any smaller because the code was not working if I did that. Player Class:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.awt.event.*;
public class Player extends JComponent
{
private int x;
private int y;
private int h = 20;
private int w = 20;
private Rectangle rect;
private int dx=5;
private int dy=5;
private Graphics2D g2;
public Player(int x, int y)
{
this.x = x;
this.y = y;
rect= new Rectangle(x,y,w,h);
}
public void assignGraphics(Graphics g)
{
g2 = (Graphics2D)g;
}
public Player()
{
x=0;
y=0;
}
public void paintComponent(Graphics g)
{
g2 = (Graphics2D) g;
rect = new Rectangle(x,y,w,h);
g2.setColor(Color.BLUE);
g2.fill(rect);
g2.draw(rect);
Rectangle test = new Rectangle(100,100,w,h);
g2.setColor(Color.GREEN);
g2.fill(test);
g2.draw(test);
}
public Rectangle getRectComp()
{
return rect;
}
public void setMove(int a, int b)
{
x=x+a;
y=y+b;
repaint();
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
}
Obstacle Component:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import java.io.IOException;
public class ObstacleComponent extends JComponent
{
private int x;
private int y;
public Ellipse2D.Double elli;
private int dx=5;
private int dy=5;
private int h;
private int w;
private Graphics2D g2;
public ObstacleComponent(int x, int y, int h, int w)
{
this.x = x;
this.y = y;
this.h = h;
this.w = w;
}
public void assignGraphics(Graphics g)
{
g2 = (Graphics2D)g;
}
public ObstacleComponent()
{
x=0;
y=0;
}
public void paintComponent(Graphics g) // method declaration- a method which overrides the paintComponent method from the JComponent class.
// This method takes in an explicit parameter of a Graphics object
{
g2 = (Graphics2D) g;
elli = new Ellipse2D.Double(x,y,w,h);
g2.setColor(Color.BLACK);
g2.fill(elli);
g2.draw(elli);
Rectangle test= new Rectangle(0,0,w,h);
g2.setColor(Color.GREEN);
g2.fill(test);
g2.draw(test);
}
public void setMove(int a, int b)
{
x=x+a; // sets the dx variable to the value of parameter variable a
y=y+b;
repaint();
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public Rectangle getRectComp()
{
return new Rectangle(x,y,20,20);
}
}
Path:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;
import javax.swing.plaf.TableUI;
import javax.swing.table.TableColumn;
import java.awt.event.*;
import javax.swing.border.EtchedBorder;
public class Path extends JPanel implements ActionListener
{
public ArrayList <ObstacleComponent> badGuys;
private int interval;
private int xDimension = 1000;
private int yDimension = 600;
private Graphics2D pen;
public Path(int rate)
{
badGuys = new ArrayList<ObstacleComponent>();
setPreferredSize(new Dimension(xDimension, yDimension));
setBorder(new EtchedBorder());
setLayout(new GridLayout(1,1));
}
public Graphics2D getG()
{
return pen;
}
public void actionPerformed(ActionEvent av)
{
if(interval%10==0)
{
badGuys.add(new ObstacleComponent(200,10,20,20));
add(badGuys.get(badGuys.size()-1));
badGuys.get(badGuys.size()-1).assignGraphics(pen);
}
for(int b = 0;b<badGuys.size();b++)
{
badGuys.get(b).setMove(-5,0);
}
removeObstaclesOffTheScreen();
repaint();
interval++;
}
public void removeObstaclesOffTheScreen()
{
for(int b = 0;b<badGuys.size();b++)
{
if(badGuys.get(b).getX()<0)
{
remove(badGuys.remove(b));
}
}
}
}
Board:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.*;
import javax.swing.plaf.TableUI;
import javax.swing.table.TableColumn;
import java.awt.event.*;
import javax.swing.border.EtchedBorder;
public class Board implements ActionListener {
// instance variables - replace the example below with your own
private ArrayList<Path> paths;
public JPanel theGame;
private int interval;
private int currentPlayerPath;
public Player player;
private int pathNumber = 1;//4;
private int levelTime;
private int levelRate;
private boolean notGameOver;
private int removeThisCounter=0;
private int timeToChangeRate;
private Random gen;
private int levelRange = 20;
public Board()
{
theGame = new JPanel();
setLayout(pathNumber);
player = new Player();
levelRate = 0;
paths = new ArrayList<Path>();
gen = new Random();
for(int a = 0;a<pathNumber;a++)
{
paths.add(new Path(getRandomRate()));
}
for(int a = 0;a<pathNumber;a++)
{
theGame.add(paths.get(a));
}
currentPlayerPath=0;
setCurrentPlayerPath();
}
public JPanel returnTheGamePanel()
{
return theGame;
}
public void setLayout(int paths)
{
theGame.setLayout(new GridLayout(pathNumber, paths));
}
public void setCurrentPlayerPath()
{
paths.get(currentPlayerPath).add(player);
player.assignGraphics(paths.get(currentPlayerPath).getG());
}
public boolean hit()
{
Path currentPath = paths.get(currentPlayerPath);
for(int a = 0;a<currentPath.badGuys.size();a++)
{
Object b = player.getRectComp();
Object c = currentPath.badGuys.get(a).getRectComp();
if (((Rectangle)b).intersects((Rectangle)c))
{
return true;
}
else
{
System.out.println("player: " + player.getX() + " " + player.getY());
System.out.println("badguy: " + currentPath.badGuys.get(a).getX() + " " + currentPath.badGuys.get(a).getY());
}
}
return false;
}
public void actionPerformed(ActionEvent av)
{
for(int a = 0;a<pathNumber;a++)
{
paths.get(a).actionPerformed(av);
}
player.repaint();
theGame.revalidate();
theGame.repaint();
}
public void gameOver()
{
notGameOver=!notGameOver;
}
public boolean isGameOver()
{
return notGameOver;
}
}
Engine:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.sound.sampled.*;
import java.io.*;
import java.awt.geom.*;
public class Engine {
public static void main (String[] args) {
JOptionPane.showMessageDialog(null, "Press arrow key to move.");
final JFrame display = new JFrame();
display.setSize(1000, 600);
display.setTitle("Code does not work");
display.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
final Board b = new Board();
class TimedAction implements ActionListener
{
private int removeThisCounter=0;
public void actionPerformed(ActionEvent av)
{
b.actionPerformed(av);
if(b.hit())
{
System.out.println("HIT!!"+removeThisCounter);
removeThisCounter++;
}
display.revalidate();
display.repaint();
}
}
class PlayerAction implements KeyListener
{
public void keyPressed (KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode==KeyEvent.VK_LEFT)
{
b.player.setMove(-7, 0);
}
if(keyCode==KeyEvent.VK_RIGHT)
{
b.player.setMove(7, 0);
}
if(keyCode==KeyEvent.VK_UP)
{
b.player.setMove(0,-7);
}
if(keyCode==KeyEvent.VK_DOWN)
{
b.player.setMove(0,7);
}
else
{
b.player.setMove(0,0);
}
}
public void keyReleased(KeyEvent e) {} //method delcaration for empty methods needed to override the abstract methods of the KeyListener interface
public void keyTyped(KeyEvent e) {}
}
Timer theTime = new Timer(1000, new TimedAction());
theTime.start();
JPanel masterPanel = new JPanel();
display.addKeyListener(new PlayerAction());
masterPanel.add(b.returnTheGamePanel());
display.add(masterPanel);
display.setVisible(true);
}
}