Multi- threading in Java - trouble with implmenting in program - java

I created the below bouncing ball program. I'm new to programming in general, but got this working fine. The objective was to have the ball bounce within the frame and to appear in random locations at program start up.
the next thing I am trying to do is to intoduce multiple balls into the frame that bounce around. I'm trying to do this using the Rnnable interface but havent been able to get this working. The Balls can move independently, passing through each other. Each Ball should have its own thread, rather than one thread updating an array of Balls.Below is my attempt but I havent able to get this working.
Any advice would be great.
/*Bounce class*/
import java.awt.Color;
import java.awt.Graphics;
import java.util.concurrent.ThreadLocalRandom;
import javax.swing.JPanel;
public class Bounce2 extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
/*variables*/
int x, y;
int anglex = 1, angley = 1, speed = 10;
int min = 40, max = 760;
public Bounce2() {
min = 60;
max = 740;
}
public void setGenerateRandom (int max, int min) {
x = ThreadLocalRandom.current().nextInt(min, max +1);
y = ThreadLocalRandom.current().nextInt(min, max +1);
run();
}
public void run() {
if (x + anglex < 0) {
anglex = speed;
} else if (x + anglex > getWidth() - 50) {
anglex = -speed;
} else if (y + angley < 0) {
angley = speed;
} else if (y + angley > getHeight() - 50) {
angley = -speed;
}
x = x + anglex;
y = y + angley;
}
public void paint (Graphics g) {
super.paint(g);
Color c = Color.blue;
g.setColor(c);
g.fillOval(x, y, 80, 80);
}
public void random() {
setGenerateRandom(max, min);
}
}
/*Bounce2Test class*/
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Bounce2Test {
public static void main(String[] args) throws InterruptedException {
{
int num = 0;
String objects;
objects = JOptionPane.showInputDialog("Please enter number of balls!");
num = Integer.parseInt(objects);
// Number of threads
for (int i = 0; i < num; i++) {
Thread object = new Thread(new Bounce2());
object.start();
JFrame frame = new JFrame("Bouncing Ball");
Bounce2 ball = new Bounce2();
frame.add(ball);
frame.setSize(800,800);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ball.random();
while(true) {
ball.run();
ball.repaint();
Thread.sleep(10);
}
}
}
}
}

Related

Why doesn't this array based Java game work?

