I just made my first game in java, but the collision detection completely sucks. Does anyone have an idea on how to fix it? I've tried multiple things already but none of them worked. I've the rocks come from above the player they get detected, but if the player hits them sideways they don't hit him.
public void checkRock(){
if((x == rockX && y == rockY) || (x==rockX && y 1 ==rockY) || (x==rockX && y 2 ==rockY)){
running = false;
}
else if((x 1 == rockX && y == rockY) || (x 1==rockX && y 1 ==rockY) || (x 1==rockX && y 2 ==rockY)){
running = false;
}
if(!running){
timer.stop();
}
}
Full code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.AttributeSet.ColorAttribute;
import java.util.Random;
import java.util.random.*;
public class GamePanel extends JPanel implements ActionListener{
static final int SCREEN_WIDTH = 600;
static final int SCREEN_HEIGHT = 600;
static final int UNIT_SIZE = 25;
static final int GAME_UNITS = (SCREEN_HEIGHT*SCREEN_WIDTH)/UNIT_SIZE;
static final int DELAY = 75;
int x = 0;
int y = SCREEN_HEIGHT-(UNIT_SIZE*3);
int rocksFallen;
int rockX;
int rockY = 0;
char direction = 'R';
char directionRock = 'D';
boolean running = false;
Timer timer;
Random random;
GamePanel(){
random = new Random();
this.setPreferredSize(new Dimension(SCREEN_WIDTH,SCREEN_HEIGHT));
this.setBackground(Color.BLACK);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
}
public void startGame(){
newRock();
running = true;
timer = new Timer(DELAY,this);
timer.start();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g){
if(running){
for(int i = 0;i<SCREEN_HEIGHT/UNIT_SIZE;i ){
g.drawLine(i*UNIT_SIZE, 0, i*UNIT_SIZE, SCREEN_HEIGHT);
g.drawLine(0, i*UNIT_SIZE, SCREEN_WIDTH, i*UNIT_SIZE);
}
g.setColor(Color.red);
g.fillOval(rockX, rockY, UNIT_SIZE, UNIT_SIZE);
g.setColor(Color.green);
g.fillRect(x, y, UNIT_SIZE*2, UNIT_SIZE*3);
}
else{
gameOver(g);
}
}
public void newRock(){
rockX = random.nextInt((int)(SCREEN_WIDTH/UNIT_SIZE))*UNIT_SIZE;
rockY = 0;
}
public void move(){
switch (direction){
case 'R':
if (x<SCREEN_WIDTH-(UNIT_SIZE*2)){
x = x UNIT_SIZE;
}
break;
case 'L':
if (x>0){
x = x-UNIT_SIZE;
}
break;
}
if(directionRock=='D'){
rockY = rockY UNIT_SIZE;
}
}
public void checkRock(){
if((x == rockX && y == rockY) || (x==rockX && y 1 ==rockY) || (x==rockX && y 2 ==rockY)){
running = false;
}
else if((x 1 == rockX && y == rockY) || (x 1==rockX && y 1 ==rockY) || (x 1==rockX && y 2 ==rockY)){
running = false;
}
if(!running){
timer.stop();
}
}
public void checkCollisions(){
if(rockY>SCREEN_HEIGHT){
newRock();
rocksFallen ;
}
}
public void gameOver(Graphics g){
g.setColor(Color.red);
g.setFont(new Font("Ink Free",Font.BOLD,75));
FontMetrics metrics = getFontMetrics(g.getFont());
g.drawString("Game Over", (SCREEN_WIDTH-metrics.stringWidth("Game OVer"))/2, SCREEN_HEIGHT/2);
}
@Override
public void actionPerformed(ActionEvent e){
if(running){
move();
checkRock();
checkCollisions();
}
repaint();
}
public class MyKeyAdapter extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e){
switch (e.getKeyCode()){
case KeyEvent.VK_LEFT:
direction = 'L';
break;
case KeyEvent.VK_RIGHT:
direction = 'R';
break;
}
}
}
}
GameFrame code:
import javax.swing.*;
import javax.swing.text.AttributeSet.ColorAttribute;
import java.util.Random;
import java.util.random.*;
public class GameFrame extends JFrame{
GameFrame(){
this.add(new GamePanel());
this.setTitle("FlyingRocks");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.pack();
this.setVisible(true);
this.setLocationRelativeTo(null);
}
}
Main Code:
public class Game extends JFrame{
public static void main(String[] args) {
new GameFrame();
}
}
CodePudding user response:
As proposed by camickr use Shape
for easy collision detection.
The following is a one-file mre (copy paste the entire code into ShapesCollision.java
and run) of a basic implementation of it:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Ellipse2D;
import java.util.*;
import java.util.List;
import javax.swing.Timer;
import javax.swing.*;
public class ShapesCollision extends JPanel implements ActionListener {
private final static int H = 350, W = 400, RATE = 30;
private final static Color BG = Color.DARK_GRAY;
private final static Color[] SHAPE_COLORS ={Color.RED, Color.BLUE};//to have more balls, add more colors
private final List<Ball> balls;
private final Dimension size;
public ShapesCollision() {
Random rnd = new Random();
balls = new ArrayList<>();
for(Color color : SHAPE_COLORS){
//todo check that added shape does not overlap previous ones
balls.add(new Ball(color,rnd.nextInt(W), rnd.nextInt(H)));
}
Timer timer = new Timer(RATE,this);
timer.start();
size = new Dimension(W,H);
setBackground(BG);
setVisible(true);
}
@Override
public void paintComponent(Graphics g) { //for custom painting override paintComponent, not paint
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
for(Ball ball : balls){
g2D.setColor(ball.getColor());
g2D.draw(ball);
g2D.fill(ball);
}
}
public static void main(String[] args) {
JFrame myFrame = new JFrame("Colliding Shapes");
myFrame.setLocationByPlatform(true);;
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.add(new ShapesCollision());
myFrame.pack();
myFrame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
checkCollision();
horizontalMove();
verticalMove();
repaint();
}
private void checkCollision() {
for(Ball ball1 : balls){
for(Ball ball2 : balls){
if(ball1 == ball2) {
continue;
}
if(ball1.intersects(ball2.getBounds2D())){
changeHorizontalDirection(ball1);
changeVerticalDirection(ball1);
changeHorizontalDirection(ball2);
changeVerticalDirection(ball2);
repaint();//optional
}
}
}
}
private void horizontalMove() {
for(Ball ball : balls){
double maxX = ball.getBounds().getMaxX();
if(ball.isMovingRight()){
if(maxX < getWidth() || ball.x <= 0){
ball.x = ball.getSpeed(); //keep moving right
continue;
}
}
if(!ball.isMovingRight()){
if(ball.x > 0 || maxX >= getWidth()){
ball.x -= ball.getSpeed();//keep moving left
continue;
}
}
changeHorizontalDirection(ball);
}
}
private void verticalMove() {
for(Ball ball : balls){
double maxY = ball.getBounds().getMaxY();
if(ball.isMovingDown()){
if(maxY<getHeight() || ball.y <=0){
ball.y = ball.getSpeed(); //keep moving down
continue;
}
}
if(!ball.isMovingDown()){
//ball is moving up
if(ball.y > 0 || ball.y >= maxY){
ball.y -= ball.getSpeed();//keep moving up
continue;
}
}
changeVerticalDirection(ball);
}
}
private void changeHorizontalDirection(Ball ball){
ball.setMovingRight(! ball.isMovingRight());
ball.x = ball.isMovingRight() ? ball.x ball.getSpeed() : ball.x - ball.getSpeed();
}
private void changeVerticalDirection(Ball ball){
ball.setMovingDown(! ball.isMovingDown());
ball.y = ball.isMovingDown() ? ball.y ball.getSpeed() : ball.y - ball.getSpeed();
}
@Override
public Dimension preferredSize() {
return size;
}
}
class Ball extends Ellipse2D.Double{
private static final int SPEED = 10, SHAPE_SIZE = 40;
private Color color;
private int speed;
private boolean isMovingRight, isMovingDown;
public Ball(Color color, int x, int y) {
super(x,y,SHAPE_SIZE, SHAPE_SIZE);
this.color = color;
Random rnd = new Random();
isMovingRight = rnd.nextBoolean();
isMovingDown = rnd.nextBoolean();
speed = SPEED;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public boolean isMovingRight() {
return isMovingRight;
}
public void setMovingRight(boolean isMovingRight) {
this.isMovingRight = isMovingRight;
}
public boolean isMovingDown() {
return isMovingDown;
}
public void setMovingDown(boolean isMovingDown) {
this.isMovingDown = isMovingDown;
}
}
Run it online here