I'm building a very simple Java game where a player rectangle fires bullet rectangles at enemy rectangles. When a single bullet is on screen, it always correctly collides with enemies. When multiple bullets are on screen, they often go right through the enemies without triggering a collision. The only way to get the collision to work is to run very far away from the enemy; if the bullet travels a very far distance before hitting the enemy, the collision will work with multiple bullets on screen.
I tried writing a method to calculate a new rectangle that extends the colliding sprites' previous location to its current location, and then checking these extended rectangles for collisions, but to no avail.
Below are the methods I'm using in the sprite parent class to create these extended rectangles and to check for intersection:
public boolean movingIntersects(GameEntity g) {
return this.getMovingRectangle().intersects(g.getMovingRectangle());
}
public Rectangle getMovingRectangle() {
Rectangle r = new Rectangle();
r.x = Math.min(x, prevX);
r.y = Math.min(y, prevY);
r.width = Math.abs(x - prevX) + width;
r.height = Math.abs(y - prevY) + height;
//System.out.println(this + " " + r);
return r;
}
This is the code I'm using in the actionPerformed
method to handle moving and managing the sprites. Variable p is the player, keys holds the keys being pressed, tm holds the Timer that triggers the actionPerformed:
public void actionPerformed(ActionEvent e) {
// pause game if necessary
if (keys.contains(KeyEvent.VK_ESCAPE)) {
paused = !paused;
keys.remove(KeyEvent.VK_ESCAPE);
}
if (!paused) {
// Setup player movement
p.movement = 0;
if (keys.contains(KeyEvent.VK_W)) {
p.movement |= GameEntity.UP;
}
if (keys.contains(KeyEvent.VK_S)) {
p.movement |= GameEntity.DOWN;
}
if (keys.contains(KeyEvent.VK_A)) {
p.movement |= GameEntity.LEFT;
}
if (keys.contains(KeyEvent.VK_D)) {
p.movement |= GameEntity.RIGHT;
}
// Setup bullets
p.framesToNextFire = Math.max(0, --p.framesToNextFire);
if (p.framesToNextFire == 0) {
Bullet b = new Bullet(this, 0, 0, 0, p.bulletSpeed);
b.x = p.x + (p.width / 2) - (b.width / 2);
b.y = p.y + (p.height / 2) - (b.height / 2);
if (keys.contains(KeyEvent.VK_UP)) {
b.movement = GameEntity.UP;
p.bullets.add(b);
p.framesToNextFire = p.coolDown;
} else if (keys.contains(KeyEvent.VK_DOWN)) {
b.movement = GameEntity.DOWN;
p.bullets.add(b);
p.framesToNextFire = p.coolDown;
} else if (keys.contains(KeyEvent.VK_LEFT)) {
b.movement = GameEntity.LEFT;
p.bullets.add(b);
p.framesToNextFire = p.coolDown;
} else if (keys.contains(KeyEvent.VK_RIGHT)) {
b.movement = GameEntity.RIGHT;
p.bullets.add(b);
p.framesToNextFire = p.coolDown;
}
}
// Move GameEntities
if (enemies.size() > 0) {
// move player
p.move(GameEntity.CONSTRAIN);
// move enemies
for (Enemy en : enemies) {
en.move(GameEntity.CONSTRAIN);
}
// move bullets
Iterator<Bullet> itB = p.bullets.iterator();
while (itB.hasNext()) {
Bullet b = itB.next();
//System.out.println(b.x + ":" + b.y);
if (b.move(GameEntity.REMOVE)) {
itB.remove();
}
}
// Check for shot enemies
itB = p.bullets.iterator();
Iterator<Enemy> itE = enemies.iterator();
while (itB.hasNext()) {
Bullet b = itB.next();
while (itE.hasNext()) {
Enemy m = itE.next();
if (b.movingIntersects(m)) {
m.health -= b.health;
itB.remove();
if (m.health <= 0) {
int points = (int) (m.intelligence * m.speed * 100);
System.out.println(m.intelligence + " + " + m.speed + " = " + points);
score += points;
itE.remove();
}
break;
}
}
}
// Check for dead player
itE = enemies.iterator();
while (itE.hasNext()) {
Enemy m = itE.next();
if (m.intersects(p)) {
// Player is dead
tm.stop();
// Show score
message = "Game Over";
paused = true;
// Reset game
level = 1;
score = 0;
startLevel();
tm.start();
break;
}
}
// Draw the screen
repaint();
} else {
tm.stop();
p.bullets.clear();
repaint();
level++;
startLevel();
tm.start();
}
}
}