Collision detection
In this part of the Java 2D games tutorial we will talk about collision detection.Many games need to handle collisions. Especially arcade games. Simply said, we need to detect when two objects collide on screen. In the next code example, we will expand the previous example. We add a new Alien sprite. We will detect two collisions. When the missile hits an alien ship and when our spacecraft collides with an alien.
Shooting aliens
In the first example we will have a spacecraft. We can move the spacecraft on the board using the cursor keys.Craft.java
package collision;This class represents a spacecraft.
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Craft {
private String craft = "craft.png";
private int dx;
private int dy;
private int x;
private int y;
private int width;
private int height;
private boolean visible;
private Image image;
private ArrayList missiles;
public Craft() {
ImageIcon ii = new ImageIcon(this.getClass().getResource(craft));
image = ii.getImage();
width = image.getWidth(null);
height = image.getHeight(null);
missiles = new ArrayList();
visible = true;
x = 40;
y = 60;
}
public void move() {
x += dx;
y += dy;
if (x < 1) {
x = 1;
}
if (y < 1) {
y = 1;
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Image getImage() {
return image;
}
public ArrayList getMissiles() {
return missiles;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public boolean isVisible() {
return visible;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
fire();
}
if (key == KeyEvent.VK_LEFT) {
dx = -1;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 1;
}
if (key == KeyEvent.VK_UP) {
dy = -1;
}
if (key == KeyEvent.VK_DOWN) {
dy = 1;
}
}
public void fire() {
missiles.add(new Missile(x + width, y + height/2));
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = 0;
}
if (key == KeyEvent.VK_RIGHT) {
dx = 0;
}
if (key == KeyEvent.VK_UP) {
dy = 0;
}
if (key == KeyEvent.VK_DOWN) {
dy = 0;
}
}
}
public Rectangle getBounds() {The getBounds() method returns the bounds of the spacecraft image. We need them in collision detection.
return new Rectangle(x, y, width, height);
}
Board.java
package collision;This is the Board class.
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Board extends JPanel implements ActionListener {
private Timer timer;
private Craft craft;
private ArrayList aliens;
private boolean ingame;
private int B_WIDTH;
private int B_HEIGHT;
private int[][] pos = {
{2380, 29}, {2500, 59}, {1380, 89},
{780, 109}, {580, 139}, {680, 239},
{790, 259}, {760, 50}, {790, 150},
{980, 209}, {560, 45}, {510, 70},
{930, 159}, {590, 80}, {530, 60},
{940, 59}, {990, 30}, {920, 200},
{900, 259}, {660, 50}, {540, 90},
{810, 220}, {860, 20}, {740, 180},
{820, 128}, {490, 170}, {700, 30}
};
public Board() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);
ingame = true;
setSize(400, 300);
craft = new Craft();
initAliens();
timer = new Timer(5, this);
timer.start();
}
public void addNotify() {
super.addNotify();
B_WIDTH = getWidth();
B_HEIGHT = getHeight();
}
public void initAliens() {
aliens = new ArrayList();
for (int i=0; i<pos.length; i++ ) {
aliens.add(new Alien(pos[i][0], pos[i][1]));
}
}
public void paint(Graphics g) {
super.paint(g);
if (ingame) {
Graphics2D g2d = (Graphics2D)g;
if (craft.isVisible())
g2d.drawImage(craft.getImage(), craft.getX(), craft.getY(),
this);
ArrayList ms = craft.getMissiles();
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile)ms.get(i);
g2d.drawImage(m.getImage(), m.getX(), m.getY(), this);
}
for (int i = 0; i < aliens.size(); i++) {
Alien a = (Alien)aliens.get(i);
if (a.isVisible())
g2d.drawImage(a.getImage(), a.getX(), a.getY(), this);
}
g2d.setColor(Color.WHITE);
g2d.drawString("Aliens left: " + aliens.size(), 5, 15);
} else {
String msg = "Game Over";
Font small = new Font("Helvetica", Font.BOLD, 14);
FontMetrics metr = this.getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString(msg, (B_WIDTH - metr.stringWidth(msg)) / 2,
B_HEIGHT / 2);
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e) {
if (aliens.size()==0) {
ingame = false;
}
ArrayList ms = craft.getMissiles();
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
if (m.isVisible())
m.move();
else ms.remove(i);
}
for (int i = 0; i < aliens.size(); i++) {
Alien a = (Alien) aliens.get(i);
if (a.isVisible())
a.move();
else aliens.remove(i);
}
craft.move();
checkCollisions();
repaint();
}
public void checkCollisions() {
Rectangle r3 = craft.getBounds();
for (int j = 0; j<aliens.size(); j++) {
Alien a = (Alien) aliens.get(j);
Rectangle r2 = a.getBounds();
if (r3.intersects(r2)) {
craft.setVisible(false);
a.setVisible(false);
ingame = false;
}
}
ArrayList ms = craft.getMissiles();
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
Rectangle r1 = m.getBounds();
for (int j = 0; j<aliens.size(); j++) {
Alien a = (Alien) aliens.get(j);
Rectangle r2 = a.getBounds();
if (r1.intersects(r2)) {
m.setVisible(false);
a.setVisible(false);
}
}
}
}
private class TAdapter extends KeyAdapter {
public void keyReleased(KeyEvent e) {
craft.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
craft.keyPressed(e);
}
}
}
private int[][] pos = {These are initial positions of alien ships.
{2380, 29}, {2500, 59}, {1380, 89},
{780, 109}, {580, 139}, {680, 239},
{790, 259}, {760, 50}, {790, 150},
{980, 209}, {560, 45}, {510, 70},
{930, 159}, {590, 80}, {530, 60},
{940, 59}, {990, 30}, {920, 200},
{900, 259}, {660, 50}, {540, 90},
{810, 220}, {860, 20}, {740, 180},
{820, 128}, {490, 170}, {700, 30}
};
for (int i = 0; i < aliens.size(); i++) {The paint() method draws all aliens from the aliens ArrayList. They are drawn only if they have not been previously destroyed. This is checked by the isVisible() method.
Alien a = (Alien)aliens.get(i);
if (a.isVisible())
g2d.drawImage(a.getImage(), a.getX(), a.getY(), this);
}
if (aliens.size()==0) {If we destroy all alien ships, the game is finished.
ingame = false;
}
ArrayList ms = craft.getMissiles();Here we check, if any of the missiles intersects with any of the aliens. If they do, both the missile and the alien are destroyed.
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
Rectangle r1 = m.getBounds();
for (int j = 0; j<aliens.size(); j++) {
Alien a = (Alien) aliens.get(j);
Rectangle r2 = a.getBounds();
if (r1.intersects(r2)) {
m.setVisible(false);
a.setVisible(false);
}
}
}
Alien.java
package collision;This is the Alien class.
import java.awt.Image;
import java.awt.Rectangle;
import javax.swing.ImageIcon;
public class Alien {
private String craft = "alien.png";
private int x;
private int y;
private int width;
private int height;
private boolean visible;
private Image image;
public Alien(int x, int y) {
ImageIcon ii = new ImageIcon(this.getClass().getResource(craft));
image = ii.getImage();
width = image.getWidth(null);
height = image.getHeight(null);
visible = true;
this.x = x;
this.y = y;
}
public void move() {
if (x < 0)
x = 400;
x -= 1;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isVisible() {
return visible;
}
public void setVisible(Boolean visible) {
this.visible = visible;
}
public Image getImage() {
return image;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
}
public void move() {Aliens return to the screen, after they have disappeared on the left.
if (x < 0)
x = 400;
x -= 1;
}
Missile.java
package collision;This is the Missile class.
import java.awt.Image;
import java.awt.Rectangle;
import javax.swing.ImageIcon;
public class Missile {
private int x, y;
private Image image;
boolean visible;
private int width, height;
private final int BOARD_WIDTH = 390;
private final int MISSILE_SPEED = 2;
public Missile(int x, int y) {
ImageIcon ii =
new ImageIcon(this.getClass().getResource("missile.png"));
image = ii.getImage();
visible = true;
width = image.getWidth(null);
height = image.getHeight(null);
this.x = x;
this.y = y;
}
public Image getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public boolean isVisible() {
return visible;
}
public void setVisible(Boolean visible) {
this.visible = visible;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
public void move() {
x += MISSILE_SPEED;
if (x > BOARD_WIDTH)
visible = false;
}
}
Collision.java
package collision;Finally, this is the main class.
import javax.swing.JFrame;
public class Collision extends JFrame {
public Collision() {
add(new Board());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
setLocationRelativeTo(null);
setTitle("Collision");
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
new Collision();
}
}
Figure: Shooting aliens
This chapter was about collision detection.
0 comments:
Post a Comment