Oval collision method never called - Java Swing - java

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?

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).
Have a look at Collections.synchronizedList or CopyOnWriteArrayList (the latter doesn't need synchronizing for iteration).
However, synchronization on each insertion and each iteration seems very inefficient to me, especially because you are aiming for a game which requires fast rendering and background processing. It may be sufficient for a basic game though.
As a sidenote: a better technique for a game would be to use double buffering: render the game graphics in a background thread e.g. on a BufferedImage, and when done, switch the two buffers so that the one you just drew is now displayed on screen, and the other one can be used again for drawing the next frame. You might need a synchronization checkpoint between frames. But this is slightly more advanced, so if you are just starting in Java, I wouldn't spend too much time on it and keep things simple.

You need to call the repaint method in your while loop in the main method so run() can be called. You can do it with this:
panel.repaint():
Also, You must call the run method. You can do it in ball or in the panel.

ball.isAlive() always return false bucause your thread has not been started. If you want to start your threads in paintComponent() method you shouldn't use this method.
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;
private boolean ballsStarted;
// 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 (!ballsStarted)
{
ball.start();
}
ball.move();
repaint();
g.fillOval(ball.getX(), ball.getY(),
ball.radius * 2, ball.radius * 2);
}
ballsStarted = true;
}
// 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();
}
}
}

Related

How do I paint multiple objetcs that move at different speeds in Java?

