God God - 7 months ago 12
Java Question

Oval collision method never called - Java Swing

I need to calculate a 2 ovals collision in a

java
swing
mini game.

I have a
JPanel
which draws my
ArrayList
of balls
Thread
's and my player ball. In the
run()
method of my non player balls i check for a collision between the player ball and the balls
Thread
ArrayList
.

The problem is my collision method is never executed. It's not even getting to my collision
if
statement. Just never calls the method.

Ball.java:

public class Ball extends Thread
{
int x;
int y;
int velocity = 1;
public int radius = 20;
public boolean directionX = true; // True - right, false - left
public boolean directionY = false; // True - up, false - down

public static final int Y_STARTING_POSITION = 0;
public static final int X_STARTING_POSITION = 0;

public Ball()
{
switch (this.getStartingSide())
{
case 0: // Left
{
this.directionX = true;
this.directionY = true;

this.x = this.getRandomHeight();
this.y = this.getRandomWidth();

break;
}

case 1: // Right
{
this.directionX = false;
this.directionY = false;

this.x = this.getRandomHeight();
this.y = this.getRandomWidth();

break;
}

case 2: // Top
{
this.directionX = true;
this.directionY = false;

this.x = this.getRandomWidth();
this.y = this.getRandomHeight();

break;
}

case 3: // Bottom
{
this.directionX = false;
this.directionY = true;

this.x = this.getRandomWidth();
this.y = this.getRandomHeight();

break;
}

}
}


public int getX()
{
return this.x;
}
public void setX(int x)
{
this.x = x;
}
public int getY()
{
return this.y;
}
public void setY(int y)
{
this.y = y;
}

public void move()
{
if (this.directionX) // Right
{
this.x += this.velocity;
}
else // Left
{
this.x -= this.velocity;
}
if (this.directionY) // Up
{
this.y -= this.velocity;
}
else // Down
{
this.y += this.velocity;
}
}

@Override
public void run()
{
try
{
this.isCollision(); // Never called
Thread.sleep(20);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}

/**
* Get a random number varies from 0 to the screen width.
*
* @return The random number.
*
*/
public int getRandomWidth()
{
Random random = new Random();
return random.nextInt((Program.getPanelWidth() - 0) + 1) + 0; // Minimum = 0,maximum = Program.panelWidth
}
/**
* Get a random number varies from 0 to the screen height.
*
* @return The random number.
*
*/
public int getRandomHeight()
{
Random random = new Random();
return random.nextInt((Program.getPanelHeight() - 0) + 1) + 0; // Minimum = 0,maximum = Program.panelHeight
}
/**
* Get the starting side of a ball.
*
* Left - 0.
* Right - 1.
* Top - 2.
* Bottom - 3.
*
* @return
*
*/
public int getStartingSide()
{
Random random = new Random();
return random.nextInt((4 - 0) + 1) + 0; // Minimum = 0,maximum = 3
}


public void isCollision()
{
System.out.println("SSSSSSSSSSSSSSSS");
if (Math.sqrt(Math.pow(MyPanel.playerX + MyPanel.playerRadius - this.getX() + this.radius,2)
+ Math.pow(MyPanel.playerY + MyPanel.playerRadius - this.getY() + this.radius,2))
<= MyPanel.playerRadius + this.radius) // A collision
{
System.exit(0);
}
}


} // End of Ball class


MyPanel.java:

public class MyPanel extends JPanel implements KeyListener
{
private static final long serialVersionUID = 1L;

private static final Color BACKGROUND_COLOR = Color.WHITE;
private static final Color NPC_BALLS_COLOR = Color.RED;

// The player is an oval
public static int playerRadius = 35;

public static int playerX;
public static int playerY;

// True - first player position, false - otherwise
private boolean playerPosition = true;

// Array of all the balls threads
public static ArrayList<Ball> balls = new ArrayList<Ball>();


public MyPanel()
{
this.setBackground(MyPanel.BACKGROUND_COLOR);
this.setFocusable(true);
this.addKeyListener(this);

new Timer(10,new UpdateUI());
}


// Drawing

@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);

final double PANEL_WIDTH = this.getWidth();
final double PANEL_HEIGHT = this.getHeight();

if (this.playerPosition)
{
MyPanel.playerX = (int)(PANEL_WIDTH / 2 - MyPanel.playerRadius);
MyPanel.playerY = (int)(PANEL_HEIGHT / 2 - MyPanel.playerRadius);
this.playerPosition = false;
}

// Drawing the player
g.setColor(Color.BLACK);
g.fillOval(playerX,playerY, MyPanel.playerRadius * 2, MyPanel.playerRadius * 2);

// Drawing npc's balls
g.setColor(MyPanel.NPC_BALLS_COLOR);
for (Ball ball: MyPanel.balls) // ConcurrentModificationException
{
if (ball.isAlive())
{
ball.start();
}

ball.move();
repaint();
g.fillOval(ball.getX(), ball.getY(),
ball.radius * 2, ball.radius * 2);
}

}

// Keyboard listeners

@Override
public void keyPressed(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_W: // Up
{
MyPanel.playerY -= 10;
repaint();
break;
}
case KeyEvent.VK_S: // Down
{
MyPanel.playerY += 10;
repaint();
break;
}
case KeyEvent.VK_D: // Right
{
MyPanel.playerX += 10;
repaint();
break;
}
case KeyEvent.VK_A: // Left
{
MyPanel.playerX -= 10;
repaint();
break;
}
}
}

@Override
public void keyReleased(KeyEvent e)
{

}

@Override
public void keyTyped(KeyEvent e)
{

}

public class UpdateUI implements ActionListener
{

@Override
public void actionPerformed(ActionEvent e)
{
repaint();
}

}






} // End of MyPanel class


Program.java:

public class Program
{
private static int panelWidth;
private static int panelHeight;

public static void main(String[] args)
{
MyFrame frame = new MyFrame();

Program.panelWidth = frame.getWidth();
Program.panelHeight = frame.getHeight();

// Generate a ball each 2 seconds
while (true)
{
try
{
MyPanel.balls.add(new Ball());


Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}

} // End of main method

public static int getPanelWidth()
{
return Program.panelWidth;
}


public static int getPanelHeight()
{
return Program.panelHeight;
}




}


The
JFrame
is nothing special and just adds the
JPanel
to it and so.

So my
isCollision()
method is never called even if It's on my
run()
method of my
Thread
. How come?

Answer

You never started the Thread implemented by your Ball class.

The ConcurrentModificationException is due to the fact that you are adding balls to an ArrayList which is by nature a thread-unsafe datastructure if you don't synchronize it externally. Here you are adding in a thread while iterating the list in the EDT (Event Dispatch Thread). Either you synchronize on the list, or you use a thread-safe data structure (for iteration you still may need to lock the full list).

Comments