Intersection of Two Rectangles with paintComponent - java

I am writing a program that allows a user to paint rectangles onto a JLabel, and show the intersection and union of these rectangles. I have setup the GUI for the class but am struggling to find a way to integrate the intersection and union methods from the rectangle class. I know these methods work when used separately from the GUI.
When I try to run the program I keep getting an IndexOutOfBoundsException and the drawn rectangles are cleared from the gui. The intersections of each rectangle should show up in a different color on the JLabel. I tried to debug the program and for some reason when I create two rectangles and store them in my array list many many rectangle objects of the same characteristics are being created.
For the union method, a new rectangle should be create that contains all of the rectangles on the inside.
RectangleFrame1:
public class RectangleFrame1 extends JFrame implements ActionListener
{
JPanel buttonPanel;
JButton saveImage;
JButton clearImage;
JCheckBox intersections;
JCheckBox union;
RectangleLabel drawingArea;
boolean intersect = false;
boolean uni = false;
public RectangleFrame1()
{
super();
setTitle("Rectangles");
setSize(600,600);
setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setBorder(BorderFactory.createLineBorder(Color.black));
this.add(buttonPanel, BorderLayout.SOUTH);
intersections = new JCheckBox("Draw Intersections");
buttonPanel.add(intersections);
intersections.addActionListener(this);
intersections.setActionCommand("Intersections");
union = new JCheckBox("Draw Union");
buttonPanel.add(union);
union.addActionListener(this);
union.setActionCommand("Union");
saveImage = new JButton("Save Image");
saveImage.setMargin(new Insets(0,0,0,0));
buttonPanel.add(saveImage);
saveImage.addActionListener(this);
saveImage.setActionCommand("Save Image");
clearImage = new JButton("Clear Image");
clearImage.setMargin(new Insets(0,0,0,0));
buttonPanel.add(clearImage);
clearImage.addActionListener(this);
clearImage.setActionCommand("Clear Image");
drawingArea = new RectangleLabel();
drawingArea.setBorder(BorderFactory.createLineBorder(Color.blue));
this.add(drawingArea, BorderLayout.CENTER);
drawingArea.addMouseListener((MouseListener) drawingArea);
drawingArea.addMouseMotionListener((MouseMotionListener) drawingArea);
}
#Override
public void actionPerformed(ActionEvent arg0)
{
switch(arg0.getActionCommand())
{
case "Intersections":
if(intersections.isSelected())
{
intersect = true;
}
else
{
intersect = false;
}
case "Union":
if(union.isSelected())
{
uni = true;
}
else
{
uni = false;
}
case "Clear Image": drawingArea.clearImage();
case "Save Image": drawingArea.saveImage();
}
}
class RectangleLabel extends JLabel implements MouseListener, MouseMotionListener
{
Rectangle rectangle = null;
int x, y, x2, y2;
ArrayList<Rectangle> a = new ArrayList();
int counter;
public RectangleLabel()
{
super();
}
#Override
public void mousePressed(MouseEvent arg0)
{
x = arg0.getX();
y = arg0.getY();
rectangle = new Rectangle(x, y, 0, 0);
}
#Override
public void mouseDragged(MouseEvent arg0)
{
// TODO Auto-generated method stub
x2 = arg0.getX();
y2 = arg0.getY();
if(rectangle.getX() > x2)
{
rectangle.setWidth(x-x2);
}
if(x2 > rectangle.getX())
{
rectangle.setWidth(x2-x);
}
if(y > y2)
{
rectangle.setHeight(y-y2);
}
if(y2 > y)
{
rectangle.setHeight(y2-y);
}
a.add(rectangle);
counter++;
repaint();
}
#Override
public void mouseReleased(MouseEvent arg0)
{
repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(rectangle != null)
{
for(int i = 0; i < a.size(); i++)
{
float thickness = 2;
((Graphics2D) g).setStroke(new BasicStroke(thickness));
g.setColor(Color.BLUE);
g.drawRect(a.get(i).getX(), a.get(i).getY(), a.get(i).getWidth(), a.get(i).getHeight());
g.setColor(Color.gray);
g.fillRect(a.get(i).getX(), a.get(i).getY(), a.get(i).getWidth(), a.get(i).getHeight());
}
}
if(intersect == true && counter > 0)
{
for(int h = 0; h < counter-1; h++)
{
for(int j = 1; j < counter; j++)
{ if(a.get(h).overlaps(a.get(j)))
{
Rectangle rect = a.get(h).intersect(a.get(j));
g.setColor(Color.RED);
g.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}
}
}
if(uni == true && counter > 0)
{
for(int h = 0; h < counter - 1; h++)
{
for(int j = 1; j < counter; j++)
{
Rectangle rect = a.get(h).union(a.get(j));
g.setColor(Color.WHITE);
g.drawRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}
}
}
public void saveImage()
{
BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D aaaaa = image.createGraphics();
aaaaa.setBackground(Color.WHITE);
aaaaa.clearRect(0, 0, this.getWidth(), this.getHeight());
this.paintAll(aaaaa);
try
{
File output = new File("rectangle.png");
ImageIO.write(image, "Rectangles", output);
}
catch(IOException ie)
{
}
}
public void clearImage()
{
a.clear();
repaint();
}
}
}
Rectangle:
public class Rectangle
{
private int x,y,width,height;
public Rectangle(int x,int y,int width,int height)
{
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public Rectangle(Rectangle a)
{
this.x = a.x;
this.y = a.y;
this.width = a.width;
this.height = a.height;
}
public String toString()
{
return "Start: ("+x+","+y+"), Width: "+width+", Height: "+height+"\n";
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public void setX(int x)
{
this.x = x;
}
public void setY(int y)
{
this.y = y;
}
public void setWidth(int width)
{
this.width = width;
}
public void setHeight(int height)
{
this.height = height;
}
public int area()
{
return width*height;
}
public boolean overlaps(Rectangle a)
{
if ((x>a.x+a.width) || (a.x>x+width) || (y>a.y+a.height) || (a.y>y+height))
{
return false;
}
return true;
}
public Rectangle intersect(Rectangle a)
{
if (!overlaps(a))
return null;
int left,right,top,bottom;
if (x<a.x)
left = a.x;
else
left = x;
if (y<a.y)
bottom = a.y;
else
bottom = y;
if ((x+width)<(a.x+a.width))
right = x+width;
else
right = a.x+a.width;
if ((y+height)<(a.y+a.height))
top = y+height;
else
top = a.y+a.height;
return new Rectangle(left,bottom,right-left,top-bottom);
}
public Rectangle union(Rectangle a)
{
int left,right,top,bottom;
if (x<a.x)
left = x;
else
left = a.x;
if (y<a.y)
bottom = y;
else
bottom = a.y;
if ((x+width)<(a.x+a.width))
right = a.x+a.width;
else
right = x+width;
if ((y+height)<(a.y+a.height))
top = a.y+a.height;
else
top = y+height;
return new Rectangle(left,bottom,right-left,top-bottom);
}
}

There are a number of problems...
You're mouseDragged event handler is adding the same Rectangle to the a ArrayList, over and over again, increasing the counter value along with it.
This is not required. All you need to do is add the Rectangle on the mousePressed event. When mouseReleased is called, you could evaluate the Rectangle to check if the size is greater than 0x0 and remove it if it's not (ie remove any Rectangle whose size is 0x0)
Don't rely on the counter variable, it's too easy for the value to become misaligned with the size of the a List. Instead, rely on a.size instead.
The switch statement in your ActionListener is evaluating the matching case, but also all the following cases below it. This is a feature of switch. If you don't want to evaluate the following cases, you need to add a break at the end of each case (or where ever you want to "break" the processing).
For example, when you click Draw Intersections, it is also evaluating Union, Clear Image and Save Image cases...
You could try using something like...
switch (arg0.getActionCommand()) {
case "Intersections":
intersect = intersections.isSelected();
break;
case "Union":
uni = union.isSelected();
break;
case "Clear Image":
drawingArea.clearImage();
break;
case "Save Image":
drawingArea.saveImage();
break;
}
instead...
Logic Errors in Painting Code...
There's also a logic area with your intersect paint code, where it is comparing a rectangle with itself, which ends up painting the whole rectangle.
Instead of
if (a.get(h).overlaps(a.get(j))) {
You might consider using
if (!a.get(h).equals(a.get(j)) && a.get(h).overlaps(a.get(j))) {
This is possibly occurring in you union painting logic as well, but I didn't really check that
Works fine for me...
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RectangleFrame1 extends JFrame implements ActionListener {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
RectangleFrame1 frame = new RectangleFrame1();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
JPanel buttonPanel;
JButton saveImage;
JButton clearImage;
JCheckBox intersections;
JCheckBox union;
RectangleLabel drawingArea;
boolean intersect = false;
boolean uni = false;
public RectangleFrame1() {
super();
setTitle("Rectangles");
setSize(600, 600);
// setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setBorder(BorderFactory.createLineBorder(Color.black));
this.add(buttonPanel, BorderLayout.SOUTH);
intersections = new JCheckBox("Draw Intersections");
buttonPanel.add(intersections);
intersections.addActionListener(this);
intersections.setActionCommand("Intersections");
union = new JCheckBox("Draw Union");
buttonPanel.add(union);
union.addActionListener(this);
union.setActionCommand("Union");
saveImage = new JButton("Save Image");
saveImage.setMargin(new Insets(0, 0, 0, 0));
buttonPanel.add(saveImage);
saveImage.addActionListener(this);
saveImage.setActionCommand("Save Image");
clearImage = new JButton("Clear Image");
clearImage.setMargin(new Insets(0, 0, 0, 0));
buttonPanel.add(clearImage);
clearImage.addActionListener(this);
clearImage.setActionCommand("Clear Image");
drawingArea = new RectangleLabel();
drawingArea.setBorder(BorderFactory.createLineBorder(Color.blue));
this.add(drawingArea, BorderLayout.CENTER);
drawingArea.addMouseListener((MouseListener) drawingArea);
drawingArea.addMouseMotionListener((MouseMotionListener) drawingArea);
}
#Override
public void actionPerformed(ActionEvent arg0) {
switch (arg0.getActionCommand()) {
case "Intersections":
intersect = intersections.isSelected();
break;
case "Union":
uni = union.isSelected();
break;
case "Clear Image":
drawingArea.clearImage();
break;
case "Save Image":
drawingArea.saveImage();
break;
}
repaint();
}
class RectangleLabel extends JLabel implements MouseListener, MouseMotionListener {
Rectangle rectangle = null;
int x, y, x2, y2;
ArrayList<Rectangle> a = new ArrayList();
public RectangleLabel() {
super();
}
#Override
public void mousePressed(MouseEvent arg0) {
x = arg0.getX();
y = arg0.getY();
rectangle = new Rectangle(x, y, 0, 0);
a.add(rectangle);
}
#Override
public void mouseDragged(MouseEvent arg0) {
// TODO Auto-generated method stub
x2 = arg0.getX();
y2 = arg0.getY();
if (rectangle.getX() > x2) {
rectangle.setWidth(x - x2);
}
if (x2 > rectangle.getX()) {
rectangle.setWidth(x2 - x);
}
if (y > y2) {
rectangle.setHeight(y - y2);
}
if (y2 > y) {
rectangle.setHeight(y2 - y);
}
repaint();
}
#Override
public void mouseReleased(MouseEvent arg0) {
rectangle = null;
repaint();
}
#Override
public void mouseMoved(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Rectangle rect : a) {
float thickness = 2;
((Graphics2D) g).setStroke(new BasicStroke(thickness));
g.setColor(Color.BLUE);
g.drawRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
g.setColor(Color.gray);
g.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
if (intersect) {
for (int h = 0; h < a.size() - 1; h++) {
for (int j = 1; j < a.size(); j++) {
if (!a.get(h).equals(a.get(j)) && a.get(h).overlaps(a.get(j))) {
Rectangle rect = a.get(h).intersect(a.get(j));
g.setColor(Color.RED);
g.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}
}
}
if (uni) {
for (int h = 0; h < a.size() - 1; h++) {
for (int j = 1; j < a.size(); j++) {
if (!a.get(h).equals(a.get(j)) && a.get(h).overlaps(a.get(j))) {
Rectangle rect = a.get(h).union(a.get(j));
g.setColor(Color.WHITE);
g.drawRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
}
}
}
}
public void saveImage() {
BufferedImage image = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D aaaaa = image.createGraphics();
aaaaa.setBackground(Color.WHITE);
aaaaa.clearRect(0, 0, this.getWidth(), this.getHeight());
this.paintAll(aaaaa);
try {
File output = new File("rectangle.png");
ImageIO.write(image, "Rectangles", output);
} catch (IOException ie) {
}
}
public void clearImage() {
a.clear();
repaint();
}
}
public class Rectangle {
private int x, y, width, height;
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public Rectangle(Rectangle a) {
this.x = a.x;
this.y = a.y;
this.width = a.width;
this.height = a.height;
}
public String toString() {
return "Start: (" + x + "," + y + "), Width: " + width + ", Height: " + height + "\n";
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public int area() {
return width * height;
}
public boolean overlaps(Rectangle a) {
if ((x > a.x + a.width) || (a.x > x + width) || (y > a.y + a.height) || (a.y > y + height)) {
return false;
}
return true;
}
public Rectangle intersect(Rectangle a) {
if (!overlaps(a)) {
return null;
}
int left, right, top, bottom;
if (x < a.x) {
left = a.x;
} else {
left = x;
}
if (y < a.y) {
bottom = a.y;
} else {
bottom = y;
}
if ((x + width) < (a.x + a.width)) {
right = x + width;
} else {
right = a.x + a.width;
}
if ((y + height) < (a.y + a.height)) {
top = y + height;
} else {
top = a.y + a.height;
}
return new Rectangle(left, bottom, right - left, top - bottom);
}
public Rectangle union(Rectangle a) {
int left, right, top, bottom;
if (x < a.x) {
left = x;
} else {
left = a.x;
}
if (y < a.y) {
bottom = y;
} else {
bottom = a.y;
}
if ((x + width) < (a.x + a.width)) {
right = a.x + a.width;
} else {
right = x + width;
}
if ((y + height) < (a.y + a.height)) {
top = a.y + a.height;
} else {
top = y + height;
}
return new Rectangle(left, bottom, right - left, top - bottom);
}
}
}

Related

Java Multithreading Mouse Click

After making changes based on a previous post I have taken the following code a few steps further by introducing single/double click recognition. Why are the balls being created in the top left corner and not where the mouse is clicked?
BouncingBalls.java
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BouncingBalls extends JPanel implements MouseListener {
protected List<RandomBall> randomBalls = new ArrayList<RandomBall>(20);
protected List<VerticalBall> verticalBalls = new ArrayList<VerticalBall>(20);
private Container container;
private DrawCanvas canvas;
private Boolean doubleClick = false;
private final Integer waitTime = (Integer) Toolkit.getDefaultToolkit()
.getDesktopProperty("awt.multiClickInterval");
private static int canvasWidth = 500;
private static int canvasHeight = 500;
public static final int UPDATE_RATE = 30;
int count = 0;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height) {
canvasWidth = width;
canvasHeight = height;
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
start();
}
public void start() {
Thread t = new Thread() {
public void run() {
while (true) {
update();
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException e) {
}
}
}
};
t.start();
}
public void update() {
for (RandomBall ball : randomBalls) {
ball.ballBounce(container);
}
for (VerticalBall ball : verticalBalls) {
ball.verticalBounce(container);
}
}
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
container.draw(g);
for (RandomBall ball : randomBalls) {
ball.draw(g);
}
for (VerticalBall ball : verticalBalls) {
ball.draw(g);
}
}
public Dimension getPreferredSize() {
return (new Dimension(canvasWidth, canvasHeight));
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Stack Answer 2");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(canvasHeight, canvasWidth));
f.pack();
f.setVisible(true);
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() >= 2) {
doubleClick = true;
verticalBalls.add(new VerticalBall(getX(), getY(), canvasWidth, canvasHeight));
System.out.println("double click");
} else {
Timer timer = new Timer(waitTime, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (doubleClick) {
/* we are the first click of a double click */
doubleClick = false;
} else {
count++;
randomBalls.add(new RandomBall(getX(), getY(), canvasWidth, canvasHeight));
/* the second click never happened */
System.out.println("single click");
}
}
});
timer.setRepeats(false);
timer.start();
}
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
RandomBall.java
import java.awt.Color;
import java.awt.Graphics;
public class RandomBall {
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private int x;
private int y;
private int canvasWidth = 500;
private int canvasHeight = 500;
private boolean leftRight;
private boolean upDown;
private int deltaX;
private int deltaY;
private int radius = 20;
private int red = random(255);
private int green = random(255);
private int blue = random(255);
RandomBall(int x, int y, int width, int height) {
this(x, y, width, height, false, false);
}
RandomBall(int x, int y, int width, int height, boolean leftRight, boolean upDown) {
this.x = x;
this.y = y;
this.canvasWidth = width;
this.canvasHeight = height;
this.leftRight = leftRight;
this.upDown = upDown;
updateDelta();
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius),
(int) (2 * radius));
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
deltaX = minimumMovement + (int) (Math.random() * maxExtra);
}
public void ballBounce(Container container) {
// controls horizontal ball motion
if (leftRight) {
x += deltaX;
if (x >= getWidth()) {
leftRight = false;
updateDelta();
}
} else {
x += -deltaX;
if (x <= 0) {
leftRight = true;
updateDelta();
}
}
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return canvasWidth;
}
public int getHeight() {
return canvasHeight;
}
}
VerticalBall.java
import java.awt.Color;
import java.awt.Graphics;
public class VerticalBall {
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private int x;
private int y;
private int canvasWidth = 500;
private int canvasHeight = 500;
private boolean upDown;
private int deltaY;
private int radius = 20;
private int red = random(255);
private int green = random(255);
private int blue = random(255);
VerticalBall(int x, int y, int width, int height) {
this(x, y, width, height, false);
}
VerticalBall(int x, int y, int width, int height, boolean upDown) {
this.x = x;
this.y = y;
this.canvasWidth = width;
this.canvasHeight = height;
this.upDown = upDown;
updateDelta();
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius),
(int) (2 * radius));
}
private void updateDelta() {
final int minimumMovement = 5;
final int maxExtra = 10;
deltaY = minimumMovement + (int) (Math.random() * maxExtra);
}
public void verticalBounce(Container container) {
// controls vertical ball motion
if (upDown) {
y += deltaY;
if (y >= getHeight()) {
upDown = false;
updateDelta();
}
} else {
y += -deltaY;
if (y <= 0) {
upDown = true;
updateDelta();
}
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return canvasWidth;
}
public int getHeight() {
return canvasHeight;
}
}
Container.java
import java.awt.Color;
import java.awt.Graphics;
public class Container {
private static final int HEIGHT = 500;
private static final int WIDTH = 500;
private static final Color COLOR = Color.WHITE;
public void draw(Graphics g) {
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
Basically, because that's where you're telling them to be created...
verticalBalls.add(new VerticalBall(getX(), getY(), canvasWidth, canvasHeight));
getX() and getY() are getting the component's location (which happens to be close enough to 0x0 for arguments sake)...
Instead, you should be using the MouseEvent information...
public void mousePressed(MouseEvent e) {
if (e.getClickCount() >= 2) {
doubleClick = true;
verticalBalls.add(new VerticalBall(e.getX(), e.getY(), canvasWidth, canvasHeight));
System.out.println("double click");
}
}
This will create an issue for your Timer...
Instead you may need to introduce a couple of variables to hold the position information...
final int x = e.getX();
final int y = e.getX();
if (e.getClickCount() >= 2) {
...
} else {
Timer timer = new Timer(waitTime, new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (doubleClick) {
/* we are the first click of a double click */
doubleClick = false;
} else {
count++;
randomBalls.add(new RandomBall(x, y, canvasWidth, canvasHeight));
/* the second click never happened */
System.out.println("single click");
}
}
});
timer.setRepeats(false);
timer.start();
}
You need to use the getX and getY from the MouseEvent, not from the JPanel.
As a sidenote, your use of a separate Thread to periodically update the gui is bad because you can't use separate threads to call swing methods. use a swing Timer instead.

JPanel tearing even though I double buffer?

EDIT: This is an SSCCE to demonstrate my problem.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class Main {
public static BufferedImage map, tileSand, tileSea;
public static void main(String[] args) {
map = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
for(int x = 0; x < 50 ; x++){
for(int y = 0; y < 50 ; y++){
boolean colour = Math.random() < 0.5;
if (colour){
map.setRGB(x, y, -256);
} else {
map.setRGB(x, y, -16776961);
}
}
}
tileSand = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
Graphics g = tileSand.getGraphics();
g.setColor(Color.YELLOW);
g.fillRect(0, 0, 32, 32);
tileSea = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
g.setColor(Color.BLUE);
g = tileSea.getGraphics();
g.fillRect(0, 0, 32, 32);
Island test = new Main.Island();
test.start();
long start, sleep;
while(true) {
start = System.currentTimeMillis();
test.getCanvas().requestFocus();
test.getCanvas().repaint();
sleep = 15-(System.currentTimeMillis()-start);
try {
Thread.sleep(sleep > 0 ? sleep : 0);
} catch (InterruptedException e) {
}
}
}
static class Island implements Runnable {
private Tile[][] tiles;
private JFrame frame;
private JPanel panel;
private Thread logicThread;
private boolean running = false;
private boolean paused = false;
private Image image;
private Player player;
public Island() {
image = new BufferedImage(1027, 768, BufferedImage.TYPE_INT_ARGB);
player = new Player();
tiles = new Tile[map.getWidth()][map.getHeight()];
int rgb;
for(int x = 0; x < map.getWidth(); x++) {
for(int y = 0; y < map.getHeight(); y++) {
rgb = map.getRGB(x, y);
switch (rgb) {
case -16776961: tiles[x][y] = new Tile("sea");
break;
case -256: tiles[x][y] = new Tile("sand");
break;
}
}
}
makeMap();
makeFrame();
addBindings();
logicThread = new Thread(this);
}
public JPanel getCanvas() {
return panel;
}
public void start() {
running = true;
paused = false;
logicThread.start();
}
public void run() {
long sleep, before;
while(running){
before = System.currentTimeMillis();
player.move();
try {
sleep = 15-(System.currentTimeMillis()-before);
Thread.sleep(sleep > 0 ? sleep : 0);
} catch (InterruptedException ex) {
}
while(running && paused);
}
paused = false;
}
private void makeFrame() {
frame = new JFrame("Island");
panel = new JPanel(){
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, 1024, 768);
long xl, yl;
xl = player.getLocation().x-512;
yl = player.getLocation().y-384;
int x2, y2;
x2 = (int) Math.floor(xl / 32);
y2 = (int) Math.floor(yl / 32);
int xoffset, yoffset;
xoffset = (int) (xl % 32);
yoffset = (int) (yl % 32);
for(int x = x2; x < x2+40; x++) {
for(int y = y2; y < y2+40; y++) {
if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) {
g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null);
}
}
}
g.drawImage(image, 0, 0, null);
}
};
panel.setPreferredSize(new Dimension(1024, 768));
panel.setIgnoreRepaint(true);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
private void addBindings() {
InputMap inputMap = panel.getInputMap();
ActionMap actionMap = panel.getActionMap();
inputMap.put(KeyStroke.getKeyStroke("Q"),"hold-sprint");
actionMap.put("hold-sprint", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.sprint(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released Q"),"release-sprint");
actionMap.put("release-sprint", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.sprint(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("RIGHT"),"hold-right");
actionMap.put("hold-right", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.right(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released RIGHT"),"release-right");
actionMap.put("release-right", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.right(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("DOWN"),"hold-down");
actionMap.put("hold-down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.down(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released DOWN"),"release-down");
actionMap.put("release-down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.down(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("LEFT"),"hold-left");
actionMap.put("hold-left", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.left(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released LEFT"),"release-left");
actionMap.put("release-left", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.left(false);
}
});
inputMap.put(KeyStroke.getKeyStroke("UP"),"hold-up");
actionMap.put("hold-up", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.up(true);
}
});
inputMap.put(KeyStroke.getKeyStroke("released UP"),"release-up");
actionMap.put("release-up", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
player.up(false);
}
});
}
private void makeMap() {
for(int x = 0; x < tiles.length; x++) {
for(int y = 0; y < tiles[0].length; y++) {
switch (tiles[x][y].getType()) {
case "sea": tiles[x][y].setContent(tileSea);
break;
case "sand": tiles[x][y].setContent(tileSand);
break;
}
}
}
}
}
static class Player{
private Point location;
private int xspeed, yspeed;
private boolean left, up, right, down, sprint;
public Player() {
location = new Point(0, 0);
left = false;
up = false;
right = false;
down = false;
sprint = false;
xspeed = yspeed = 0;
}
public void left(boolean state){
left = state;
}
public void up(boolean state){
up = state;
}
public void right(boolean state){
right = state;
}
public void down(boolean state){
down = state;
}
public void sprint(boolean state) {
sprint = state;
}
public void move() {
if (sprint) {
if (left) {
if(xspeed>-10)
xspeed--;
} if (right) {
if(xspeed<10)
xspeed++;
} if (up) {
if(yspeed>-10)
yspeed--;
} if (down) {
if(yspeed<10)
yspeed++;
}
} else {
if (left) {
if(xspeed>-5)
xspeed--;
} if (right) {
if(xspeed<5)
xspeed++;
} if (up) {
if(yspeed>-5)
yspeed--;
} if (down) {
if(yspeed<5)
yspeed++;
}
}
if (!sprint) {
if (xspeed > 5) {
xspeed--;
} if (xspeed < -5) {
xspeed++;
} if (yspeed > 5) {
yspeed--;
} if (yspeed < -5) {
yspeed++;
}
}
if (!left && !right) {
if (xspeed > 0) {
xspeed--;
} if (xspeed < 0) {
xspeed++;
}
} if (!up && !down) {
if (yspeed > 0) {
yspeed--;
} if (yspeed < 0) {
yspeed++;
}
}
location.x = location.x + xspeed;
location.y = location.y + yspeed;
}
public Point getLocation() {
return location;
}
}
static class Tile {
private String type;
private BufferedImage tile;
public Tile(String type) {
this.type = type;
}
public String getType() {
return type;
}
public void setContent(BufferedImage newTile) {
tile = newTile;
}
public BufferedImage getContent() {
return tile;
}
}
}
I have a JPanel with a modified paintComponent method. In this method I draw the relevant tiles from a 2d array to the screen based on the player location. I draw all my tiles to a BufferedImage and then I apply it to the screen at the end of the paint method. In theory this should not create tearing as I am double buffering? Here is the appropriate code, image is just a BufferedImage with the dimensions of the screen:
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, 1024, 768);
long xl, yl;
xl = player.getLocation().x-512;
yl = player.getLocation().y-384;
int x2, y2;
x2 = (int) Math.floor(xl / 32);
y2 = (int) Math.floor(yl / 32);
int xoffset, yoffset;
xoffset = (int) (xl % 32);
yoffset = (int) (yl % 32);
for(int x = x2; x < x2+40; x++) {
for(int y = y2; y < y2+40; y++) {
if (x < tiles.length && x > 0 && y < tiles[0].length && y > 0) {
g2d.drawImage(tiles[x][y].getContent(), (x-x2)*32 - xoffset, (y-y2)*32 - yoffset, null);
}
}
}
g.drawImage(image, 0, 0, null);
}
I think the tearing could possibly be caused by the player's location changing over the duration of the paint method causing the tiles not to match up, the faster the player goes the more obvious the effect is. However I get the players location at the start and store it in two longs, I was under the impression that longs are passed by value not reference so the player location should be constant whilst the method runs.
I am happy to provide more code :), and thanks in advance.
Just so if people find my question and wonder what I ended up doing to "fix" it, switch over to c++ and SDL or some other image library before you are to far into your project, it's simply better for this kind of thing.