I have made a very basic 2D game where you have to shoot down your enemies which are coming from 5 different tracks. I created a 2D array (track) to store the locations of the enemies, projectiles. The array is 790 wide because the track is 790 pixels long. I am using a game loop to update and render which is working just fine.
But because the loop is influenced by the performance of the computer I am using the ScheduledExecutorService class to execute the movement and spawning of enemies but for some reason it isn't working, the enemies don't move or sometimes don't even spawn and the projectiles don't move. The program doesn't give an error it just doesn't work. I checked and there are no syntax errors and I couldn't find any logical problems in it either at least of my knowledge.
Please give a short and not too complicated answer because I'm still a beginner.
The code: (controls are S,D / up, down for movement and space to shoot)
package com.bacskai.peashooter;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable, KeyListener {
private static final long serialVersionUID = -4227990863874935837L;
JFrame frame;
static Dimension d;
Thread thread;
public static int width = 300;
public static int height = width / 16 * 9;
int scale = 3;
boolean running;
boolean alive = true;
int[][] track = new int[5][790]; // the array
int trackY = 2; // the track which the player is on
private int playerPos = 250;
private int playerPos1 = 220; // the 3 starting points for the triangle
private int playerPos2 = 280;
int health = 3;
int score = 0;
long delay = 100;
long delay2 = 5000;
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
ScheduledExecutorService executor2 = Executors.newScheduledThreadPool(1);
Runnable task = new Runnable() {
public void run() {
move();
}
};
Runnable task2 = new Runnable() {
public void run() {
spawnEnemy();
}
};
public Game() {
d = new Dimension(width * scale, height * scale);
setPreferredSize(d);
frame = new JFrame();
}
private void start() {
thread = new Thread(this, "thread");
running = true;
thread.start();
for (int i = 0; i == 5; i++) {
for (int j = 0; j == 790; j++) { // initializing the array
track[i][j] = 0;
}
}
executor.scheduleAtFixedRate(task, delay, delay,
TimeUnit.MILLISECONDS); // moveing
executor2.scheduleAtFixedRate(task2, delay2, delay2,
TimeUnit.MILLISECONDS); // spawning new enemies
System.out.println("Game started, window width: " + getWidth() + ",
height: " +
getHeight());
}
public void run() {
while (running) { // game loop
update();
if (alive) {
render();
}
}
}
private void stop() {
try {
frame.dispose();
thread.join();
executor.shutdownNow();
executor2.shutdownNow();
} catch (Exception e) {
System.out.println("Error while closing: " + e);
}
System.out.println("Program closed, processes halted");
}
public void update() {
if (health == 0) {
alive = false;
executor.shutdownNow();
executor2.shutdownNow();
System.out.println("Game over");
}
}
private void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {createBufferStrategy(3); return;}
Graphics g = bs.getDrawGraphics();
// Map
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.cyan);
g.fillRect(100, 0, 10, 490);
g.fillRect(0, 98, 900, 10);
g.fillRect(0, 196, 900, 10);
g.fillRect(0, 294, 900, 10);
g.fillRect(0, 392, 900, 10);
// Score / health
Font font = new Font("Default", Font.PLAIN, 30);
g.setFont(font);
g.setColor(Color.red);
g.drawString("Score: " + score, 740, 30);
g.setColor(Color.yellow);
g.drawString("Health: " + health, 600, 30);
// Player
g.setColor(Color.green);
int[] xPoints = {10, 10, 60};
int[] yPoints = {playerPos1, playerPos2, playerPos};
g.fillPolygon(xPoints, yPoints, 3);
// Enemies
g.setColor(Color.red);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 790; j++) {
if (track[i][j] == 1) {
g.fillRect(100 + j, i * 97 + 44, 30, 30);
}
}
}
// Projectiles
g.setColor(Color.green);
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 790; j++) {
if (track[i][j] == 2) {
g.fillOval(110 + j, i * 97 + 44, 27, 27);
}
}
}
bs.show();
g.dispose();
} // End of render
public int randInt(int min, int max) {
Random rand = new Random();
int randomNum = rand.nextInt((max - min) + 1) + 1;
return randomNum;
}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
stop();
}
if(e.getKeyCode() == KeyEvent.VK_UP && trackY > 0) {
trackY--;
playerPos -= 98;
playerPos1 -= 98;
playerPos2 -= 98;
System.out.println("Key pressed: up");
}
if(e.getKeyCode() == KeyEvent.VK_DOWN && trackY < 4) {
trackY++;
playerPos += 98;
playerPos1 += 98;
playerPos2 += 98;
System.out.println("Key pressed: down");
}
if(e.getKeyCode() == KeyEvent.VK_SPACE) {
shoot();
}
}
public void keyReleased(KeyEvent e) {}
public void shoot() {
System.out.println("Player shot projectile from: " + (trackY + 1));
track[trackY][0] = 2;
}
public void move() {
System.out.print("asd");
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 790; j++) {
if (track[i][j] == 2 && track[i][j + 2] == 1) {
track[i][j] = 0;
track[i][j + 2] = 0;
break;
}
switch (track[i][j]) {
case 0: // 0 ==> empty position
break;
case 1: // 1 ==> enemy
if (j != 0) {
track[i][j - 1] = 1;
track[i][j] = 0;
} else {
track[i][j] = 0;
enemyArrived();
}
System.out.print("");
break;
case 2: // 2 ==> projectile
if (j == 789) {
track[i][j] = 0;
break;
}
track[i][j + 1] = 2;
track[i][j] = 0;
System.out.print("");
break;
default:
System.out.println("Unable to identify object type at: track[" + i + "][" + j + "]");
break;
}
}
}
}
public void spawnEnemy() {
int trakk = randInt(1, 5);
track[trakk][789] = 1;
System.out.println("New enemy at: " + trakk);
}
public void enemyArrived() {
health--;
System.out.println("Player lost a health point, current health: " + health);
}
public static void main(String[] args) {
Game game = new Game();
game.frame.setResizable(false);
game.frame.setTitle("Peasooter");
game.frame.add(game);
game.frame.pack();
game.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.frame.setLocationRelativeTo(null);
game.frame.setVisible(true);
game.frame.addKeyListener(game);
game.start();
}
}
Also I would be very happy if somebody could tell me if there is a way of optimizing this game to not consume 25% - 30% of the cpu.
I've managed to make your app sort of run with some changes and bug fixing. It's not a finished solution but something to help you move forward.
From the top
I changed the delays values, this made the game playable since it seems 100 is way to short time. You probably won't like my values for playability but with my values the game can be tested at least.
long delay = 1000;
long delay2 = 3000;
No point in having two ScheduledExecutorService objects so delete the second one.
I have no idea why you want to spawn a thread run your code from there so I removed it.
//thread = new Thread(this, "thread");
running = true;
//thread.start();
And manually called the run() method at the end of start() so with that and the single executor the second half of start()is
executor.scheduleAtFixedRate(task, delay, delay,
TimeUnit.MILLISECONDS); // moveing
executor.scheduleAtFixedRate(task2, delay2, delay2,
TimeUnit.MILLISECONDS); // spawning new enemies
System.out.println("Game started, window width: " + getWidth() + ", height: " + getHeight());
run();
}
You are all over the place with your for loops, at one place you have i < 6 for the limit, and at another you have i == 5 (which always will be false). Go through all loops and make sure they are defined as
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 790; j++) {
Also call randInt properly to fit you array size
int trakk = randInt(0, 4);
The game still behaves very odd but most of the time I get some red enemies and I can shoot them down.
Update
I played some more with it and made two more changes.
Your random generator method creates a new Random object each time it's called which is unnecessary and I didn't see the point of having the randInt method so I delete the method and declare a new member at the top
Random rand = new Random();
and then used it where the call to randInt used to be
int trakk = rand.nextInt(NUMBER_OF_ROWS);
To see if I could improve the performance I introduced 3 constants and then used them for the array and the for loops (replacing all occurrences of 5 and 790 with them)
private static final int NUMBER_OF_ROWS = 5;
private static final int NUMBER_OF_PIXELS = 790;
private static final int LAST_PIXEL = NUMBER_OF_PIXELS - 1;
Then I made the array much smaller by changing the two first to 3 and 100, this again made the game much more playable (although it messed up the graphics some) making it easier to test and fix bugs.

Button To Reset The View Of JFrame

I have to write a program that will generate 20 random circles with random radius lengths. If any of these circles intersect with another, the circle must be blue, and if it does not intersect, the color is red. I must also place a button on the JFrame. If this button is pressed, it needs to clear out the JFrame, and generate a new set of 20 circles following the same color rules. I am extremely new to Java Swing and am really stuck. I have everything working except the button. I cannot get a new set of circles to generate. Any help would be greatly appreciated. Thank You.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
setPreferredSize(new Dimension(1000, 800)); // set window size
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
// Add button to run again
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
add(btnAgain);
btnAgain.addActionListener(new ButtonClickListener());
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String action = e.getActionCommand();
if(action.equals("Run Again"))
{
new IntersectingCircles();
}
}
}
}
Suggestions:
Give your class a method that creates the random circles and calls repaint()
This method should create the circles and add them into an ArrayList.
Consider using Ellipse2D to represent your circles, and so you'd have an ArrayList<Ellipse2D>.
Call this method in your class constructor.
Call it again in the button's ActionListener.
Never add button's or change the state of your class from within your paintComponent method. This method is for drawing the circles and drawing them only and nothing more. Your way you will be creating the button each time the paintComponent method is called, so you could be potentially needlessly creating many JButtons
and needlessly slowing down your time-critical painting method.
Instead add the button in the constructor.
Be sure to call super.paintComponent(g) in your paintComponent method as its first call. This will clear the old circles when need be.
Also in paintComponent, iterate through the ArrayList of circles, drawing each one.
After some searching on this website, i found what i needed. Everything seems to work now. Thanks.
import java.awt.Graphics;
import javax.swing.JPanel;
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class IntersectingCircles extends JPanel
{
private int[] xAxis = new int [20]; // array to hold x axis points
private int[] yAxis = new int [20]; // array to hold y axis points
private int[] radius = new int [20]; // array to hold radius length
public static void main (String[] args)
{
JFrame frame = new JFrame("Random Circles");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1000, 800));
ActionListener runAgain = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent c)
{
frame.getContentPane().add(new IntersectingCircles());
frame.pack();
}
};
JButton btnAgain = new JButton("Run Again");
btnAgain.setBounds(850, 10, 100, 30);
btnAgain.addActionListener(runAgain);
frame.add(btnAgain);
frame.getContentPane().add (new IntersectingCircles());
frame.pack();
frame.setVisible(true);
}
public IntersectingCircles()
{
Random random = new Random();
// Create coordinates for circles
for (int i = 0; i < 20; i++)
{
xAxis[i] = random.nextInt(700) + 100;
yAxis[i] = random.nextInt(500) + 100;
radius[i] = random.nextInt(75) + 10;
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
// Determine if circles intersect, create circles, color circles
for (int i = 0; i < 20; i++)
{
int color = 0;
for (int h = 0; h < 20; h++)
{
if(i != h)
{
double x1 = 0, x2 = 0, y1 = 0, y2 = 0, d = 0;
x1 = (xAxis[i] + radius[i]);
y1 = (yAxis[i] + radius[i]);
x2 = (xAxis[h] + radius[h]);
y2 = (yAxis[h] + radius[h]);
d = (Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1)*(y2 - y1))));
if (d > radius[i] + radius[h] || d < (Math.abs(radius[i] - radius[h])))
{
color = 0;
}
else
{
color = 1;
break;
}
}
}
if (color == 0)
{
g.setColor(Color.RED);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
else
{
g.setColor(Color.BLUE);
g.drawOval(xAxis[i], yAxis[i], radius[i] * 2, radius[i] * 2);
}
}
}
}
private class ButtonClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
repaint();
}
}
Maybe you can have a try...