I am working on homework for class, and its late because I can't seem to understand the material despite all the research that I am doing. I am a beginner and do not know much in the way of java. Also, this is my first post so please be forgiving when you are reading this.
I am building on source code from my textbook, which I updated recently for past homework, but now I am trying to generate a class that draws multiple squares and moves those objects independently and at different speeds. They will all need to rebound off the walls as well. I followed the instructions and created two arrays that will hold the random x and y values between 1 and 10. However, I struggle with arrays and I am sure that I am not doing it correctly. So, I would love some feedback to see if I have it set up correctly.
I have a the jpanel pulling up and drawing, and as long as there is 1 square it is working fine bouncing off the walls, but things change when I draw more than one. The do not move independently and they also share the same speed. Some even disappear from time to time. This has really thrown me off. I appreciate any help!
In short, I am trying to paint new squares that all travel in different directions and at different speeds. Per the instructions we are suppose create and use a two arrays that handle the x and y values.
Here is what I have so far:
public class DotsPanel extends JPanel
{
private int delay = 15;
private final int SIZE = 7, IMAGE_SIZE = 3; // radius of each dot
private Timer timer;
private int x, y, i;
private ArrayList<Point> pointList;
static int [] xarray = new int [1000];
static int [] yarray = new int [1000];
Random rand = new Random();
//-----------------------------------------------------------------
// Constructor: Sets up this panel to listen for mouse events.
//-----------------------------------------------------------------
public DotsPanel()
{
pointList = new ArrayList<Point>();
int [] xarray = new int [1000];
int [] yarray = new int [1000];
timer = new Timer(delay, new ReboundListener());
addMouseListener (new DotsListener());
addMouseMotionListener (new DotsListener());
setBackground(Color.gray);
setPreferredSize(new Dimension(700, 500));
for(int i = 0; i < xarray.length; i++)
{
xarray[i] = rand.nextInt(7);
yarray[i] = rand.nextInt(7);
}
timer.start();
}
//-----------------------------------------------------------------
// Draws all of the dots stored in the list.
//-----------------------------------------------------------------
public void paintComponent(Graphics page)
{
super.paintComponent(page);
page.setColor(Color.BLUE);
for (Point spot : pointList)
{
page.fillRect(spot.x-SIZE, spot.y-SIZE, 25, 25);
page.drawString("Count: " + pointList.size(), 5, 15);
}
}
//*****************************************************************
// Represents the listener for mouse events.
//*****************************************************************
private class DotsListener implements MouseListener, MouseMotionListener
{
//--------------------------------------------------------------
// Adds the current point to the list of points and redraws
// the panel whenever the mouse button is pressed.
//--------------------------------------------------------------
public void mousePressed(MouseEvent event)
{
pointList.add(event.getPoint());
repaint();
}
public void mouseDragged(MouseEvent event)
{
// initially I had two xarray and yarray in here just like in
// mouseClicked
// but it did not change anything when removed
}
//--------------------------------------------------------------
// Provide empty definitions for unused event methods.
//--------------------------------------------------------------
public void mouseClicked(MouseEvent event)
{
xarray[i] = rand.nextInt(7);
yarray[i] = rand.nextInt(7);
}
public void mouseReleased(MouseEvent event) {}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}
public void mouseMoved(MouseEvent e) {}
}
private class ReboundListener implements ActionListener
{
//--------------------------------------------------------------
// Updates the position of the image and possibly the direction
// of movement whenever the timer fires an action event.
//--------------------------------------------------------------
public void actionPerformed(ActionEvent event)
{
for (Point spot : pointList)
{
spot.x += xarray[i];
spot.y += yarray[i];
if (spot.x <= 0 || spot.x >= 700)
xarray[i] = xarray[i] * -1;
if (spot.y <= 0 || spot.y >= 500)
yarray[i] = yarray[i] * -1;
repaint();
}
}
}
}
However, I struggle with arrays and I am sure that I am not doing it correctly.
I wouldn't use Arrays.
Instead, have a Ball object manage its own state. Then you can have different color, speed, size etc for each Ball. Then when the Timer fires you just calculate the new position and repaint the Ball.
Here is an example to get you started:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class BallAnimation4
{
private static void createAndShowUI()
{
BallPanel panel = new BallPanel();
JFrame frame = new JFrame("BallAnimation4");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.setSize(800, 600);
frame.setLocationRelativeTo( null );
//frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setVisible( true );
panel.addBalls(5);
panel.startAnimation();
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
class BallPanel extends JPanel implements ActionListener
{
private ArrayList<Ball> balls = new ArrayList<Ball>();
public BallPanel()
{
setLayout( null );
setBackground( Color.BLACK );
}
public void addBalls(int ballCount)
{
Random random = new Random();
for (int i = 0; i < ballCount; i++)
{
Ball ball = new Ball();
ball.setRandomColor(true);
ball.setLocation(random.nextInt(getWidth()), random.nextInt(getHeight()));
ball.setMoveRate(32, 32, 1, 1, true);
// ball.setMoveRate(16, 16, 1, 1, true);
ball.setSize(32, 32);
balls.add( ball );
}
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for (Ball ball: balls)
{
ball.draw(g);
}
}
public void startAnimation()
{
Timer timer = new Timer(75, this);
timer.start();
}
public void actionPerformed(ActionEvent e)
{
move();
repaint();
}
private void move()
{
for (Ball ball : balls)
{
ball.move(this);
}
}
class Ball
{
public Color color = Color.BLACK;
public int x = 0;
public int y = 0;
public int width = 1;
public int height = 1;
private int moveX = 1;
private int moveY = 1;
private int directionX = 1;
private int directionY = 1;
private int xScale = moveX;
private int yScale = moveY;
private boolean randomMove = false;
private boolean randomColor = false;
private Random myRand = null;
public Ball()
{
myRand = new Random();
setRandomColor(randomColor);
}
public void move(JPanel parent)
{
int iRight = parent.getSize().width;
int iBottom = parent.getSize().height;
x += 5 + (xScale * directionX);
y += 5 + (yScale * directionY);
if (x <= 0)
{
x = 0;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (x >= iRight - width)
{
x = iRight - width;
directionX *= (-1);
xScale = randomMove ? myRand.nextInt(moveX) : moveX;
if (randomColor) setRandomColor(randomColor);
}
if (y <= 0)
{
y = 0;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
if (y >= iBottom - height)
{
y = iBottom - height;
directionY *= (-1);
yScale = randomMove ? myRand.nextInt(moveY) : moveY;
if (randomColor) setRandomColor(randomColor);
}
}
public void draw(Graphics g)
{
g.setColor(color);
g.fillOval(x, y, width, height);
}
public void setColor(Color c)
{
color = c;
}
public void setLocation(int x, int y)
{
this.x = x;
this.y = y;
}
public void setMoveRate(int xMove, int yMove, int xDir, int yDir, boolean randMove)
{
this.moveX = xMove;
this.moveY = yMove;
directionX = xDir;
directionY = yDir;
randomMove = randMove;
}
public void setRandomColor(boolean randomColor)
{
this.randomColor = randomColor;
switch (myRand.nextInt(3))
{
case 0: color = Color.BLUE;
break;
case 1: color = Color.GREEN;
break;
case 2: color = Color.RED;
break;
default: color = Color.BLACK;
break;
}
}
public void setSize(int width, int height)
{
this.width = width;
this.height = height;
}
}
}
Since your Arrays only contain the Point you want to paint you don't have any information about the speed each point should be moved at. The best you could do is create a random amount each point should be moved each time its location is changed. This would give erratic movement as each time you move a point the distance would be random.
If you want more constant speed then you would need to create a second Array to contain the distance each point should move every time.
This starts to get messy creating a new Array every time you want a new property to be unique for the object you want to paint. That is why the approach to create a custom Object with multiple properties is easier to manage.

How to return Instance Variables for objects in an array

I am new to graphics in java and I am currently working on a game. Essentially, there are rising bubbles, and the user has to pop them by moving the mouse over them.
I have already made the bubbles but now for the collision detection, I need to be able to find the x and coordinates as well as the diameter of the circle. How can I return the instance variables for each bubble (from the Bubbles object array). You can see my code below. If you find coding errors, please let me know.
Game Class:
public class Game extends JPanel{
public static final int WINDOW_WIDTH = 600;
public static final int WINDOW_HEIGHT = 400;
private boolean insideCircle = false;
private static boolean ifPaused = false;
private static JPanel mainPanel;
private static JLabel statusbar;
private static int clicks = 0;
//Creates a Bubbles object Array
Bubbles[] BubblesArray = new Bubbles[5];
public Game() {
//initializes bubble objects
for (int i = 0; i < BubblesArray.length; i++)
BubblesArray[i] = new Bubbles();
}
public void paint(Graphics graphics) {
//makes background white
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
//paints square objects to the screen
for (Bubbles aBubblesArray : BubblesArray) {
aBubblesArray.paint(graphics);
}
}
public void update() {
//calls the Square class update method on the square objects
for (Bubbles aBubblesArray : BubblesArray) aBubblesArray.update();
}
public static void main(String[] args) throws InterruptedException {
statusbar = new JLabel("Default");
Game game = new Game();
game.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
statusbar.setText(String.format("Your mouse is at %d, %d", e.getX(), e.getY()));
}
public void mouseExited(MouseEvent e){
ifPaused = true;
}
public void mouseEntered(MouseEvent e){
ifPaused = false;
}
});
JFrame frame = new JFrame();
frame.add(game);
frame.add(statusbar, BorderLayout.SOUTH);
frame.setVisible(true);
frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Bubble Burst");
frame.setResizable(false);
frame.setLocationRelativeTo(null);
while (true) {
if (!ifPaused){
game.update();
game.repaint();
Thread.sleep(5);
}
}
}
}
Bubbles Class:
public class Bubbles{
private int circleXLocation;
private int circleSize;
private int circleYLocation = Game.WINDOW_WIDTH + circleSize;
private int fallSpeed = 1;
private int color = (int) (4 * Math.random() + 1);
Random rand = new Random();
private int whereMouseX;
private int whereMouseY;
public int generateRandomXLocation(){
return circleXLocation = (int) (Game.WINDOW_WIDTH * Math.random() - circleSize);
}
public int generateRandomCircleSize(){
return circleSize = (int) (50 * Math.random() + 30);
}
public int generateRandomFallSpeed(){
return fallSpeed = (int) (5 * Math.random() + 1);
}
public void paint(Graphics g){
if (color == 1) g.setColor(new Color(0x87CEEB));
if (color == 2) g.setColor(new Color(0x87CEFF));
if (color == 3) g.setColor(new Color(0x7EC0EE));
if (color == 4) g.setColor(new Color(0x6CA6CD));
g.fillOval (circleXLocation, circleYLocation, circleSize, circleSize);
}
public Bubbles(){
generateRandomXLocation();
generateRandomCircleSize();
generateRandomFallSpeed();
}
public void update(){
if (circleYLocation <= - circleSize){
generateRandomXLocation();
generateRandomFallSpeed();
generateRandomCircleSize();
circleYLocation = Game.WINDOW_HEIGHT + circleSize;
}
if (circleYLocation > - circleSize){
circleYLocation -= fallSpeed;
}
}
public int getX(){
return circleXLocation;
}
public int getY(){
return circleYLocation;
}
public int getCircleSize(){
return circleSize;
}
}
Set your bubbles to include x and y values in it's constructor.
Public Bubble(float x, float y, int circleSize){
// initialize variables here
}
Then check to see if they are colliding with your current mouse location, something like...
if(e.getX() == this.getX() && e.getY() == this.getY()){
// do something
}
Loop through each Bubble in the array and access the public get methods you have created in the Bubble class:
Example:
for (Bubble b : BubblesArray)
{
int x = b.getX();
int y = b.getY();
}

Java Swing - paintComponent() not drawing my Threads

I want to add to an ArrayList of Thread's which represent a ball with (x,y) coordinated and a move() method a new ball Thread every 5 seconds.
So my JPanel implements Runnable and in there i add to the ArrayList a new ball Thread.
In the paintComponent() method i use foreach loop to iterate the ArrayList of ball Thread's and start their Thread which moves them and call for repaint(). Problem is i i don't see any drawing at all(Only the player drawing).
MyPanel.java:
public class MyPanel extends JPanel implements KeyListener,Runnable
{
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
private int playerRadius = 20;
private int playerX;
private int playerY;
// True - first player position, false - otherwise
private boolean playerPosition = true;
// Array of all the balls threads
private ArrayList<BallThread> balls = new ArrayList<BallThread>();
private Thread generateBallsThread;
public MyPanel()
{
this.setBackground(MyPanel.BACKGROUND_COLOR);
this.setFocusable(true);
this.addKeyListener(this);
this.generateBallsThread = new Thread();
generateBallsThread.start();
}
// 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)
{
this.playerX = (int)(PANEL_WIDTH / 2 - this.playerRadius);
this.playerY = (int)(PANEL_HEIGHT / 2 - this.playerRadius);
this.playerPosition = false;
}
// Drawing the player
g.setColor(Color.BLACK);
g.fillOval(playerX,playerY, this.playerRadius * 2, this.playerRadius * 2);
// Drawing npc's balls
g.setColor(MyPanel.NPC_BALLS_COLOR);
for (BallThread ball: this.balls)
{
ball.start();
g.fillOval(ball.getBall().getX(), ball.getBall().getY(),
ball.getBall().radius, ball.getBall().radius);
repaint();
}
}
// Keyboard listeners
#Override
public void keyPressed(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_W: // Up
{
this.playerY -= 5;
repaint();
break;
}
case KeyEvent.VK_S: // Down
{
this.playerY += 5;
repaint();
break;
}
case KeyEvent.VK_D: // Right
{
this.playerX += 5;
repaint();
break;
}
case KeyEvent.VK_A: // Left
{
this.playerX -= 5;
repaint();
break;
}
}
}
#Override
public void keyReleased(KeyEvent e)
{
}
#Override
public void keyTyped(KeyEvent e)
{
}
public int getBallXStartingPositionFromTop()
{
return (int) Math.random() * 101; // 0 - 100
}
//public int getBallYStartingPositionFromLeft()
//{
// return (int) Math.random() * 101; // 0 - 100
//}
/**
*
*
*
* Class for the balls threads.
*
*/
public class BallThread extends Thread
{
private Ball ball;
public BallThread(Ball ball)
{
this.ball.setX(ball.getX());
this.ball.setY(ball.getY());
}
#Override
public void run()
{
try
{
this.ball.move();
Thread.sleep(4000);
repaint(); // Execute paintComponent() method
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public Ball getBall()
{
return this.ball;
}
public void setBall(Ball ball)
{
this.ball = ball;
}
}
#Override
public void run()
{
try
{
Thread.sleep(5000); // 5 seconds
this.balls.add(new BallThread(new Ball(20,20)));
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
} // End of MyPanel class
Ball.java:
public class Ball
{
int x;
int y;
int velocity = 1;
public int radius = 10;
public boolean directionX = true; // True - right, false - left
public boolean directionY = false; // True - up, false - down
public static final int Y_STARTING_POSITION_FROM_TOP = 0;
public Ball(int x, int y)
{
this.x = x;
this.y = y;
}
public Ball()
{
}
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
{
this.y += this.velocity;
}
}
}
And i omitted a simple JFrame class and a main() who generates the JFrame with the JPanel added to it.
Any ideas why i don't get to see the drawing of the ball Thread's?
this.generateBallsThread = new Thread();
generateBallsThread.start();
That does nothing. It is an empty Thread with no logic.
I think you want
this.generateBallsThread = new BallsThread();
generateBallThread.start();
Also, you should not be using a Thread for animation. You should be using a Swing Timer. Any logic that updates the state of a Swing component should be executed on the Event Dispatch Thread. Read the section from the Swing tutorial on Concurrency for more information. The tutorial also has a section on How to Use Swing Timers.

Java 2D Game adding bombs

I'm very new to game design (this is my first attempt) and this project will be used to create an android game.
I'm trying to make a simple game (as simple as possible).
What I need:
A background
a ship (that can move left an right at the bottom of the screen)
Enemies (Bombs dropping down from the sky)
projectiles (to shoot bombs with, shoot straight up)
Score (in the upper corner)
I have studied this tutorial:
http://www.kilobolt.com/game-development-tutorial.html
and changed code to get this:
http://i297.photobucket.com/albums/mm231/mabee84/Battleship.png
the black rectangles are projectiles.
Now I need to create the bombs but I can't figure out how to implement them.
they need to spawn at fixed y-value and a random x-value (within the screen)
Upon shooting on the bombs they should die but if bombs hit the ship game is over.
Please help i'm a bit stuck.
package kiloboltgame;
import java.applet.Applet;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URL;
import java.util.ArrayList;
public class StartingClass extends Applet implements Runnable, KeyListener {
private Ship ship;
public static Bomb b1, b2;
public static int score = 0;
private Font font = new Font(null, Font.BOLD, 30);
private Image image, Battleship, Background, Bomb;
private static Background bg1, bg2;
private URL base;
private Graphics second;
#Override
public void init() {
setSize(800, 480);
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
Frame frame = (Frame) this.getParent().getParent();
frame.setTitle("BattleShip");
try{
base = getDocumentBase();
}catch (Exception e){
//TODO: handle exception
}
//Image Setups
Battleship = getImage(base, "data/Battleship.png");
Background = getImage(base, "data/Background.png");
Bomb = getImage(base, "data/Bomb1.png");
}
#Override
public void start() {
bg1 = new Background(0, 0);
bg2 = new Background(800, 0);
ship = new Ship();
b1 = new Bomb(340, 100);
b2 = new Bomb(700, 100);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void stop() {
// TODO Auto-generated method stub
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void run() {
while (true) {
ship.update();
ArrayList projectiles = ship.getProjectiles();
for(int i = 0; i < projectiles.size(); i++){
Projectile p = (Projectile) projectiles.get(i);
if(p.isVisible() == true){
p.update();
}else{
projectiles.remove(i);
}
}
b1.update();
b2.update();
bg1.update();
bg2.update();
repaint();
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void update(Graphics g) {
if(image == null){
image = createImage(this.getWidth(), this.getHeight());
second = image.getGraphics();
}
second.setColor(getBackground());
second.fillRect(0, 0, getWidth(), getHeight());
second.setColor(getForeground());
paint(second);
g.drawImage(image, 0, 0, this);
}
#Override
public void paint(Graphics g) {
g.drawImage(Background, bg1.getBgX(), bg1.getBgY(), this);
ArrayList projectiles = ship.getProjectiles();
for(int i = 0; i < projectiles.size(); i++){
Projectile p = (Projectile) projectiles.get(i);
g.setColor(Color.BLACK);
g.fillRect(p.getX(), p.getY(), 5, 10);
}
g.drawImage(Battleship, ship.getCenterX() + 230, ship.getCenterY() -23, this);
g.drawImage(Bomb, b1.getCenterX() - 20, b1.getCenterY() - 20, this);
g.drawImage(Bomb, b2.getCenterX() - 20, b2.getCenterY() - 20, this);
g.setFont(font);
g.setColor(Color.BLACK);
g.drawString(Integer.toString(score), 710, 30);
}
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_LEFT:
ship.moveLeft();
break;
case KeyEvent.VK_RIGHT:
ship.moveRight();
break;
case KeyEvent.VK_CONTROL:
ship.shoot();
score = score +100;
break;
}
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
ship.stop();
break;
case KeyEvent.VK_RIGHT:
ship.stop();
break;
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public static Background getBg1() {
return bg1;
}
}
package kiloboltgame;
import java.util.ArrayList;
public class Ship {
//In Java, Class Variables should be private so that only its methods can change them.
private int centerX = 100;
private int centerY = 382;
private int speedX = 0;
private int speedY = 1;
private ArrayList<Projectile> projectiles = new ArrayList<Projectile>();
public void update() {
// Moves Character or Scrolls Background accordingly.
if (speedX < 0) {
centerX += speedX;
} else if (speedX == 0) {
System.out.println("Do not scroll the background.");
} else {
if (centerX <= 440) {
centerX += speedX;
} else {
System.out.println("Scroll Background Here");
}
}
// Updates Y Position
if (centerY + speedY >= 382) {
centerY = 382;
}else{
centerY += speedY;
}
// Prevents going beyond X coordinate of 0
if (centerX + speedX <= -230) {
centerX = -229;
}
}
public void moveRight() {
speedX = 6;
}
public void moveLeft() {
speedX = -6;
}
public void shoot(){
Projectile p = new Projectile(centerX + 285, centerY -10);
projectiles.add(p);
}
public ArrayList getProjectiles(){
return projectiles;
}
public void stop() {
speedX = 0;
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public int getSpeedX() {
return speedX;
}
public int getSpeedY() {
return speedY;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setSpeedY(int speedY) {
this.speedY = speedY;
}
}
package kiloboltgame;
public class Background {
private int bgX, bgY, speedX;
public Background(int x, int y){
bgX = x;
bgY = y;
speedX = 0;
}
public void update() {
bgX += speedX;
if (bgX <= -800){
bgX += 1600;
}
}
public int getBgX() {
return bgX;
}
public int getBgY() {
return bgY;
}
public int getSpeedX() {
return speedX;
}
public void setBgX(int bgX) {
this.bgX = bgX;
}
public void setBgY(int bgY) {
this.bgY = bgY;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
}
public class Projectile {
private int x, y, speedY;
private boolean visible;
public Projectile(int startX, int startY) {
x = startX;
y = startY;
speedY = -7;
visible = true;
}
public void update() {
y += speedY;
if(y > 480){
visible = false;
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getSpeedY() {
return speedY;
}
public boolean isVisible() {
return visible;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setSpeedY(int speedY) {
this.speedY = speedY;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
}
package kiloboltgame;
public class Enemy {
private int maxHealth, currentHealth, power, speedX, centerX, centerY;
private Background bg = StartingClass.getBg1();
//Behavioral Methods
public void update(){
centerX += speedX;
speedX = bg.getSpeedX();
}
public void die(){
}
public void attack(){
}
public int getMaxHealth() {
return maxHealth;
}
public int getCurrentHealth() {
return currentHealth;
}
public int getPower() {
return power;
}
public int getSpeedX() {
return speedX;
}
public int getCenterX() {
return centerX;
}
public int getCenterY() {
return centerY;
}
public Background getBg() {
return bg;
}
public void setMaxHealth(int maxHealth) {
this.maxHealth = maxHealth;
}
public void setCurrentHealth(int currentHealth) {
this.currentHealth = currentHealth;
}
public void setPower(int power) {
this.power = power;
}
public void setSpeedX(int speedX) {
this.speedX = speedX;
}
public void setCenterX(int centerX) {
this.centerX = centerX;
}
public void setCenterY(int centerY) {
this.centerY = centerY;
}
public void setBg(Background bg) {
this.bg = bg;
}
}
package kiloboltgame;
public class Bomb extends Enemy {
public Bomb(int centerX, int centerY) {
setCenterX(centerX);
setCenterY(centerY);
}
}
This is all code that i have so far (I know the background is f*ed since the game this is based on is scrolling right and i haven't fixed it yet.
I recommend putting all object creation in a seperate part of the program. I'd make a BombFactory with a makeBomb mathod that returns a new Bomb instance. Inside the factory, figure out the x-coordinate, for instance using a randomiser. As parameters, you could specify a y-coordinate and possibly an upper and lower bound for the x. This way you can make new Bombs on the fly.
public class BombFactory {
private final Random rand;
public BombFactory() {
this.rand = new Random();
}
public Bomb makeBomb(int lowerboundX, int rangeX, int yPos) {
final int xPos = lowerboundX + rand.nextInt(rangeX);
return new Bomb(xPos, yPos);
}
}
As for the behaviour, I'd look into inheritance and interfaces some more. I see a lot of methods occurring more than once. You generally want to avoid that kind of duplication. You can start by taking all the methods having something to do with coords or movement and putting them in an abstract base class.
You can make a method inside Enemy that checks for a collision and responds to that in different ways, depending on how the subclass overrides it. In case of a Bomb, it would probably always kill itself and whatever it came in contact with.

Ball is not moving like I want

i want to create a Pong game. I want to move the ball in a way until it touch a wall. if it touch the wall, it go the other way. The problem is that when I start playing, the ball goes in the right way but when it touch the wall, the ball direction reverse but only for one pixel so the ball reverse for 1 pixel and then the direction change angain and it touch the wall again. My code for the moving ball is in the initBall method. Please help me :(
here is my playPanel class :
private int posX = SCREEN_WIDTH / 2;
private int posY;
public Point posMouse = new Point();
private Point posBall = new Point();
private int playPanelWidth;
private int playPanelHeight;
private int padPanelWidth;
private int padPanelHeight;
private int panPanelWidth;
private int panPanelHeight;
private JLabel player1Score = new JLabel("0");
private JLabel ComputerScore = new JLabel("0");
private JPanel panPlayer1;
public JPanel panComputer;
public JPanel padPlayer1;
public JPanel padComputer;
private JButton but_Escape = new JButton("Press escape to continue !");
/*
* Constructor
*/
// ==============================================
public PlayPanel() {
super(new BorderLayout());
setBackground(PANPLAY_COLOR);
panPlayer1 = new JPanel();
panComputer = new JPanel();
padPlayer1 = new JPanel();
padComputer = new JPanel();
padPlayer1.setBackground(Color.DARK_GRAY);
padComputer.setBackground(Color.DARK_GRAY);
padPlayer1.setPreferredSize(PADPANEL_SIZE);
padComputer.setPreferredSize(PADPANEL_SIZE);
panPlayer1.setBackground(PANPLAY_COLOR);
panComputer.setBackground(PANPLAY_COLOR);
panPlayer1.add(padPlayer1);
panComputer.add(padComputer);
add(panPlayer1, BorderLayout.WEST);
add(panComputer, BorderLayout.EAST);
addMouseMotionListener(this);
panPlayer1.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent arg0) {
setPanPanelWidth(arg0.getComponent().getSize().width);
setPanPanelHeight(arg0.getComponent().getSize().height);
}
});
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent arg0) {
setPlayPanelWidth(arg0.getComponent().getSize().width);
setPlayPanelHeight(arg0.getComponent().getSize().height);
}
});
}
/*
* Setters and Getters
*/
// ==============================================
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
public JPanel getPanPlayer1() {
return panPlayer1;
}
public void setPanPlayer1(JPanel panPlayer1) {
this.panPlayer1 = panPlayer1;
}
public JPanel getPanComputer() {
return panComputer;
}
public void setPanComputer(JPanel panComputer) {
this.panComputer = panComputer;
}
public int getPlayPanelHeight() {
return playPanelHeight;
}
public void setPlayPanelHeight(int playPanelHeight) {
this.playPanelHeight = playPanelHeight;
}
public int getPlayPanelWidth() {
return playPanelWidth;
}
public void setPlayPanelWidth(int playPanelWidth) {
this.playPanelWidth = playPanelWidth;
}
public int getPadPanelWidth() {
return padPanelWidth;
}
public void setPadPanelWidth(int padPanelWidth) {
this.padPanelWidth = padPanelWidth;
}
public int getPadPanelHeight() {
return padPanelHeight;
}
public void setPadPanelHeight(int padPanelHeight) {
this.padPanelHeight = padPanelHeight;
}
public int getPanPanelWidth() {
return panPanelWidth;
}
public void setPanPanelWidth(int panPanelWidth) {
this.panPanelWidth = panPanelWidth;
}
public int getPanPanelHeight() {
return panPanelHeight;
}
public void setPanPanelHeight(int panPanelHeight) {
this.panPanelHeight = panPanelHeight;
}
/*
* Add the ball
*/
// ==============================================
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(Color.BLACK);
initBall(g2);
// trait épais
g2.setColor(Color.DARK_GRAY);
g2.setStroke(new BasicStroke(10));
g2.drawLine((getPlayPanelWidth() / 2) - 5, getPlayPanelHeight(),
(getPlayPanelWidth() / 2) - 5, 0);
}
/*
* Init ball
*/
// ==============================================
private void initBall(Graphics2D graphics2d) {
int x = getPosX(), y = getPosY();
boolean backX = false;
boolean backY = false;
Graphics2D g2 = graphics2d;
g2.fillOval(posX, posY, BALL_WIDTH, BALL_HEIGHT);
//posBall.setLocation(posX + BALL_WIDTH, posY + (BALL_HEIGHT / 2));
if (x < 1)
backX = false;
if (x > getWidth() - 50)
backX = true;
if (y < 1)
backY = false;
if (y > getHeight() - 50)
backY = true;
if (!backX)
setPosX(++x);
else {
setPosX(--x);
}
if (!backY)
setPosY(++y);
else
setPosY(--y);
repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void mouseDragged(MouseEvent arg0) {
}
#Override
public void mouseMoved(MouseEvent arg0) {
posMouse.setLocation(arg0.getX(), arg0.getY()
- (getPadPanelHeight() / 2));
padPlayer1.setLocation(getPanPanelWidth() - 15, (int) posMouse.getY());
padComputer.setLocation(5, (int) posMouse.getY());
}
}
So you have:
private void initBall(Graphics2D graphics2d) {
int x = getPosX(), y = getPosY();
boolean backX = false;
boolean backY = false;
in the beginning, so that regardless of which direction the ball is going, booth booleans are set to false every time. Then, you don't have an "Else" when it comes to setting the back option in
if (x < 1)
backX = false;
if (x > getWidth() - 50)
backX = true;
if (y < 1)
backY = false;
if (y > getHeight() - 50)
backY = true;
What is happening is that the ball is moving in the right direction, until it hits a wall (I'm guessing the top wall). then this is called:
if (y > getHeight() - 50)
backY = true;
So then for that iteration the ball goes back because of
if (!backY)
setPosY(++y);
else
setPosY(--y);
But then you set it back to false right away. I suggest you have
private boolean backX = false; //same for backY
outside your method.

Categories