Java Applet Game 2D Window Scrolling

I'm trying to develop a 2D RPG Game in a Java Applet. Right now I've got a simple oval that the player can use Left, Right, Up and Down to move, and collisions against the borders of the applet stops them. The problem is, I want to create a giant world(2000px by 2000x) of area that the player can move. However, I want them only to see 600px by 400x of the screen at one time. If they keep moving right, I want the screen to follow them, same goes for up, down and left. Can anyone tell me how to do this? Here is my code so far:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.applet.Applet;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Main extends Applet implements Runnable, KeyListener
{
private Image dbImage;
private Graphics dbg;
Thread t1;
int x = 0;
int y = 0;
int prevX = x;
int prevY = y;
int radius = 40;
boolean keyReleased = false;
public void init()
{
setSize(600, 400);
}
public void start()
{
addKeyListener(this);
t1 = new Thread(this);
t1.start();
}
public void destroy()
{
}
public void stop()
{
}
public void paint(Graphics g)
{
//player
g.setColor(Color.RED);
g.fillOval(x, y, radius, radius);
}
public void update(Graphics g)
{
dbImage = createImage (this.getSize().width, this.getSize().height);
dbg = dbImage.getGraphics();
// initialize buffer
if (dbImage == null)
{
}
// clear screen in background
dbg.setColor(getBackground());
dbg.fillRect(0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
dbg.setColor(getForeground());
paint(dbg);
// draw image on the screen
g.drawImage(dbImage, 0, 0, this);
}
#Override
public void run()
{
while (true)
{
//x++;
repaint();
try
{
t1.sleep(17);
}
catch (Exception e)
{
}
}
}
public boolean CheckCollision(String dir)
{
if (x <= 0 && dir.equals("L"))
{
x = prevX;
return true;
}
else if (y <= 0 && dir.equals("U"))
{
y = prevY;
return true;
}
else if (x >= (getWidth() - radius) && dir.equals("R"))
{
System.out.println(getWidth());
x = prevX;
return true;
}
else if (y >= (getHeight() - radius) && dir.equals("D"))
{
y = prevY;
return true;
}
return false;
}
#Override
public void keyPressed(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_RIGHT:
if (!CheckCollision("R"))
{
x += 4;
prevX = x;
}
break;
case KeyEvent.VK_LEFT:
if (!CheckCollision("L"))
{
x -= 4;
prevX = x;
}
break;
case KeyEvent.VK_UP:
if (!CheckCollision("U"))
{
y -= 4;
prevY = y;
}
break;
case KeyEvent.VK_DOWN:
if (!CheckCollision("D"))
{
y += 4;
prevY = y;
}
break;
}
}
#Override
public void keyReleased(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
}
This is a basic example of scrolling viewable area, where the virtual world is large then the view area.
This basically maintains a number of parameters. It maintains the point where in the world the top/left of the view is and the players position within the world.
These values are converted back to real world coordinates (where 0x0 is the top left corner of the viewable area).
The examples also use BufferedImage#getSubImage to make it easier to render. You could calculate the offset position of the map to the view as well, but that comes down to needs...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MiddleEarth {
public static void main(String[] args) {
new MiddleEarth();
}
public MiddleEarth() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new WorldPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class WorldPane extends JPanel {
private BufferedImage map;
private BufferedImage party;
private Point viewPort;
private Point partyPoint;
private BufferedImage view;
public WorldPane() {
try {
map = ImageIO.read(getClass().getResource("/MiddleEarth.jpg"));
party = ImageIO.read(getClass().getResource("/8BitFrodo.png"));
viewPort = new Point(0, (map.getHeight() / 2) - 100);
partyPoint = new Point(party.getWidth() / 2, (map.getHeight() / 2)); // Virtual Point...
} catch (IOException exp) {
exp.printStackTrace();
}
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "goRight");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "goLeft");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "goUp");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "goDown");
am.put("goRight", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(10, 0);
}
});
am.put("goLeft", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(-10, 0);
}
});
am.put("goUp", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(0, -10);
}
});
am.put("goDown", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
moveParty(0, 10);
}
});
}
protected void moveParty(int xDelta, int yDelta) {
partyPoint.x += xDelta;
partyPoint.y += yDelta;
Point view = fromWorld(partyPoint);
if (view.x > getWidth() - (party.getWidth() / 2)) {
viewPort.x += xDelta;
if (viewPort.x + getWidth() > map.getWidth()) {
viewPort.x = map.getWidth() - getWidth();
partyPoint.x = map.getWidth() - (party.getWidth() / 2) - 1;
}
invalidate();
} else if (view.x < party.getWidth() / 2) {
viewPort.x += xDelta;
if (viewPort.x < 0) {
viewPort.x = 0;
partyPoint.x = (party.getWidth() / 2);
}
invalidate();
}
System.out.println(view + "; " + getHeight());
if (view.y > getHeight() - (party.getHeight() / 2)) {
viewPort.y += yDelta;
if (viewPort.y + getHeight() > map.getHeight()) {
viewPort.y = map.getHeight() - getHeight();
partyPoint.y = map.getHeight() - (party.getHeight() / 2) - 1;
}
invalidate();
} else if (view.y < party.getHeight() / 2) {
viewPort.y += yDelta;
if (viewPort.y < 0) {
viewPort.y = 0;
partyPoint.y = (party.getHeight() / 2);
}
invalidate();
}
repaint();
}
#Override
public void invalidate() {
view = null;
super.invalidate();
}
public BufferedImage getView() {
if (view == null && getWidth() > 0 && getHeight() > 0) {
view = map.getSubimage(viewPort.x, viewPort.y, getWidth(), getHeight());
}
return view;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (map != null) {
g2d.drawImage(getView(), 0, 0, this);
Point real = fromWorld(partyPoint);
int x = real.x - (party.getWidth() / 2);
int y = real.y - (party.getHeight()/ 2);
g2d.drawImage(party, x, y, this);
}
g2d.dispose();
}
protected Point fromWorld(Point wp) {
Point p = new Point();
p.x = wp.x - viewPort.x;
p.y = wp.y - viewPort.y;
return p;
}
}
}
This is how I do in my engine.
I'll keep two variables OffSetX and OffSetY
And calculate them every step to center the player like this.
OffSetX = 0;
OffSetY = 0;
if (MAP_WIDTH > WINDOW_WIDTH) {
OffSetX = Math.round(WINDOW_WIDTH / 2 - obj.getX() - TILE_SIZE);
OffSetX = Math.min(OffSetX, 0);
OffSetX = Math.max(OffSetX, WINDOW_WIDTH - MAP_WIDTH);
}
if (MAP_HEIGHT > WINDOW_HEIGHT) {
OffSetY = Math.round(WINDOW_HEIGHT / 2 - obj.getY() - TILE_SIZE);
OffSetY = Math.min(OffSetY, 0);
OffSetY = Math.max(OffSetY, WINDOW_HEIGHT - MAP_HEIGHT);
}
And then draw the map at the position (OffSetX, OffSetY) i.e., just add these to the original position of the object to draw.
You may want to skip rendering objects which are not visible.