Implementation of Galton board in java

I am writing the implementation of Galton Board in Java by using Java awt, Swing and thread. My Program has three text field to choose number of slots, number of balls, and number of ball drops at the same time, two buttons one for display and one for start the program. I try to make it work like I can choose the amount of balls and click start and the balls auto falling down the chimney. Currently, My program be able to drop one ball and running fine, but I don't know how to implement that be able drop more than one ball. Any suggestions or help are appreciated, Thank you. This is Main.Class
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Random;
import javax.swing.*;
public class Main extends JFrame {
private String num_slots;
private String num_balls;
private String ball_free;
private JButton Display;
private JButton Start;
private JPanel textpanel;
private JPanel mainpanel;
private JPanel graphpanel;
public Main() {
textpanel = new JPanel();
textpanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 20));
textpanel.add(new JLabel("Number of Slots"));
final JTextField text1 = new JTextField(10);
textpanel.add(text1);
textpanel.add(new JLabel("Number of Balls"));
final JTextField text2 = new JTextField(10);
textpanel.add(text2);
textpanel.add(new JLabel("How many balls can be freed"));
final JTextField text3 = new JTextField(10);
textpanel.add(text3);
Display = new JButton("Display");
textpanel.add(Display);
Start = new JButton("Start");
textpanel.add(Start);
// Create panel p2 to hold a text field and p1
mainpanel = new JPanel(new BorderLayout());
mainpanel.add(textpanel, BorderLayout.NORTH);
/*
* graphpanel = new JPanel(); graphpanel.setLayout(new
* BoxLayout(graphpanel, BoxLayout.Y_AXIS));
*/
add(mainpanel, BorderLayout.CENTER);
Display.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Display) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa);
mainpanel.revalidate();
}
}
});
Start.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == Start) {
num_slots = text1.getText();
int slots = Integer.parseInt(num_slots);
num_balls = text2.getText();
int balls = Integer.parseInt(num_balls);
MainPanel pa = new MainPanel(slots, balls);
mainpanel.add(pa, BorderLayout.CENTER);
pa.start();
mainpanel.revalidate();
mainpanel.repaint();
}
}
});
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Main frame = new Main();
frame.setTitle("The Galton board");
frame.setSize(1000, 800);
frame.setLocationRelativeTo(null); // Center the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setAutoRequestFocus(true);
}
}
main panel class contains the chimneys and balls
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JPanel;
class MainPanel extends JPanel implements Runnable {
private int num;
private int number_ball;
public static int start_y = 100;
private float ball_x = 385;
private float ball_y = 50;
private float radius = 15;
private static int panel_x = 300;
private static int panel_y = 100;
private int diameter = 20;
private int last_x = 0;
private final static Random generator = new Random();
ArrayList<Balls> list_ball = new ArrayList<Balls>();
private int m_interval = 100;
private Timer m_timer;
public MainPanel() {
}
public MainPanel(int number) {
num = number;
}
public MainPanel(int number, int ball) {
num = number;
number_ball = ball;
for (int i = 1; i <= number_ball; i++)
{
list_ball.add(new Balls());
}
m_timer = new Timer(m_interval, new TimerAction());
}
public int getPanel_y() {
return panel_y;
}
public void start()
{
m_timer.setInitialDelay(250);
m_timer.start();
}
#Override
protected void paintComponent(Graphics g) {
int start_y = 100;
panel_x = 300;
panel_y = 100;
diameter = 20;
last_x = 0;
super.paintComponent(g);
if (num % 2 == 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
} else if (num % 2 != 0) {
for (int i = 1; i <= num; i++) {
if ((i % 2) != 0) {
for (int k = 1; k <= num; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
} else if ((i % 2) == 0) {
for (int k = 1; k <= num + 1; k++) {
g.setColor(Color.BLUE);
g.fillOval(panel_x - 20, panel_y, diameter, diameter);
panel_x = panel_x + 40;
}
}
panel_y = panel_y + 40;
panel_x = 300;
}
}
for (int n = 40; n < panel_y - 40; n = n + 40) {
if (num % 2 == 0) {
g.drawLine(panel_x - 50 + n, panel_y - 10, panel_x - 50 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 50 + n, panel_y + 80);
last_x = panel_x - 50 + n;
} else if (num % 2 != 0) {
g.drawLine(panel_x - 30 + n, panel_y - 10, panel_x - 30 + n,
panel_y + 80);
g.drawLine(panel_x, panel_y + 80, panel_x - 30 + n, panel_y + 80);
last_x = panel_x - 30 + n;
}
}
for (int i = 0; i< list_ball.size(); i++)
{
list_ball.get(i).draw(g);
}
}
class TimerAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
for (int i = 0; i< list_ball.size(); i++)
{
list_ball.get(i).move();
//return;
//m_timer.stop();
repaint();
}
}
Balls Class
import java.awt.geom.Ellipse2D;
import java.util.Random;
import java.awt.*;
public class Balls {
private Ellipse2D.Double thisBall;
private int Ball_x;
private int Ball_y;
public int radius;
public int start_y;
private final static Random generator = new Random();
Mainpanel pa = new Mainpanel();
public Balls()
{
start_y = 100;
Ball_x = 385;
Ball_y = 50;
radius = 15;
}
public void draw(Graphics g)
{
g.setColor(Color.RED);
g.fillOval(Ball_x, Ball_y, radius, radius);
}
public void move()
{
if (Ball_y < pa.getPanel_y() + 65)
{
int direction = generator.nextInt(2);
Ball_y = Ball_y + 5;
if (Ball_y == start_y - 10 && start_y < pa.getPanel_y())
{
if (direction == 0)
{
Ball_x = Ball_x - 20;
}
else Ball_x = Ball_x + 20;
start_y = start_y + 40;
}
System.out.println(Ball_y);
System.out.println(pa.getPanel_y());
}
// Ball_x = Ball_x + 5;
}
}
Create a new logical class, not a GUI class, for your Ball, one that does not extend a JPanel or any Swing component, but rather one that has the logic behind the Ball as well as perhaps a rendering method that accepts a Graphics or Graphics2D object. Then give your drawing JPanel class an ArrayList of these Ball objects, move them in your game loop -- note that I would prefer using a Swing Timer and not a background thread, and then in your JPanel's paintComponent method iterate through the ArrayList of Balls, drawing each Ball by calling its rendering method.
As an aside: all your class names should begin with an upper case letter, and all identifiers other than constants should use camel case, so your mainpanel class should be named MainPanel. I've edited your code prettify the code formatting and have made this change for you.
Aside number 2: your current code has code logic inside of paintComponent. Don't do that as that will mess you up. You don't have full control over when or even if paintComponent will be called.

Java both if() and else if() statements are being called

Okay, so I'm in the progress of making a game, and I need the collisions to work. I have an if() { } else if() {} -statement, but BOTH of them are being called. Here is my code:
Inside my Player Class:
public Rectangle[] tileRect;
public void update() {
tileRect = new Rectangle[Level1.tiles.size()];
for (int w = 0; w < Level1.tiles.size(); w++) {
Tile m = (Tile) Level1.tiles.get(w);
tileRect[w] = m.getBounds();
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
} else if (!tileRect[w].intersects(getRect())){
dy = 4;
}
}
x += dx;
y += dy;
}
public Rectangle getRect() {
return new Rectangle(x, y, 32, 32);
}
Here is my Tile class (the Level1.tiles is an arrayList of tiles):
package level;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Tile extends Rectangle {
// Defines the id of the tile, used for setting textures.
private static final long serialVersionUID = 1L;
public int id;
// Location
public int x;
public int y;
// Variables for the terrain sprite sheet.
public BufferedImage image;
public String imageLocation;
public BufferedImage[] sprite;
public int rows = 16;
public int collumns = 16;
public int width = 16;
public int height = 16;
public Tile(int idVal, int xPos, int yPos) {
x = xPos * 32;
y = yPos * 32;
id = idVal;
setBounds(x, y, 32, 32);
createImages();
}
public BufferedImage getImage() {
return sprite[id];
}
public void createImages() {
imageLocation = "res/tile/terrain.png";
try {
image = ImageIO.read(new File(imageLocation));
} catch (IOException e) {
System.out.println("Unable to find file " + imageLocation
+ ", printing stack trace!");
e.printStackTrace();
}
sprite = new BufferedImage[rows * collumns];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < collumns; j++) {
sprite[(i * collumns) + j] = image.getSubimage(j * width, i
* height, width, height);
}
}
}
public int getXLoc() {
return x;
}
public int getYLoc() {
return y;
}
public void setX(int xPos) {
x = xPos;
}
public void setY(int yPos) {
y = yPos;
}
}
I'm getting the "intersecting" message in the console, but the player is still falling down (because dy = 4). Please help! I've been trying to solve this all morning...
If and Else cannot both be caught at the same time.
Looks like you are looping through, seeing an intersection, then continuing to loop through regardless.
Try adding a break command to your for loop.
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
break;
} else if (!tileRect[w].intersects(getRect())){
dy = 4;
}
The break will stop your for loop from continuing and you will exit the loop with dy = 0; rather than going onto the next tile and changing it back to dy = 4;
if and else if cannot be called in the same run. If if condition is true, then any else is never run (not even checked). It's probably different runs. Debug or put a log to see the flow.
Also
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
} else if (!tileRect[w].intersects(getRect())){
dy = 4;
}
is much simpler written as
if(tileRect[w].intersects(getRect())) {
System.out.println("intersecting");
dy = 0;
} else {
dy = 4;
}

