The Program is simple enough. I'm trying to get 3-10 random looking faces to print on a panel in a frame in Java. The problem is the faces won't print on the panel. I'm pretty new to this so I'm not sure what I've mucked up, and I've been trying to find a solution to my problem for a while. Any help?
//Leonard
//Random Face Drawer(3-10)
//Last Modified: 10/6/18
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
//Main Class
public class FaceDraw {
public static void main(String[] args) {
int width = 900;
int height = 600;
Random rand = new Random();
ArrayList<Face> myFaceList = new ArrayList<Face>();
for( int i = 1; i < (rand.nextInt(8)+3); i ++) {
myFaceList.add(new Face(rand.nextInt(width-50)+50,rand.nextInt(height-50)+50,rand.nextInt(101),rand.nextInt(101)));
System.out.print(myFaceList);
}
FaceFrame myFaceFrame = new FaceFrame(myFaceList, width, height);
myFaceFrame.setVisible(true);
}
}
class OvalDraw extends Oval{
public OvalDraw () {
super(0,0,0,0);
}
public OvalDraw (int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
}
public void paintComponent(Graphics g) {
g.drawOval(getPositionX(),getPositionY(),getWidth(),getHeight());
System.out.format("OvalDraw.paintComponent(x = %d, y = %d, w = %d, h = %d)", getPositionX(),getPositionY(),getWidth(),getHeight());
}
}
//Face Class, extends from OvalDraw makes the face
class Face extends OvalDraw {
private OvalDraw eye1;
private OvalDraw eye2;
private Random smile;
private int smileStatus;
public Face () {
super(0, 0, 0, 0);
eye1 = new OvalDraw(0,0,0,0);
eye2 = new OvalDraw(0,0,0,0);
smileStatus = smile.nextInt(2);
}
public Face (int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
// variables to set my eyes to be the same size but in two different spots on the same y axis
int eyeHeight = heightIn/12;
int eyeWidth = widthIn/10;
int eye1PositionX = positionXIn + positionXIn/3;
int eyePositionY = positionYIn + positionYIn/12;
int eye2PositionX = eye1PositionX + (positionXIn/3)*2;
eye1 = new OvalDraw(eye1PositionX,eyePositionY,eyeWidth,eyeHeight);
eye2 = new OvalDraw(eye2PositionX,eyePositionY,eyeWidth,eyeHeight);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
eye1.paintComponent(g);
eye2.paintComponent(g);
if(smileStatus == 0) {
g.drawArc(getPositionX(), getPositionY() + getHeight()/2, getWidth(), getHeight(), 45, 90);
}else if(smileStatus == 1){
g.drawArc(getPositionX(), getPositionY() + getHeight()/2, getWidth(), getHeight(), 45, 90);
}else{
g.drawArc(getPositionX(), getPositionY() + getHeight()/2, getWidth(), getHeight(), 45, 90);
}
}
}
class FacePanel extends JPanel{
private ArrayList<Face> FaceList;
public void setFaceList(ArrayList<Face> FaceListIn) {
FaceList = FaceListIn;
}
//draw panel
FacePanel(){
super();
assert false:"unexpected error...(shape draw panel)";
}
FacePanel(ArrayList<Face> FaceListIn){
setFaceList(FaceList);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Face oD : FaceList) {
oD.paintComponent(g);
}
}
}
class FaceFrame extends JFrame{
private FacePanel myFacePanel;
public FaceFrame(ArrayList<Face> faceListIn, int width, int height) {
setBounds(100,100,900,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FacePanel myFacepanel = new FacePanel(faceListIn);
}
}
//Main class for my Shapes
abstract class Shape {
//setting of position
//positioning for x
public final void setPositionX(int positionXIn) {
positionX = positionXIn;
}
public final int getPositionX() {
return positionX;
}
private int positionX;
//positioning for y
public final int getPositionY() {
return positionY;
}
public final void setPositionY(int positionYIn) {
positionY = positionYIn;
}
private int positionY;
//The Width of the Shape
public final void setWidth(int widthIn) {
width = OneOrGreater(widthIn);
}
public final int getWidth() {
return width;
}
private int width;
//The Height of the Shape
public final void setHeight(int heightIn) {
height = OneOrGreater(heightIn);
}
public final int getHeight() {
return height;
}
private int height;
//function for shape
public Shape() {
this(0,0,0,0);
}
public Shape(int positionXIn, int positionYIn, int widthIn, int heightIn) {
setPositionX(positionXIn);
setPositionY(positionYIn);
setWidth(widthIn);
setHeight(heightIn);
}
protected static int OneOrGreater(int valueIn) {
assert valueIn>=1:"Shape parameter is unexeptedly less than 1.";
int returnValue = valueIn;
if (valueIn < 1) {
returnValue = 1;
}
return returnValue;
}
//strings
public String toString() {
return String.format("positionX=%d, positionY=%d, width=%d, height=%d", positionX, positionY, getWidth(), getHeight());
}
abstract public double CalcArea();
abstract public double CalcPerimeter();
}
//The Rectangle class that inherits from Shape
class Rectangle extends Shape {
public Rectangle() {
this(0,0);
}
public Rectangle(int widthIn, int heightIn) {
setWidth(widthIn);
setHeight(heightIn);
}
public Rectangle(int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
}
//calculating area for rectangle is base * height
public double CalcArea() {
return getWidth() * getHeight();
}
//calculating rectangle perimeter is 2(width+height)
public double CalcPerimeter() {
return getWidth() + getWidth() + getHeight() + getHeight();
}
}
//Class for Oval that inherits from Shape
class Oval extends Shape {
Oval () {
super();
}
Oval(int positionXIn, int positionYIn, int widthIn, int heightIn) {
super(positionXIn, positionYIn, widthIn, heightIn);
}
//Calculating area of oval with oval formula
public double CalcArea() {
return Math.PI * (getWidth()/2) * (getHeight()/2);
}
//The perimeter of an oval is 2 pi * square root of ((a^2+b^2)/2)
public double CalcPerimeter() {
double a = getWidth() / 2.0;
double b = getHeight() / 2.0;
double perimeter =2*Math.PI*Math.sqrt((Math.pow(a,2)+Math.pow(b,2))/2);
return perimeter;
}
}
class FaceFrame extends JFrame {
private FacePanel myFacePanel;
public FaceFrame(ArrayList<Face> faceListIn, int width, int height) {
setBounds(100, 100, 900, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FacePanel myFacepanel = new FacePanel(faceListIn);
}
}
Adding myFacepanel to the JFrame might be a good start...
public FaceFrame(ArrayList<Face> faceListIn, int width, int height) {
setBounds(100, 100, 900, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
FacePanel myFacepanel = new FacePanel(faceListIn);
// This might be a good place to start
add(myFacepanel);
}
... next problem ...
FacePanel(ArrayList<Face> FaceListIn){
setFaceList(FaceList);
}
Your assigning FaceList to itself (you're not using FaceListIn).
I'd get rid of the static and update the code...
class FacePanel extends JPanel {
private ArrayList<Face> FaceList;
public void setFaceList(ArrayList<Face> FaceListIn) {
FaceList = FaceListIn;
}
//draw panel
FacePanel() {
super();
}
FacePanel(ArrayList<Face> FaceListIn) {
setFaceList(FaceListIn);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Face oD : FaceList) {
oD.paintComponent(g);
}
}
}
Related
I am trying to implement langton's ant , and i did it well :
langton's ant java simulation screen
for painting in my jPanel, i override the paintComponent at each step but it take so much time for painting every black or white rectangle , i just want that at each step i only paint the two rectangle who have changed!?
So my question is, how to only paint a rectangle without changing what was painted in previous frame?
here is my code for painting
public void paintComponent(Graphics g){
g.setColor(Color.white);
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(Color.black);
int careLargeur = getWidth() / m;
int careHauteur = getHeight() / n;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(map[i][j])
g.fillRect(j*careLargeur,i*careHauteur,careLargeur,careHauteur);
}
//draw fourmi
g.setColor(Color.red);
g.fillOval(jF*careLargeur, iF*careHauteur, careLargeur, careHauteur);
}
any help? or should i give more details ?
here is the jar :
Paint your rectangles to a BufferedImage, and then draw that BufferedImage within your paintComponent method. You could also limit how much is re-drawn by using one of the repaint(...) overrides that specifies the exact rectangular region to repaint.
So your paintComponent method could be as simple as this:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
g.setColor(Color.red);
g.fillOval(jF*careLargeur, iF*careHauteur, careLargeur, careHauteur);
}
With drawing changes being made to the img BufferedImage.
Assuming that you're using a Swing Timer to drive the state changes to your model, you could
change the model, and then
update the BufferedImage based on the model changes, and
call repaint(...) on only the updated region.
Incomplete code attempt.... not yet done!
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
/**
* https://en.wikipedia.org/wiki/Langton%27s_ant
* https://stackoverflow.com/a/44930371/522444
* #author Pete
*
*/
public class LangtonsAnt {
private static final int TIMER_DELAY = 30;
private static void createAndShowGui() {
Model model = new Model(800);
View view = new View(800);
Controller controller = new Controller(model, view);
JFrame frame = new JFrame("Langtons Ant");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(view);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
controller.startTimer(TIMER_DELAY);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static class Model {
public static final String POINT = "point";
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
private int gridSize;
private boolean[][] grid; // false is white. Better to use enums
private Point oldValue;
private Point point; // ant location
public Model(int gridSize) {
this.gridSize = gridSize;
grid = new boolean[gridSize][gridSize];
int x = gridSize / 2;
int y = gridSize / 2;
setPoint(new Point(x, y));
}
public void setPoint(Point point) {
this.oldValue = this.point;
Point newValue = point;
this.point = point;
support.firePropertyChange(POINT, oldValue, newValue);
}
public Point getPoint() {
return point;
}
public boolean[][] getGrid() {
return grid;
}
public int getGridSize() {
return gridSize;
}
public void step() {
// first will hold relative new positions
int newX = 0;
int newY = 0;
boolean gridPoint = getGridPoint(point);
if (oldValue == null) {
newX = point.x;
newY = point.y - 1;
} else {
int dX = point.x - oldValue.x;
int dY = point.y - oldValue.y;
if (dX != 0) {
// from left or right
newY = dX > 0 ? 1 : -1; // assume "white" or false
newY = gridPoint ? -newY : newY; // if "black" then reverse
} else {
// from up or down
newX = dY > 0 ? -1 : 1; // assume "white" or false
newX = gridPoint ? -newX : newX; // if "black" then reverse
}
// convert from relative to absolute new positions
newX = point.x + newX;
newY = point.y + newY;
}
setGridPoint(point, !gridPoint);
setPoint(new Point(newX, newY));
}
public boolean getGridPoint(int x, int y) {
return grid[x][y];
}
public boolean getGridPoint(Point p) {
return getGridPoint(p.x, p.y);
}
public void setGridPoint(int x, int y, boolean b) {
grid[x][y] = b;
}
public void setGridPoint(Point p, boolean b) {
setGridPoint(p.x, p.y, b);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
support.addPropertyChangeListener(propertyName, l);
}
}
private static class Controller {
private Model model;
private View view;
private Timer timer;
public Controller(Model model, View view) {
this.model = model;
this.view = view;
view.setAntImg(createAntImg());
model.addPropertyChangeListener(Model.POINT, new ModelListener());
}
private BufferedImage createAntImg() {
// trivial image for now
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
g.setColor(Color.RED);
g.fillRect(0, 0, 1, 1);
g.dispose();
return img;
}
public void startTimer(int delay) {
timer = new Timer(delay, new TimerListener());
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
model.step();
}
}
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO Finish this.
// get the new point and old point
// translate model coord to view coord
// Change the state of the view's buffered image
// repaint the limited region that was changed
}
}
}
private static class View extends JPanel {
private static final Color BACKGROUND = Color.WHITE;
private BufferedImage gridImg;
private BufferedImage antImg;
private Point guiAntLocation;
private int pixelWidth;
public View(int pixelWidth) {
this.pixelWidth = pixelWidth;
gridImg = new BufferedImage(pixelWidth, pixelWidth, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = gridImg.createGraphics();
g2.setColor(BACKGROUND);
g2.fillRect(0, 0, pixelWidth, pixelWidth);
g2.dispose();
}
public int getPixelWidth() {
return pixelWidth;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (getGridImg() != null) {
g.drawImage(getGridImg(), 0, 0, this);
}
if (guiAntLocation != null && antImg != null) {
int x = guiAntLocation.x;
int y = guiAntLocation.y;
g.drawImage(antImg, x, y, this);
}
}
public void setGuiAntLocation(Point guiAntLocation) {
this.guiAntLocation = guiAntLocation;
}
public Point getGuiAntLocation() {
return guiAntLocation;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || getGridImg() == null) {
return super.getPreferredSize();
}
return new Dimension(getGridImg().getWidth(), getGridImg().getHeight());
}
public BufferedImage getGridImg() {
return gridImg;
}
public void setGridImg(BufferedImage gridImg) {
this.gridImg = gridImg;
}
public void setAntImg(BufferedImage antImg) {
this.antImg = antImg;
}
}
}
I am trying to have a series of rectangles rotating about their respective centres and moving to the right, but since the plane contains all the rectangles, all the rectangles rotate in unison about the centre of the latest added rectangle instead of independently around their respective centres. Here are the codes:
The main program:
import java.awt.Graphics2D;
import java.util.ArrayList;
public class Rectangles {
public static final int SCREEN_WIDTH = 400;
public static final int SCREEN_HEIGHT = 400;
public static void main(String[] args) throws Exception {
Rectangles game = new Rectangles();
game.play();
}
public void play() {
board.setupAndDisplay();
}
public Rectangles() {
board = new Board(SCREEN_WIDTH, SCREEN_HEIGHT, this);
rectangle_2 = new Rectangle_2();
rectangles = new ArrayList<Rectangle_2>();
}
public void drawRectangles(Graphics2D g, float elapsedTime) {
ticks++;
if (ticks % 4000 == 0) {
Rectangle_2 rectangle = new Rectangle_2();
rectangles.add(rectangle);
}
rotateRectangles(g);
drawRectangles(g);
moveRectangles(elapsedTime);
for (int i = 0; i < rectangles.size(); i++) {
Rectangle_2 rectangle = rectangles.get(i);
if (rectangle.getX() < -75) {
rectangles.remove(i);
i--;
}
}
}
public void drawRectangles(Graphics2D g) {
for (Rectangle_2 rectangle: rectangles) {
rectangle.drawRectangle(g);
}
}
public void rotateRectangles(Graphics2D g) {
for (Rectangle_2 rectangle: rectangles) {
rectangle.rotateRectangle(g);
}
}
public void moveRectangles(float elapsedTime) {
for (Rectangle_2 rectangle: rectangles) {
rectangle.move(10 * elapsedTime);
}
}
private Board board;
private Rectangle_2 rectangle_2;
private int ticks = 0;
private ArrayList<Rectangle_2> rectangles;
}
The rectangle class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Rectangle_2 {
public Rectangle_2() {
x = 0;
y = 200;
rectangle = new Rectangle((int) x, (int) y, 25, 25);
}
public void drawRectangle(Graphics2D g) {
g.setColor(Color.red);
g.draw(rectangle);
}
public void rotateRectangle(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
angle += 0.001;
g2.rotate(angle, rectangle.getX() + rectangle.getWidth() / 2, rectangle.getY() + rectangle.getHeight() / 2);
g2.setColor(Color.red);
}
public void move(float elapsedTime) {
x = x + elapsedTime;
rectangle.setLocation((int) x, (int) y);
}
public boolean collides(Rectangle r) {
return r.intersects(rectangle);
}
#Override
public String toString() {
return "Pipe [x = " + x + ", y = " + y + ", rectangle = " + rectangle + "]";
}
public Rectangle getRectangle() {
return rectangle;
}
public double getX() {
return x;
}
private double x;
private double y;
private double angle = 0;
private Rectangle rectangle;
}
The board class where the animation takes place:
import java.awt.*;
import javax.swing.*;
public class Board extends JPanel {
private static final long serialVersionUID = 1L;
public Board(int width_, int height_, Rectangles simulator_) {
width = width_;
height = height_;
game = simulator_;
lastTime = -1L;
}
public void setupAndDisplay() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JScrollPane(this));
f.setSize(width, height);
f.setLocation(200, 200);
f.setVisible(true);
this.setFocusable(true);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
boolean first = (lastTime == -1L);
long elapsedTime = System.nanoTime() - lastTime;
lastTime = System.nanoTime();
g.setColor(Color.white);
g.fillRect(0, 0, width, height);
g.setColor(Color.white);
game.drawRectangles((Graphics2D) g, (first ? 0.0f : (float) elapsedTime / 1e9f));
repaint();
}
private int width;
private int height;
private long lastTime;
private Rectangles game;
}
Please note the rectangle takes a couple of seconds to appear because of the delay implemented. Thank you :).
The Graphics context is a shared resource, that is, during a single paint cycle, all the components get the same Graphics context. Any changes you make to the Graphics context are also maintained (or compound in the case of same transformations). So this means, each time you call Graphics#rotate, you are actually compounding any of the previous rotations which might have been executed on it.
You need to change you code in two ways...
You need a independent update cycle, independent of the paint cycle
Create a local copy of the Graphics context BEFORE you apply any transformations
For example...
Rectangles becomes the main driver/engine. It's responsible for managing the entities and updating them each cycle. Normally, I'd use some kind of interface that described the functionality that other case might be able to use, but you get the idea
public class Rectangles {
public static void main(String[] args) throws Exception {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Rectangles game = new Rectangles();
game.play();
}
});
}
public void play() {
Board board = new Board(this);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(board);
f.pack();
f.setLocation(200, 200);
f.setVisible(true);
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateRectangles();
board.repaint();
lastTime = System.nanoTime();
}
});
timer.start();
}
public Rectangles() {
rectangle_2 = new Rectangle_2();
rectangles = new ArrayList<Rectangle_2>();
}
protected void updateRectangles() {
boolean first = (lastTime == -1L);
double elapsedTime = System.nanoTime() - lastTime;
elapsedTime = (first ? 0.0f : (float) elapsedTime / 1e9f);
ticks++;
if (ticks <= 1 || ticks % 100 == 0) {
Rectangle_2 rectangle = new Rectangle_2();
rectangles.add(rectangle);
}
rotateRectangles();
moveRectangles(elapsedTime);
for (int i = 0; i < rectangles.size(); i++) {
Rectangle_2 rectangle = rectangles.get(i);
if (rectangle.getX() < -75) {
rectangles.remove(i);
i--;
}
}
}
public void drawRectangles(Graphics2D g) {
for (Rectangle_2 rectangle : rectangles) {
rectangle.drawRectangle(g);
}
}
protected void rotateRectangles() {
for (Rectangle_2 rectangle : rectangles) {
rectangle.rotateRectangle();
}
}
protected void moveRectangles(double elapsedTime) {
for (Rectangle_2 rectangle : rectangles) {
rectangle.move(10 * elapsedTime);
}
}
private long lastTime = -1L;
private Rectangle_2 rectangle_2;
private int ticks = 0;
private ArrayList<Rectangle_2> rectangles;
}
Board becomes nothing more then a surface onto which the entities can be rendered
public class Board extends JPanel {
public Board(Rectangles engine) {
game = engine;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
game.drawRectangles((Graphics2D) g);
}
private Rectangles game;
}
And Rectangle_2 is a simple container of information which knows how to paint itself when given the chance. You will note the movement and rotation methods just update the state, they do nothing else.
drawRectangle first creates a copy of the supplied Graphics2D context, before it applies it's changes and renders the rectangle, when done, it calls dispose to dispose of the copy
public class Rectangle_2 {
public Rectangle_2() {
x = 0;
y = 200;
rectangle = new Rectangle((int) x, (int) y, 25, 25);
}
public void drawRectangle(Graphics2D g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.rotate(angle, rectangle.getX() + rectangle.getWidth() / 2, rectangle.getY() + rectangle.getHeight() / 2);
g2.setColor(Color.red);
g2.draw(rectangle);
g2.dispose();
}
public void rotateRectangle() {
angle += 0.001;
}
public void move(double elapsedTime) {
x = x + elapsedTime;
rectangle.setLocation((int) x, (int) y);
}
public boolean collides(Rectangle r) {
return r.intersects(rectangle);
}
#Override
public String toString() {
return "Pipe [x = " + x + ", y = " + y + ", rectangle = " + rectangle + "]";
}
public Rectangle getRectangle() {
return rectangle;
}
public double getX() {
return x;
}
private double x;
private double y;
private double angle = 0;
private Rectangle rectangle;
}
Basically, all that shows up is a JFrame with the black JPanel inside but no Ball/polygon anywhere. It's really annoying me now and I can't see the reason why. Any help greatly appreciated.
EDIT: Added code. Sorry for posting to Github, didn't know it was frowned upon.
public class Board extends JFrame {
private int width = 800;
private int height = 1000;
private int currentKeyCode = 0;
private boolean keyHeldDown = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Board b = new Board();
b.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Board() {
setSize(width, height);
setTitle("Drop");
setBackground(Color.BLACK);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
currentKeyCode = KeyEvent.VK_RIGHT;
keyHeldDown = true;
System.out.println("Right + 10");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
currentKeyCode = KeyEvent.VK_LEFT;
keyHeldDown = true;
System.out.println("Left + 10");
}
if (e.getKeyCode() == KeyEvent.VK_P) {
currentKeyCode = KeyEvent.VK_P;
keyHeldDown = true;
System.out.println("Pause");
}
}
#Override
public void keyReleased(KeyEvent e) {
keyHeldDown = false;
}
});
setContentPane(new Panel(this));
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
}
#Override
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
#Override
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
private class RepaintBoard implements Runnable {
final Board board;
public RepaintBoard(Board board) {
this.board = board;
}
#Override
public void run() {
board.repaint();
}
}
}
class Panel extends JComponent {
Ball ball;
private Board board;
public Panel(Board board) {
this.board = board;
ball = new Ball();
}
#Override
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
g.setColor(Color.BLACK);
g.drawRect(0, 0, board.getWidth(), board.getHeight());
g.drawPolygon(ball);
}
}
class Ball extends Polygon {
private int radius = 5;
private Point loc;
private int[] xPos = new int[radius * 2 + 1];
private int[] yPos = new int[radius * 2 + 1];
public Ball() {
for (int i = -radius, j = 0; i <= radius; i++, j++) {
xPos[j] = i;
yPos[j] = i;
}
new Ball(xPos, yPos, radius * 2 + 1, 100, 100);
}
public Ball(int[] xPos, int[] yPos, int points, int x, int y) {
super(xPos, yPos, points);
loc = new Point(x, y);
for (int i : xPos) {
System.out.println(i);
}
}
}
Don't have Ball extends Polygon
Put a drawBall(Grapchics g) {} method in the Ball class, and do your ball painting in there.
call the drawBall method in the paint
ball.drawBall(g);
Don't override paint, instead override paintComponent on the panel, and don't forget to call super.paintComponent
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
This new Ball(xPos, yPos, radius * 2 + 1, 100, 100); in your constructor does absolutely nothing. You should instead just use the second constructor, and create the ball with that constructor. Each ball should be different, so a no-arg constructor is pointless
So I got the bullet class:
import java.awt.*;
public class Bullet extends GameObject
{
private Player player;
private int deltaX;
public Bullet(final Player player, final int deltaX, final int xPos, final int yPos, final int width, final int height, final String img) {
this.deltaX = deltaX;
this.player = player;
this.xPos = xPos;
this.yPos = yPos;
this.height = height;
this.width = width;
this.rect = new Rectangle(xPos, yPos, width, height);
this.img = getImage(img);
}
#Override
public void draw(Graphics g)
{
g.drawImage(img, xPos, yPos, width, height, null);
}
#Override
void update(final Shooter shooter, final int id)
{
if(rect.intersects(player.rect))
{
shooter.bullets.remove(this);
if(!(shooter.player1.getHull() == 0))
{
player.setHealth(player.getHealth() - 1);
if(!(getStamina() < 1))
if(shooter.player1.getStamina() > 10)
shooter.player1.setStamina(shooter.player1.getStamina() - 10);
else
shooter.player1.setStamina(shooter.player1.getStamina() - 1);
else
shooter.player1.setStamina(shooter.player1.getStamina() - 0);
}
else
{
player.setHealth(player.getHealth() - 2);
}
if(!(player.getHull() == 0))
player.setHull(player.getHull() - 2);
else
player.setHull(player.getHull() - 0);
}
else if (yPos < -100 || yPos > 2000)
{
shooter.bullets.remove(this);
}
else
{
if(deltaX == 1)
{
yPos++;
rect.y++;
}
else
{
yPos--;
rect.y--;
yPos--;
rect.y--;
}
}
}
public void setPlayer(Player player) {
this.player = player;
}
public Player getPlayer()
{
return player;
}
#Override
Image getImage(String img) {
return Toolkit.getDefaultToolkit().getImage(img);
}
public int getDeltaX() {
return deltaX;
}
public void setDeltaX(int deltaX) {
this.deltaX = deltaX;
}
}
And this is my Meteor class:
import java.awt.*;
public class Meteor extends GameObject
{
private Player player;
private int deltaX;
public Meteor(final Player player, final int deltaX, final int xPos, final int yPos, final int width, final int height, final String img) {
this.deltaX = deltaX;
this.player = player;
this.xPos = xPos;
this.yPos = yPos;
this.height = height;
this.width = width;
this.rect = new Rectangle(xPos, yPos, width, height);
this.img = getImage(img);
}
#Override
public void draw(Graphics g)
{
g.drawImage(img, xPos, yPos, width, height, null);
}
#Override
void update(final Shooter shooter, final int id)
{
if (yPos < -100 || yPos > 2000)
{
shooter.meteors.remove(this);
}
else
{
if(deltaX == 1)
{
yPos++;
rect.y++;
}
else
{
yPos++;
rect.y++;
}
}
if(rect.intersects(shooter.player1.rect))
{
System.out.println("Collision");
shooter.meteors.remove(this);
shooter.player1.setHealth(shooter.player1.getHealth() - 100);
}
}
public void setPlayer(Player player) {
this.player = player;
}
public Player getPlayer()
{
return player;
}
#Override
Image getImage(String img) {
return Toolkit.getDefaultToolkit().getImage(img);
}
public int getDeltaX() {
return deltaX;
}
public void setDeltaX(int deltaX) {
this.deltaX = deltaX;
}
}
Now in the Meteor class i want to use this:
if(bullet.rect.intersect(shooter.player1.rect)
{..}
But this is not working because I cannot reference from it the bullet class. Is there any way to make it working?
This is the GameObject class
import java.awt.*;
public abstract class GameObject
{
protected Rectangle rect;
protected int xPos;
protected int yPos;
protected int height;
protected int width;
protected Image img;
protected int health;
protected int stamina;
protected int hull;
abstract void draw(Graphics g);
abstract void update(final Shooter shooter, final int id);
abstract Image getImage(String img);
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getStamina() {
return stamina;
}
public void setStamina(int stamina) {
this.stamina = stamina;
}
public Rectangle getRect() {
return rect;
}
public void setRect(Rectangle rect) {
this.rect = rect;
}
public int getHull() {
return hull;
}
public void setHull(int hull) {
this.hull = hull;
}
public int getxPos() {
return xPos;
}
public void setxPos(int xPos) {
this.xPos = xPos;
}
public int getyPos() {
return yPos;
}
public void setyPos(int yPos) {
this.yPos = yPos;
}
public Image getImg() {
return img;
}
public void setImg(Image img) {
this.img = img;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
Rect seems to be a protected attribute of the GameObject class.
You can add a public getter in your Bullet class.
public Rectangle getRect() {
return rect;
}
and then call it:
if(bullet.getRect().intersect(shooter.player1.rect))
The quick fix is
bullet.getRect().intersect(shooter.getPlayer().getRect())
A longer answer is
You need to give some thought to how your classes interact with each other. A book I would recommend is called "Head First Design Patterns."
One example is that you could simplify your code with a delegate method on the GameObject class. Your bullets, shooters, and meteors probably don't need to know or care whether the collision logic is implemented using Rectangle. Additionally, you might need to change your collision logic.
Sample method on GameObject
public boolean intersect (GameObject anotherObject) {
return this.rect.intersect(anotherObject.rect);
}
Then your code would be
bullet.intersect(shooter.getPlayer())
First of all you need a reference to Bullet within Meteor. For instance create a property
private Bullet bullet;// in this moment reference is not set up (it means bullet == null)
and set it by a defined by yourself setter method or pass a reference as a constructor parameter (depends on what are objects relations and your design).
Rectangle property of Bullet object should be defined as private/ protected and inside Meteor fetched by getter (because of encapsulation good pattern).
So it means
Rectangle rectangle = bullet.getRectangle();
where getRectangle() is a defined, by you, getter for rect property.
Additionally I advice you to read about encapsulation.
At the beginning take a look here
http://docs.oracle.com/javase/tutorial/java/javaOO/variables.html
http://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
I created a program that makes multiple bouncing balls with random color, speed and radius. When user clicks on the screen a new random ball should appear and move around screen. But i have a multi-thread issue. When i click on the screen a ball appears and doesn't moving at all. When another click comes nothing happens.
BouncingBalls Class
public class BouncingBalls extends JPanel implements MouseListener{
private Ball ball;
protected List<Ball> balls = new ArrayList<Ball>(20);
private Container container;
private DrawCanvas canvas;
private int canvasWidth;
private int canvasHeight;
public static final int UPDATE_RATE = 30;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int count = 0;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height){
canvasWidth = width;
canvasHeight = height;
ball = new Ball(x, y, speedX, speedY, radius, red, green, blue);
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
}
public void start(){
Thread t = new Thread(){
public void run(){
while(true){
update();
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException e) {}
}
}
};
t.start();
}
public void update(){
ball.move(container);
}
class DrawCanvas extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
container.draw(g);
ball.draw(g);
}
public Dimension getPreferredSize(){
return(new Dimension(canvasWidth, canvasHeight));
}
}
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
JFrame f = new JFrame("Bouncing Balls");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(500, 500));
f.pack();
f.setVisible(true);
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
count++;
balls.add(new Ball(x, y, speedX, speedY, radius, red, green, blue));
balls.get(count-1).start();
start();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
Ball Class
import java.awt.Color;
import java.awt.Graphics;
public class Ball{
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
private BouncingBalls balls;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int i = 0;
public Ball(int x, int y, int speedX, int speedY, int radius, int red, int green, int blue){
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
this.radius = radius;
this.red = red;
this.green = green;
this.blue = blue;
}
public void draw(Graphics g){
for(Ball ball : balls){
g.setColor(new Color(red, green, blue));
g.fillOval((int)(x - radius), (int)(y - radius), (int)(2 * radius), (int)(2 * radius));
}
}
public void move(Container container){
x += speedX;
y += speedY;
if(x - radius < 0){
speedX = -speedX;
x = radius;
}
else if(x + radius > 500){
speedX = -speedX;
x = 500 - radius;
}
if(y - radius < 0){
speedY = -speedY;
y = radius;
}
else if(y + radius > 500){
speedY = -speedY;
y = 500 - radius;
}
}
}
Container Class
import java.awt.Color;
import java.awt.Graphics;
public class Container {
private static final int HEIGHT = 500;
private static final int WIDTH = 500;
private static final Color COLOR = Color.WHITE;
public void draw(Graphics g){
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
You're maintaing two different references to your ball.
You have a reference to a single Ball called ball and a List of balls. Your update and paint methods only reference the single ball
Ball doesn't seem to have a start method (that I can see) so this balls.get(count-1).start(); doesn't make sense...
Updated
You don't need the reference to ball
While not a bad idea, while testing, you should probably call start in the constructor
Your update method in BouncingBalls should looping through the balls list, calling move on each ball in the list...
The paintComponent method of DrawCanvas needs access to and should make use of the balls list. This might be better achievable through a model interface
Do not construct a new Ball with parameters, as it's giving each ball the same properties, especially when you assign random values to it when you construct it any way...
Ball doesn't have (or need) a start method
public class BouncingBalls extends JPanel implements MouseListener {
// private Ball ball;
protected List<Ball> balls = new ArrayList<Ball>(20);
private Container container;
private DrawCanvas canvas;
private int canvasWidth;
private int canvasHeight;
public static final int UPDATE_RATE = 30;
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int count = 0;
public static int random(int maxRange) {
return (int) Math.round((Math.random() * maxRange));
}
public BouncingBalls(int width, int height) {
canvasWidth = width;
canvasHeight = height;
// ball = new Ball(x, y, speedX, speedY, radius, red, green, blue);
container = new Container();
canvas = new DrawCanvas();
this.setLayout(new BorderLayout());
this.add(canvas, BorderLayout.CENTER);
this.addMouseListener(this);
start();
}
public void start() {
Thread t = new Thread() {
public void run() {
while (true) {
update();
repaint();
try {
Thread.sleep(1000 / UPDATE_RATE);
} catch (InterruptedException e) {
}
}
}
};
t.start();
}
public void update() {
for (Ball ball : balls) {
ball.move(container);
}
}
class DrawCanvas extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
container.draw(g);
for (Ball ball : balls) {
ball.draw(g);
}
// ball.draw(g);
}
public Dimension getPreferredSize() {
return (new Dimension(canvasWidth, canvasHeight));
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("Bouncing Balls");
f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
f.setContentPane(new BouncingBalls(500, 500));
f.pack();
f.setVisible(true);
}
});
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent e) {
count++;
balls.add(new Ball());
// balls.add(new Ball(x, y, speedX, speedY, radius, red, green, blue));
// balls.get(count - 1).start();
// start();
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
public static class Ball {
public int random(int maxRange) {
return (int) Math.round(Math.random() * maxRange);
}
int x = random(480);
int y = random(480);
int speedX = random(30);
int speedY = random(30);
int radius = random(20);
int red = random(255);
int green = random(255);
int blue = random(255);
int i = 0;
public Ball() { //int x, int y, int speedX, int speedY, int radius, int red, int green, int blue) {
// this.x = x;
// this.y = y;
// this.speedX = speedX;
// this.speedY = speedY;
// this.radius = radius;
// this.red = red;
// this.green = green;
// this.blue = blue;
}
public void draw(Graphics g) {
g.setColor(new Color(red, green, blue));
g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius), (int) (2 * radius));
}
public void move(Container container) {
x += speedX;
y += speedY;
if (x - radius < 0) {
speedX = -speedX;
x = radius;
} else if (x + radius > 500) {
speedX = -speedX;
x = 500 - radius;
}
if (y - radius < 0) {
speedY = -speedY;
y = radius;
} else if (y + radius > 500) {
speedY = -speedY;
y = 500 - radius;
}
}
}
public static class Container {
private static final int HEIGHT = 500;
private static final int WIDTH = 500;
private static final Color COLOR = Color.WHITE;
public void draw(Graphics g) {
g.setColor(COLOR);
g.fillRect(0, 0, WIDTH, HEIGHT);
}
}
}
Updated
As pointed out by the commentators, ArrayList is not thread safe, it's not a good idea to have multiple threads trying to access it simultaneously. While adding is slightly safer then removing, it is still bad practice.
You can either replace ArrayList with Vector, which would be the simpler solution, or synchronize the access to the list around a common monitor lock. Given your example, I'd use a java.util.Vector
You Can try this alternate Java Programm for bouncing 10 multi-colored balls on a single "START" button.....
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javaimage.io.*;
class Thr extends Thread
{
boolean up=false;
Ballbounce parent;
int top,left;
Color c;
Thr(int t,int l,Color cr,ex5 p)
{
top=l;
if(top > 170)
top=170-t/8;
left=t;
c=cr;
parent=p;
}
public void run()
{
try
{
while(true)
{
Thread.sleep(37);
if(top >= 188)
up=true;
if(top <= 0)
up=false;
if(!up)
top=top+2;
else
top=top-2;
parent.p.repaint();
}
}catch(Exception e){}
}
}
class Ballbounce extends JFrame implements ActionListener
{
int top=0,left=0,n=0,radius=50;
Color C[]={Color.black,Color.cyan,Color.orange,Color.red,Color.yellow,Color.pink,Color.gray,Color.blue,Color.green,Color.magenta};
Thr t[]=new Thr[10];
GPanel p;
JButton b;
Panel p1;
Ballbounce()
{
setSize(700,300);
setVisible(true);
setLayout( new BorderLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(p=new GPanel(this),BorderLayout.CENTER);
b= new JButton("Start");
b.addActionListener(this);
add(p1=new Panel(),BorderLayout.SOUTH);
p1.setBackground(Color.lightGray);
p1.add(b);
}
public static void main(String args[])
{
new Ballbounce();
}
public void actionPerformed(ActionEvent e)
{
t[n]=new Thr(left+(radius+13)*n+29,top+n*25,C[n],this);
t[n].start();
n++;
p.repaint();
if(n >9)
b.setEnabled(false);
}
}
class GPanel extends JPanel
{
Ballbounce parent;
GPanel(Ballbounce p)
{
parent=p;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.white);
for(int i=0;i< parent.n;i++)
{
g.setColor(parent.t[i].c);
g.fillOval(parent.t[i].left,parent.t[i].top,parent.radius,parent.radius);
}
}
}
I hope you will like it....
If u are unable to understand the code... You can question it anytime...... :)
Enjoy the code... :)