how to notify multithread event on swing game

I am supposed to make a little game simulation. in this game there are three button . when user click start tank and car will close each other in 90 degrees when user click shut button tank will throw bullet to car.
i made and a simulation for this. tank throw bullet to car but when bullet crash car i couldn't this. i just need increase score of how many times tank hit car.
here is the source code
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Vehicle extends Thread {
private JPanel box;
private int XSIZE;
private int YSIZE;
private int time;
private int x;
private int y;
private int dx = 5;
private int dy = 5;
private int dim;
public Vehicle(JPanel b, int i) {
box = b;
this.dim = i;
if (i == 0) {
x = 0;
y = 100;
time = 1000;
XSIZE = 9;
YSIZE = 20;
} else {
time = 200;
y = box.getSize().height;
x = box.getSize().width / 2;
XSIZE = 6;
YSIZE = 10;
}
}
public void draw() {
Graphics g = box.getGraphics();
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
public void moveHorizontal() {
if (!box.isVisible())
return;
Graphics g = box.getGraphics();
g.setColor(Color.BLUE);
g.setXORMode(box.getBackground());
g.fillOval(x, y, XSIZE, YSIZE);
x += dx;
Dimension d = box.getSize();
if (x < 0) {
x = 0;
dx = -dx;
}
if (x + XSIZE >= d.width) {
x = d.width - XSIZE;
dx = -dx;
}
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
public JPanel getBox() {
return box;
}
public void setBox(JPanel box) {
this.box = box;
}
public void moveVertical() {
if (!box.isVisible())
return;
Graphics g = box.getGraphics();
g.setXORMode(box.getBackground());
g.fillOval(x, y, XSIZE, YSIZE);
y += dy;
Dimension d = box.getSize();
if (y < 0) {
y = 0;
dy = -dy;
}
if (y + YSIZE >= d.height) {
y = d.height - YSIZE;
dy = -dy;
}
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
public void move(int i) {
if (i == 0) {
moveHorizontal();
} else {
moveVertical();
}
}
public int getYSIZE() {
return YSIZE;
}
public void setYSIZE(int ySIZE) {
YSIZE = ySIZE;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public int getXSIZE() {
return XSIZE;
}
public void setXSIZE(int xSIZE) {
XSIZE = xSIZE;
}
public void setY(int y) {
this.y = y;
}
public void run() {
try {
draw();
for (;;) {
move(dim);
sleep(time);
}
} catch (InterruptedException e) {
}
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Bullet extends Thread {
private JPanel box;
private int XSIZE = 3;
public int getXSIZE() {
return XSIZE;
}
public void setXSIZE(int xSIZE) {
XSIZE = xSIZE;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
private int YSIZE = 1;
private int x;
private int y;
private int dx = 3;
public Bullet(JPanel b, Vehicle tank, Vehicle car) {
box = b;
x = tank.getX() + tank.getXSIZE();
if (x >= tank.getBox().getSize().width / 2)
dx = -dx;
y = tank.getY() + tank.getYSIZE() / 2;
;
}
public void draw() {
Graphics g = box.getGraphics();
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
public void move() {
if (!box.isVisible())
return;
Graphics g = box.getGraphics();
g.setColor(Color.RED);
g.setXORMode(box.getBackground());
g.fillOval(x, y, XSIZE, YSIZE);
x += dx;
Dimension d = box.getSize();
if (x < 0) {
x = 0;
}
if (x + XSIZE >= d.width) {
x = d.width - XSIZE;
}
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}
public void run() {
try {
draw();
for (;;) {
move();
sleep(20);
}
} catch (InterruptedException e) {
}
}
}
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
#SuppressWarnings("serial")
public class Tank_Shut_Car_ThreadFrame extends JFrame {
private JPanel canvas;
private boolean isOn = false;
private Vehicle tank;
private Vehicle car;
private JLabel score;
public static int sc = 0;
public Tank_Shut_Car_ThreadFrame() {
setResizable(false);
setSize(600, 400);
setTitle("Tank Shut Car");
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Container contentPane = getContentPane();
canvas = new JPanel();
contentPane.add(canvas, "Center");
canvas.setLayout(null);
score = new JLabel("0");
score.setBounds(527, 11, 36, 14);
canvas.add(score);
JLabel lblScore = new JLabel("score");
lblScore.setBounds(481, 11, 36, 14);
canvas.add(lblScore);
JPanel p = new JPanel();
addButton(p, "Start", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (!isOn) {
tank = new Vehicle(canvas, 0);
tank.start();
car = new Vehicle(canvas, 1);
car.start();
isOn = true;
}
}
});
addButton(p, "Shut", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (isOn) {
Bullet bullet = new Bullet(canvas, tank, car);
bullet.start();
score.setText("" + sc);
}
}
});
addButton(p, "Close", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
canvas.setVisible(false);
System.exit(0);
}
});
contentPane.add(p, "South");
}
public void addButton(Container c, String title, ActionListener a) {
JButton button = new JButton(title);
c.add(button);
button.addActionListener(a);
}
}
import javax.swing.JFrame;
public class Test {
public static void main(String[] args) {
JFrame frame = new Tank_Shut_Car_ThreadFrame();
frame.setVisible(true);
}
}
Okay, so I had a play around with this (just for fun)
Now, this is far from a "proper" or "complete" game engine, but it provides a basic idea of how it might be possible to mix a core thread engine with UI components.
Rather then pasting the entire code, I've uploaded the source it to Tank.zip
But the basic engine looks like this...
public class GameEngine extends Thread {
public static final Object ASSET_LOCK = new Object();
private List<GameAsset> lstAssets;
private GameScreen screen;
public GameEngine(GameScreen screen) {
// Let the thread die when the JVM closes
setDaemon(true);
// Want to be below the UI thread (personal preference)
setPriority(NORM_PRIORITY - 1);
// A list of game assests
lstAssets = new ArrayList<GameAsset>(25);
// A reference to the screen
this.screen = screen;
// Add global key listener, this is simpler to the trying to attach a key listener
// to the screen.
Toolkit.getDefaultToolkit().addAWTEventListener(new EventHandler(), AWTEvent.KEY_EVENT_MASK);
}
public GameAsset[] getAssets() {
synchronized (ASSET_LOCK) {
return lstAssets.toArray(new GameAsset[lstAssets.size()]);
}
}
/*
* Allows for assets to be added
*/
public void addAsset(GameAsset asset) {
synchronized (ASSET_LOCK) {
lstAssets.add(asset);
}
}
#Override
public void run() {
while (true) {
try {
sleep(40);
} catch (InterruptedException ex) {
}
synchronized (ASSET_LOCK) {
GameAsset[] assets = lstAssets.toArray(new GameAsset[lstAssets.size()]);
for (GameAsset asset : assets) {
if (lstAssets.contains(asset)) {
asset.update(this, screen);
}
}
screen.repaint(new ArrayList<GameAsset>(lstAssets));
}
}
}
/**
* Allows the removal of an asset...
*/
public void removeAsset(GameAsset asset) {
synchronized (ASSET_LOCK) {
lstAssets.remove(asset);
}
}
/**
* Key event handling...
*/
protected class EventHandler implements AWTEventListener {
#Override
public void eventDispatched(AWTEvent event) {
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
synchronized (ASSET_LOCK) {
GameAsset[] assets = lstAssets.toArray(new GameAsset[lstAssets.size()]);
for (GameAsset asset : assets) {
if (lstAssets.contains(asset)) {
asset.processKeyPressed(GameEngine.this, screen, keyEvent);
}
}
}
} else if (keyEvent.getID() == KeyEvent.KEY_RELEASED) {
synchronized (ASSET_LOCK) {
GameAsset[] assets = lstAssets.toArray(new GameAsset[lstAssets.size()]);
for (GameAsset asset : lstAssets) {
if (lstAssets.contains(asset)) {
asset.processKeyReleased(GameEngine.this, screen, keyEvent);
}
}
}
}
}
}
}
Swing is not thread safe. Events should be fired on the event-dispatching thread.
http://www.javamex.com/tutorials/threads/invokelater.shtml

Three Paddle Pong Hit Detection

I am creating yet another version of pong. This one uses 3 paddles for each person. I have spent almost two hours trying to figure out why the two other paddles are not detecting when the ball strikes the paddle. The original (top) paddle does detect the hit and properly updates the hit counter. I have tried separate if statements, else if statements etc., with no success. I created three Y variables to detect the position of all three paddles still no luck.
Any suggestions?
import java.awt.Point;
public class box {
private int xTopLeft, yTopLeft, width, height;
int xBall, yBall;
private int radius = 5;
int xBallVel, yBallVel;
int VELOCITY_MAG =5;
public Point ballLoc = new Point();
private int paddleY;
private int paddleYP2;
private int paddleYP3;
private int paddleWidth = 20;
private int paddleWidth2 = 20;
private int paddleWidth3 = 20;
int hitCount = 0;
int missCount = 0;
private boolean updating=true;
public int getBallRadius()
{
return radius;
}
public Point getBallLoc()
{
ballLoc.x = xBall;
ballLoc.y = yBall;
return ballLoc;
}
public box(int x, int y, int w, int h)
{
xTopLeft =x;
yTopLeft = y;
width =w;
height = h;
createRandomBallLocation();
}
public void updatePaddle(int y)
{
paddleY = y;
}
public void updatePaddleP2(int yp2)
{
paddleYP2 = yp2;
}
public void updatePaddleP3(int yp3)
{
paddleYP3 = yp3;
}
public int getPaddleWidth()
{
return paddleWidth ;
}
public int getPaddleWidth2()
{
return paddleWidth2 ;
}
public int getPaddleWidth3()
{
return paddleWidth3 ;
}
public int getPaddleY()
{
System.out.println(paddleY);
return paddleY;
}
public int getPaddleP2()
{
System.out.println(paddleYP2);
return paddleYP2;
}
public int getPaddleP3()
{
return paddleYP3;
}
public int getHitCount()
{
return hitCount;
}
public int getMissCount()
{
return missCount;
}
public int velMag()
{
return VELOCITY_MAG;
}
public void update()
{
if (!updating) return;
xBall = xBall + xBallVel;
yBall = yBall + yBallVel;
if (xBall + radius >= xTopLeft+width && xBallVel>=0)
if ((yBall >= paddleY-paddleWidth && yBall <= paddleY + paddleWidth)
|| (yBall >= paddleYP2-paddleWidth2 && yBall <= paddleYP2 + paddleWidth2 )
|| (yBall >= paddleYP3-paddleWidth3 && yBall <= paddleYP3 + paddleWidth3 ))
{
// hit paddles
xBallVel = - xBallVel;
hitCount++;
}
else if (xBall+radius >= xTopLeft + width)
{
xBallVel = - xBallVel;
}
if (yBall+radius >= yTopLeft + height && yBallVel >= 0)
{
yBallVel = - yBallVel;
}
if (yBall-radius <= yTopLeft && yBallVel <=0)
{
yBallVel = - yBallVel;
}
if (xBall-radius <= xTopLeft && xBallVel <= 0)
{
xBallVel = - xBallVel;
}
}
public void createRandomBallLocation()
{
xBall = xTopLeft + radius +
(int)((width-2*radius)*Math.random());
yBall = yTopLeft + radius +
(int)((height-2*radius)*Math.random());
xBallVel = velMag();
yBallVel = velMag();
}
}
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.image.BufferStrategy;
public class Pong extends JFrame
implements Runnable{
box box = null;
int top, left, width, height;
final int LINE_THICKNESS = 5;
Graphics bufferGraphics;
int sleep=25;
public Pong(String name)
{
super(name);
int windowWidth = 1024;
int windowHeight =768;
this.setSize(windowWidth, windowHeight);
this.setResizable(false);
this.setLocation(400, 150);
this.setVisible(true);
this.createBufferStrategy(4);
MyMouseClick mmc = new MyMouseClick();
addMouseListener(mmc);
MyMouseMotion mmm = new MyMouseMotion();
addMouseMotionListener(mmm);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Thread thread = new Thread(this);
thread.start();
}
public void run()
{
while(true)
{
try
{
if (box != null)
{
box.update();
repaint();
}
Thread.sleep(sleep);
}
catch (InterruptedException e)
{}
}
}
public void paint(Graphics g)
{
BufferStrategy bf = this.getBufferStrategy();
g = bf.getDrawGraphics();
Dimension d = getSize();
if (box ==null)
{
Insets insets = getInsets();
left = insets.left;
top = insets.top;
width = d.width-left - insets.right;
height = d.height - top - insets.bottom;
box = new box(left, top, width, height);
}
g.fillRect(0,0, d.width, d.height);
g.setColor(Color.BLUE);
g.setFont(new Font("Arial", 20, 30));
g.drawString("Hits: "+box.getHitCount(), 20, 60);
g.setColor(Color.red);
g.setFont(new Font("Arial", 20, 30));
g.drawString("Misses: "+box.getMissCount(), 20, 380);
g.fillRect(left, top, left+width, LINE_THICKNESS); // top of box
g.setColor(Color.white);
g.fillRect(left, top+height, left+width, LINE_THICKNESS); // bottom of box
g.drawLine(left, top, left, top+height); // left of box
g.drawLine(left+width, top, left+width, top+height); // right side
Point ballLoc = box.getBallLoc();
int radius = box.getBallRadius();
g.fillOval(ballLoc.x - radius, ballLoc.y-radius, 2*radius, 2*radius);
// Draw paddles Player 1
g.setColor(Color.yellow);
int yp = box.getPaddleY();
int yp2 = box.getPaddleP2();
int yp3 = box.getPaddleP3();
int yw = box.getPaddleWidth();
int yw2 = box.getPaddleWidth2();
int yw3 = box.getPaddleWidth3();
g.fillRect(left+width-5, yp-yw, 4, 50);
g.fillRect(left+width-5, (yp2-yw2)+280, 4, 50);
g.fillRect(left+width-5, (yp3-yw3)+140, 4, 50);
bf.show();
}
// *********************** Inner classes
class MyMouseClick extends MouseAdapter
{
public void mouseClicked(MouseEvent e)
{
box = null;
repaint();
}
}
class MyMouseMotion extends MouseMotionAdapter
{
public void mouseMoved(MouseEvent e)
{
int y = e.getY();
int y2 = e.getY();
int y3 = e.getY();
if (box != null)
{
box.updatePaddle(y);
box.updatePaddleP2(y2);
box.updatePaddleP3(y3);
repaint();
}
}
}
// ************************************
public static void main(String[] args) {
Pong t = new Pong("Three Paddle Pong");
t.setVisible(true);
} // end of main
}
In the paint method you do paint your 3 paddles at different y positions, but for the actual paddle positions, paddleYP? which are used for collision detection, you just set the 3 paddles to the same y in mouseMoved.

Categories