java 2d game -lagging and collision issue

I am designing a simple java 2d game.where an aircraft shoots missiles and they hit alien ships.(pictures are attached for a better understanding).
Now I need to detect when the missile hits the alien ship. So as to count the number of total hits. I used the rectangle1.intersects(rec2)method, but instead of giving me an integer 1 as the answer (after the boolean of course) it gives me some funny answer. I guess like how much the two rectangles intersect...
Also when adding new aliens in an arraylist I use the following: I add new aliens every two seconds, but this slows down the game very much.
So please guide me on these two issues.
There is a game class (contains the main frame), board class (the panel on which I draw) alient, missile and craft class. Below I am giving the the actionPerformed() of the panel class which gets called by a timer every 2ms (the rest of the code is below).
///CODE TO BE FOCUSED ON
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class game extends JFrame {
static long z;
game()
{
add(new board());
setBounds(0, 0, 500, 500);
setVisible(true);
setLayout(null);
setLocationRelativeTo(null);
setTitle("\t\t...................::::~~~~'S GAME~~~~:::::...............");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new game();
z = System.currentTimeMillis();
}
}
class board extends JPanel implements ActionListener
{
Timer t = new Timer(5, this);
public ArrayList alien_list;
craft craft_list = new craft();
Label l = new Label();
int total_hits = 0;
public board() {
setFocusable(true);
setLayout(null);
setDoubleBuffered(true);
setBackground(Color.BLACK);
addKeyListener(craft_list);
l.setBounds(0, 0, 150, 30);
l.setBackground(Color.GREEN);
add(l);
t.start();
alien_list = new ArrayList();
alien_list.add(new alien(0, 100));
alien_list.add(new alien(0, 150));
alien_list.add(new alien(0, 200));
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g1 = (Graphics2D) g;
long z = (System.currentTimeMillis() - game.z) / 1000;
if (z >= 60)
{
remove(l);
g.setColor(Color.red);
g1.drawString("time up", 100, 100);
} else
{
g1.drawImage(craft_list.getImage(), craft_list.getX(),
craft_list.getY(), null);
ArrayList a = craft_list.getmissile();
for (int i = 0; i < a.size(); i++) {
missile m = (missile) a.get(i);
g1.drawImage(m.getImage(), m.getX(), m.getY(), null);
}
l.setText("time elapsed:" + " " + +z + " " + "hits:" + " "
+ total_hits);
for (int i = 0; i < alien_list.size(); i++) {
alien m = (alien) alien_list.get(i);
g1.drawImage(m.getImage(), m.getX(), m.getY(), null);
}
}
}
public void actionPerformed(ActionEvent e) {
ArrayList a = craft_list.getmissile();
for (int i = 0; i < a.size(); i++) {
missile m = (missile) a.get(i);
if (m.visible == true)
m.move();
else
a.remove(i);
}
long z = (System.currentTimeMillis() - game.z) / 1000;
if (z % 3 == 0)
alien_list.add(new alien(-10, 100));
for (int j = 0; j < alien_list.size(); j++) {
alien m = (alien) alien_list.get(j);
if (m.visible == true)
m.move();
else
alien_list.remove(j);
}
craft_list.move();
collison();
repaint();
}
public void collison() {
ArrayList a = craft_list.getmissile();
for (int i = 0; i < a.size(); i++) {
missile m = (missile) a.get(i);
Rectangle r1 = m.getBounds();
for (int j = 0; j < alien_list.size(); j++) {
alien l = (alien) alien_list.get(j);
Rectangle r2 = l.getBounds();
if (r1.intersects(r2)) {
total_hits++;
m.setVisible(false);
l.setVisible(false);
}
}
}
}
}
class craft extends KeyAdapter
{
int x = 250;
int y = 400;
ArrayList m = new ArrayList();
Image i;
int dx, dy;
craft() {
ImageIcon i1 = new ImageIcon("1a.jpg");
i = i1.getImage();
}
public Image getImage() {
return i;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void move() {
x += dx;
y += dy;
if (x < 0)
x = 0;
if (x > 450)
x = 450;
if (y > 420)
y = 420;
if (y < 200)
y = 200;
}
public void keyPressed(KeyEvent k)
{
int key = k.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 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 void fire() {
m.add(new missile(getX() + 13, getY() - 6));
}
public ArrayList getmissile() {
return m;
}
public Rectangle getBounds() {
return new Rectangle(x, y, i.getWidth(null), i.getHeight(null));
}
}
class missile {
Image i;
int x, y;
public boolean visible;
missile(int x, int y) {
this.x = x;
this.y = y;
visible = true;
ImageIcon i1 = new ImageIcon("1c.jpg");
i = i1.getImage();
}
public Image getImage() {
return i;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void move() {
y--;
if (y < 0)
visible = false;
}
public Rectangle getBounds() {
return new Rectangle(x, y, i.getWidth(null), i.getHeight(null));
}
public void setVisible(boolean t) {
this.visible = t;
}
}
class alien {
Image i;
int x, y;;
public boolean visible;
public alien(int x, int y)
{
this.x = x;
this.y = y;
ImageIcon i1 = new ImageIcon("b.jpg");
i = i1.getImage();
visible = true;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Image getImage() {
return i;
}
public void move() {
x++;
if (x > 500)
visible = false;
}
public Rectangle getBounds() {
return new Rectangle(x, y, i.getWidth(null), i.getHeight(null));
}
public void setVisible(boolean t) {
this.visible = t;
}
}
Ok, your code format is kind of unreadable and invites everybody to oversee otherwise obvious bugs. That is what I have seen so far for your performance issue:
getBounds() creates a new Rectangle instance every time it gets called. You should update the bounds rectangle at the last line of your move() and just return the rectangle instance instead of creating a new one.
Reuse Image or ImageIcon objects. There is no need to load the same jpg file over and over again in a constructor. Make it static or use a image cache.
Instead of o++ in fire() you should use o = m.size(). Mainly because you never call o--, you only remove the rocket from the ArrayList.
And at that point everybody loses track of what o and m means. Name your variables better! o should be amountOfRockets and m should be listOfRockets.
When you use Eclipse, press ctrl + shift + f to format the code which I highly recommend. After that go through your code and name the variables correctly. That means you should give them a descriptive name. And finally: let the name of your classes start with an upper case.
Very likely that this will not yet remove all issues but it will at least help us to understand and read your code easier... which might lead us to a solution...
Update:
You still haven't done 1. and 2. I suggested but you did 3.
Here is what 1. should be as a sample for the Alien class:
private Rectangle bounds
//constructor
Alien() {
// your stuff and the bounds:
bounds = new Rectangle(x, y, i.getWidth(null), i.getHeight(null));
}
public void move() {
bounds.x++;
if (bounds.x > 500)
visible = false;
}
public Rectangle getBounds() {
return bounds;
}
You need to implement that for the Rocket class as well.
What I still don't get is where you remove the old Alien objects. Just setting their visibility is not enough. You should remove them from the list of your Alien objects. Otherwise you will loop through objects that are not there anymore.

Categories

Resources