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.
Related
To be frank i have not the slightest clue how to fix this whats so ever. It works until you get to the part that only 1 brick shows and its kinda frustrating... If anyone could help me i would appreciate it. I did look up how to fix this but i didn't even find anyone that had this problem. Google searching isn't really that good. Oh and i used Eclipse for this program.
Board Class
package Final;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;
public class Board extends JPanel implements Commons {
private Timer timer;
private String message = "Your Fired";
private Ball ball;
private Paddle paddle;
private Brick bricks[];
private boolean ingame = true;
public Board() {
initBoard();
}
private void initBoard() {
addKeyListener(new TAdapter());
setFocusable(true);
bricks = new Brick[N_OF_BRICKS];
setDoubleBuffered(true);
timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), DELAY, PERIOD);
}
#Override
public void addNotify() {
super.addNotify();
gameInit();
}
private void gameInit() {
ball = new Ball();
paddle = new Paddle();
int k = 0;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 6; j++) {
bricks[k] = new Brick(j * 40 + 30, i * 10 + 50);
k++;
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
if (ingame) {
drawObjects(g2d);
} else {
gameFinished(g2d);
}
Toolkit.getDefaultToolkit().sync();
}
private void drawObjects(Graphics2D g2d) {
g2d.drawImage(ball.getImage(), ball.getX(), ball.getY(),
ball.getWidth(), ball.getHeight(), this);
g2d.drawImage(paddle.getImage(), paddle.getX(), paddle.getY(),
paddle.getWidth(), paddle.getHeight(), this);
for (int i = 0; i < N_OF_BRICKS; i++) {
if (!bricks[i].isDestroyed()) {
g2d.drawImage(bricks[i].getImage(), bricks[i].getX(),
bricks[i].getY(), bricks[i].getWidth(),
bricks[i].getHeight(), this);
}
}
}
private void gameFinished(Graphics2D g2d) {
Font font = new Font("Verdana", Font.BOLD, 18);
FontMetrics metr = this.getFontMetrics(font);
g2d.setColor(Color.BLACK);
g2d.setFont(font);
g2d.drawString(message,
(Commons.WIDTH - metr.stringWidth(message)) / 2,
Commons.WIDTH / 2);
}
private class TAdapter extends KeyAdapter {
#Override
public void keyReleased(KeyEvent e) {
paddle.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
paddle.keyPressed(e);
}
}
private class ScheduleTask extends TimerTask {
#Override
public void run() {
ball.move();
paddle.move();
checkCollision();
repaint();
}
}
private void stopGame() {
ingame = false;
timer.cancel();
}
private void checkCollision() {
if (ball.getRect().getMaxY() > Commons.BOTTOM_EDGE) {
stopGame();
}
for (int i = 0, j = 0; i < N_OF_BRICKS; i++) {
if (bricks[i].isDestroyed()) {
j++;
}
if (j == N_OF_BRICKS) {
message = "Pay Day";
stopGame();
}
}
if ((ball.getRect()).intersects(paddle.getRect())) {
int paddleLPos = (int) paddle.getRect().getMinX();
int ballLPos = (int) ball.getRect().getMinX();
int first = paddleLPos + 8;
int second = paddleLPos + 16;
int third = paddleLPos + 24;
int fourth = paddleLPos + 32;
if (ballLPos < first) {
ball.setXDir(-1);
ball.setYDir(-1);
}
if (ballLPos >= first && ballLPos < second) {
ball.setXDir(-1);
ball.setYDir(-1 * ball.getYDir());
}
if (ballLPos >= second && ballLPos < third) {
ball.setXDir(0);
ball.setYDir(-1);
}
if (ballLPos >= third && ballLPos < fourth) {
ball.setXDir(1);
ball.setYDir(-1 * ball.getYDir());
}
if (ballLPos > fourth) {
ball.setXDir(1);
ball.setYDir(-1);
}
}
for (int i = 0; i < N_OF_BRICKS; i++) {
if ((ball.getRect()).intersects(bricks[i].getRect())) {
int ballLeft = (int) ball.getRect().getMinX();
int ballHeight = (int) ball.getRect().getHeight();
int ballWidth = (int) ball.getRect().getWidth();
int ballTop = (int) ball.getRect().getMinY();
Point pointRight = new Point(ballLeft + ballWidth + 1, ballTop);
Point pointLeft = new Point(ballLeft - 1, ballTop);
Point pointTop = new Point(ballLeft, ballTop - 1);
Point pointBottom = new Point(ballLeft, ballTop + ballHeight + 1);
if (!bricks[i].isDestroyed()) {
if (bricks[i].getRect().contains(pointRight)) {
ball.setXDir(-1);
} else if (bricks[i].getRect().contains(pointLeft)) {
ball.setXDir(1);
}
if (bricks[i].getRect().contains(pointTop)) {
ball.setYDir(1);
} else if (bricks[i].getRect().contains(pointBottom)) {
ball.setYDir(-1);
}
bricks[i].setDestroyed(true);
}
}
}
}
}
Brick Class
package Final;
import javax.swing.ImageIcon;
public class Brick extends Sprite {
private boolean destroyed;
public Brick(int x, int y) {
ImageIcon ii = new ImageIcon("images/bricks.png");
image = ii.getImage();
i_width = image.getWidth(null);
i_heigth = image.getHeight(null);
destroyed = false;
}
public boolean isDestroyed() {
return destroyed;
}
public void setDestroyed(boolean val) {
destroyed = val;
}
}
Commons Class
package Final;
public interface Commons {
public static final int WIDTH = 300;
public static final int HEIGTH = 400;
public static final int BOTTOM_EDGE = 390;
public static final int N_OF_BRICKS = 30;
public static final int INIT_PADDLE_X = 200;
public static final int INIT_PADDLE_Y = 360;
public static final int INIT_BALL_X = 230;
public static final int INIT_BALL_Y = 355;
public static final int DELAY = 1000;
public static final int PERIOD = 10;
}
Sprite Class
package Final;
import java.awt.Image;
import java.awt.Rectangle;
public class Sprite {
protected int x;
protected int y;
protected int i_width;
protected int i_heigth;
protected Image image;
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
public int getWidth() {
return i_width;
}
public int getHeight() {
return i_heigth;
}
Image getImage() {
return image;
}
Rectangle getRect() {
return new Rectangle(x, y,
image.getWidth(null), image.getHeight(null));
}
}
Breakout Class
package Final;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Breakout extends JFrame {
public Breakout() {
initUI();
}
private void initUI() {
add(new Board());
setTitle("Lord Carl's Demolition Job");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(Commons.WIDTH, Commons.HEIGTH);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Breakout game = new Breakout();
game.setVisible(true);
}
});
}
}
The problem is in checkCollision(). Inside the loop, j will never equal N_OF_BRICKS because of the loop condition. You could change to:
private void checkCollision() {
if (ball.getRect().getMaxY() > Commons.BOTTOM_EDGE) {
stopGame();
}
int j = 0;
for (int i = 0; i < N_OF_BRICKS; i++) {
if (bricks[i].isDestroyed()) {
j++;
}
}
if (j == N_OF_BRICKS) {
message = "Pay Day";
stopGame();
}
}
Also, in the Brick class you neglect to store the x,y coords:
public class Brick extends Sprite {
....
public Brick(int x, int y) {
ImageIcon ii = new ImageIcon("images/bricks.png");
image = ii.getImage();
i_width = image.getWidth(null);
i_heigth = image.getHeight(null);
destroyed = false;
// Save these
this.x = x;
this.y = y
}
....
}
Or, add a constructor to the Sprite class and call that from the Brick constructor:
public class Sprite {
....
public Sprite(int x, int y) {
this.x = x;
this.y = y;
}
....
}
public class Brick extends Sprite {
....
public Brick(int x, int y) {
// Call the sprite constructor
super(x, y);
ImageIcon ii = new ImageIcon("images/bricks.png");
image = ii.getImage();
i_width = image.getWidth(null);
i_heigth = image.getHeight(null);
destroyed = false;
}
....
}
Good day, I'm new to StackOverflow and Java programming. I currently have a school project that needs multi threading and I just need your advice on how to fix my code. I have spent too much time looking for answers on how to create a moving multiple images using a thread. I knew I'm almost near to find the solution but I'm running out of time as the submission is fast approaching. I believed I'll be more efficient if I seek help from somehow who knows better in Java.
Many thanks in advance.
Below is my current code, and it seems that image is flickering while moving.
// Bounce.java
import javax.swing.JFrame;
public class Bounce {
public static void main(String args[]) {
myBall s = new myBall(10, 20, 2, 2);
myBall s1 = new myBall(100, 10, 2, 2);
myBall s2 = new myBall(40, 10, 2, 2);
JFrame f = new JFrame();
f.add(s);
f.add(s1);
f.add(s2);
f.setVisible(true);
f.setSize(600, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Moving Ball");
}
}
The next code is in separate file.
// myBall.java
import java.awt.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
public class myBall extends JPanel implements Runnable {
private Thread animator;
int x = 0, y = 0, velX = 2, velY = 2;
Timer t;
public myBall(int x, int y, int velX, int velY) {
JFrame jf = new JFrame();
jf.setSize(600,400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(this);
jf.setVisible(true);
this.x = (int )(Math.random() * 560);
this.y = (int )(Math.random() * 360);
this.velX = velX;
this.velY = velY;
}
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, 40, 40);
g2.fill(ellipse);
}
public void cycle() {
if(x < 0 || x > 560) {
velX = -velX;
}
if(y < 0 || y > 360) {
velY = -velY;
}
x += velX;
y += velY;
System.out.println(x);
}
#Override
public void run() {
while(true) {
for (int i = 0; i < 600; i++) {
cycle();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
}
}
Here you go. I normally don't do this, but you asked nicely and your code was pretty clean, so I assumed you been working a lot on it.
public class Start {
public static void main(String args[]) {
JFrame f = new JFrame();
Gui gui = new Gui();
gui.addBalls();
f.add(gui);
f.setSize(600, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Moving Ball");
f.setVisible(true);
}
}
Class GUI:
public class Gui extends JPanel implements Runnable {
private Thread animator;
int x = 0, y = 0, velX = 2, velY = 2;
Timer t;
ArrayList<myBall> myBalls = new ArrayList<>();
#Override
public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (myBall ball: myBalls) {
int x = ball.getX();
int y = ball.getY();
Ellipse2D ellipse = new Ellipse2D.Double(x, y, 40, 40);
g2.fill(ellipse);
}
}
public void cycle() {
for (myBall ball: myBalls) {
int x = ball.getX();
int y = ball.getY();
if(x < 0 || x > 560) {
ball.reverseX();
}
if(y < 0 || y > 360) {
ball.reverseY();
}
ball.move();
System.out.println(x);
}
}
#Override
public void run() {
while(true) {
for (int i = 0; i < 600; i++) {
cycle();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
}
public void addBalls() {
for (int i = 0; i < 4; i++) {
int x = (int )(Math.random() * 560);
int y = (int )(Math.random() * 360);
int velX = -5;
int velY = 5;
myBalls.add(new myBall(x, y, velX, velY));
}
}
}
Class Ball:
public class myBall {
int x;
int y;
int velX;
int velY;
public myBall(int x, int y, int velX, int velY) {
this.x = (int )(Math.random() * 560);
this.y = (int )(Math.random() * 360);
this.velX = velX;
this.velY = velY;
}
public void move() {
x+=velX;
y+=velY;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void reverseX() {
velX = -velX;
}
public void reverseY() {
velY = -velY;
}
}
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);
}
}
}
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
I am almost done with my first little java game for my final project. It is a sidescroller where you have to shoot/avoid asteroids. My last problem is figuring out how to make my array of asteroids collide with the player's lasers. Here's what I have so far, there's an "AWT-EventQueue-0" java.lang.NullPointerException" on line 137, that I can't deal with. Any help is appreciated.
Edit: I added in my other classes, I realize it would be hard to judge the functionality of my code if I didn't show you where it came from.
package ShooterGame;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
public class Board extends JPanel implements ActionListener
{
Enemy[] baddies = new Enemy[10000];
Player p;
Image img;
int y;
Timer time;
boolean lost = false;
static Font font = new Font("SanSerif", Font.BOLD, 24);
public AudioClip theme, bang, laser;
static ArrayList<Enemy> enemies;
public static int score = 0;
public static int lives = 5;
public Board()
{
p = new Player();
addKeyListener(new ActionListener());
setFocusable(true);
ImageIcon i = new ImageIcon("images/background.png");
img = i.getImage();
time = new Timer(5, this);
time.start();
for(int j = 0; j < baddies.length; j++)
{
Random ran = new Random();
y = ran.nextInt(365)+1;
baddies[j]= new Enemy((100*j + 700), y, "images/asteroid.gif");
}
theme = Applet.newAudioClip(getClass().getResource("theme.mid"));
theme.play();
bang = Applet.newAudioClip(getClass().getResource("bang.wav"));
}
public void actionPerformed(ActionEvent e)
{
checkCollisions();
ArrayList<?> bullets = Player.getBullets();
for(int i = 0; i < bullets.size(); i++)
{
Bullet b = (Bullet)bullets.get(i);
if(b.isVisible() == true)
{
b.move();
}
else
{
bullets.remove(i);
}
}
p.move();
for(int i = 0; i < baddies.length; i++)
{
if(p.x > 400)
{
baddies[i].move(p.getdx());
}
}
repaint();
}
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
if(lost)
{
g2d.drawString("You Lose!", 300, 300);
}
if((p.getX() - 590) % 2400 == 0 || (p.getX() - 590) % 2400 == 1)
{
p.nx = 0;
}
if((p.getX() - 1790) % 2400 == 0 ||(p.getX() - 1790) % 2400 == 1)
{
p.nx2 = 0;
}
g2d.drawImage(img, 685-p.nx2, 0, null);
if(p.getX() >= 590)
{
g2d.drawImage(img, 685-p.nx, 0, null);
}
g2d.drawImage(p.getImage(), p.edge, p.getY(), null);
ArrayList<?> bullets = Player.getBullets();
for(int i = 0; i < bullets.size(); i++)
{
Bullet b = (Bullet)bullets.get(i);
g2d.drawImage(b.getImg(), b.getX(), b.getY(), null);
}
for(int i = 0; i < baddies.length; i++)
{
if(baddies[i].isAlive == true)
{
g2d.drawImage(baddies[i].getImg(), baddies[i].getX(), baddies[i].getY(), null);
}
}
g2d.setColor(Color.white);
g2d.drawString("Score: " + score, 0, 320);
g2d.drawString("Lives: " + lives, 80, 320);
}
public void checkCollisions()
{
Rectangle[] rect = new Rectangle[baddies.length];
for(int i = 0; i < baddies.length; i++)
{
Enemy e = (Enemy)baddies[i];
rect[i] = e.getBounds();
}
ArrayList<?> bullets = Player.getBullets();
for (int i = 0; i < bullets.size(); i++)
{
Bullet b = (Bullet) bullets.get(i);
Rectangle b1 = b.getBounds();
if (rect[i].intersects(b1) && baddies[i].isAlive())
{
score++;
baddies[i].isAlive = false;
baddies[i].isVisible = false;
bang.play();
}
Rectangle h = p.getBounds();
if (h.intersects(rect[i]))
{
if(baddies[i].isAlive() == true)
{
lives--;
if(lives < 0)
{
lost = true;
theme.stop();
System.exit(1);
}
}
}
}
}
private class ActionListener extends KeyAdapter
{
public void keyReleased(KeyEvent e)
{
p.keyReleased(e);
}
public void keyPressed(KeyEvent e)
{
p.keyPressed(e);
}
}
}
Enemy
package ShooterGame;
import java.awt.*;
import javax.swing.ImageIcon;
public class Enemy
{
int x, y;
Image img;
boolean isAlive = true;
boolean isVisible = true;
public Enemy(int startX, int startY, String location)
{
x = startX;
y = startY;
ImageIcon l = new ImageIcon(location);
img = l.getImage();
}
public Rectangle getBounds()
{
return new Rectangle(x, y, 60, 60);
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public boolean isAlive()
{
return isAlive;
}
public boolean isVisible()
{
return isVisible;
}
public Image getImg()
{
return img;
}
public void move(int dx)
{
x = x - dx;
}
}
Bullet
package ShooterGame;
import java.applet.Applet;
import java.awt.*;
import javax.swing.ImageIcon;
import java.applet.AudioClip;
public class Bullet
{
int x, y;
Image img;
boolean visible;
public Bullet(int startX, int startY)
{
x = startX;
y = startY;
ImageIcon newBullet = new ImageIcon("images/bullet.gif");
img = newBullet.getImage();
visible = true;
}
public Rectangle getBounds()
{
return new Rectangle(x, y, 9, 5);
}
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public Image getImg()
{
return img;
}
public boolean isVisible()
{
return visible;
}
public void move()
{
x = x + 2;
if(x > 700)
{
visible = false;
}
}
public void setVisible(boolean isVisible)
{
visible = isVisible;
}
}
Player
package ShooterGame;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Player
{
int x, dx, y, dy, nx2, nx, edge, ceiling;
Image player;
ImageIcon ib = new ImageIcon("images/player1back.gif");
ImageIcon i = new ImageIcon("images/playerstill.gif");
ImageIcon f = new ImageIcon("images/playerforward.gif");
ImageIcon up = new ImageIcon("images/playerup.gif");
ImageIcon down = new ImageIcon("images/playerdown.gif");
public AudioClip laser;
static ArrayList<Bullet> bullets;
public Player()
{laser = Applet.newAudioClip(getClass().getResource("laser.wav"));
player = ib.getImage();
x = 75;
nx = 0;
nx2 = 685;
y = 172;
edge = 150;
ceiling = 0;
bullets = new ArrayList<Bullet>();
}
public static ArrayList<Bullet> getBullets()
{
return bullets;
}
public void fire()
{
Bullet z = new Bullet((edge + 60), (y+17));
bullets.add(z);
}
public Rectangle getBounds()
{
return new Rectangle(edge, y, 43, 39);
}
public void move()
{
y = y + dy;
if(y < ceiling)
{
y = ceiling;
}
if(y > 290)
{
y = 290;
}
if(dx != -1)
{
if(edge + dx <= 151)
{
edge = edge + dx;
}
else
{
x = x + dx;
nx2 = nx2 + dx;
nx = nx + dx;
}
}
else
{
if(edge + dx > 0)
{
edge = edge + dx;
}
}
}
public int getX()
{
return x;
}
public int getdx()
{
return dx;
}
public int getY()
{
return y;
}
public Image getImage()
{
return player;
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT)
{
dx = 2;
player = f.getImage();
}
if(key == KeyEvent.VK_UP)
{
dy = -1;
player = up.getImage();
}
if(key == KeyEvent.VK_DOWN)
{
dy = 1;
player = down.getImage();
}
if(key == KeyEvent.VK_SPACE)
{
fire();
laser.play();
}
}
public void keyReleased(KeyEvent e)
{
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT)
{
dx = 1;
player = ib.getImage();
}
if(key == KeyEvent.VK_UP)
{
dy = 0;
player = ib.getImage();
}
if(key == KeyEvent.VK_DOWN)
{
dy = 0;
player = ib.getImage();
}
}
}
Frame
package ShooterGame;
import javax.swing.*;
public class Frame
{
public AudioClip theme;
public Frame()
{
JFrame frame = new JFrame();
frame.add(new Board());
frame.setTitle("SideShooter");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,365);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static void main(String[] args)
{
new Frame();
}
}
Ok, so the problem is the line mentioned in the other answer, but I believe it is that all the enemies may not be initialised before it checks collisions. Because you are making 10000 of them to start with, I think your action performed method may be checking collisions before they have all be created.
One thing to try could be to bring down the amount of enemies you have and see if it still keeps happening, try 100 or 1000, but this still won't fix the issue.
You really want to be change your game to run in it's own loop though, at the moment you are only checking collisions when the player performs an action. so if the player stops moving, no collision detection...
I would suggest that you find a book called 'Killer Game Programming in Java', there are free ebook version, and just read the first 2 chapters about making a game loop. The book is a bit old, but the basics of the loop are very good.
This question here also contains a very simple loop, and some suggestions in the comments about how to make it better.
The error is on the line
rect[i] = e.getBounds();
Are you not initializing the bounds of your Enemy class correctly? Alternatively, the Enemy you pulled out of the array could be null.