JFrame help - passing value into PaintComponent() - java

I've been working on a small "game" project for a while now and haven't been able to pass a value into my paintComponent method in any way.
Here's my program. I used a boolean test parameter, but the paintComponent method does not consider test to be true and not paint the blue square.
How can I fix this? Any help would be greatly appreciated.
Class 1 (Swing):
package swing;
import javax.swing.*;
import javax.*;
import java.awt.*;
import java.awt.event.*;
public class swing {
private static draw object = new draw();
public static void main(String[] args) {
JFrame frame = new JFrame("RogueLikeLike MVP");
frame.setVisible(true);
frame.setFocusable(true);
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);;
frame.add(object);
}
static class Move implements KeyListener{
public boolean isFocusTraversable ( ) {
return true;
}
public void keyPressed(KeyEvent e) {
int x = 10;
int y = 10;
char c = e.getKeyChar();
if(c == 's')
y+=10;
if(c == 'a')
x-=10;
if(c == 'w')
y-=10;
if(c == 'd')
x+=10;
object.setAlignmentX(x);
object.setAlignmentY(y);
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
}
}
Class 2 (draw):
package swing;
import javax.swing.*;
import java.awt.*;
public class draw extends JPanel
{
boolean test = true;
private static final long serialVersionUID = 1L;
/*public void passMethod(draw object) {
int x = (int) object.getAlignmentX();
int y = (int) object.getAlignmentY();
}*/
public void drawing(draw object){
draw thing = new draw();
thing.setX(object.getAlignmentX());
int x = 55;
repaint();
}
private void setX(float alignmentX) {
setX((int) alignmentX);
}
private void setY(float alignmentY) {
setY((int) alignmentY);
}
public void paintComponent(Graphics g, boolean test){
super.paintComponents(g);
//int x = (int)object.getAlignmentX();
//int y = (int)object.getAlignmentY();
if(test==true)
{
g.setColor(Color.blue);
g.fillRect(getX(),getY(),100,100);
}
}
}

paintComponent can be overloaded, but the overloaded version won't be used to paint the Component. Actually paintComponent isn't called by the user, but by the painting routine. Instead of overloading the method you should consider using a variable for test and reading/updating this variable.
Like this:
private boolean test = true;
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if(test){
//the rest of the code
}
}

Short answer, you can't. This isn't how method overriding works.
paintComponent is one of the documented methods used by the painting sub system to allow you to plugin custom painting, in order to work it MUST match a very particular method signature, otherwise, how would the API know what to call
Instead, paintComponent should paint the current known state of the component, either directly or indirectly.
What this means is, you component should either have a set of properties which the paintComponent method can access or some other object (ie a model) which it can use to determine the current state of which to paint.
You could use a delegate approach, which would allow to define a contract (maybe via a interface) which paintComponent could call, passing the information you need to these delegates, in order for them to perform the required painting.
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works
nb:
Add the #Override annotation above your paintComponent method, the compiler will error telling you that their is no matching method which supports your signature
Call super.paintComponent NOT super.paintComponent"s", this would set up a recursive call which would result in a StackOverflowError

Related

I am not sure what is incorrect

I am creating a small Java Jpanel game in which I am supposed to have a rocket that moves up and down via arrows and fires via space.
The firing method should work like this: Space bar pressed, thing fires and moves across screen , and then when it hits a certain x, it disappears. Also, you can only fire once until the other bullet disappears.
I do not know what I am doing wrong. For one, as soon as my code starts you can see a bullet flying across the screen.
2nd, the bullet is not disappearing.
3rd, even though the other bullet is still visible, it allows me to fire again.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class SpaceGame extends JPanel implements ActionListener{
Timer t = new Timer(2, this);
private ImageIcon rocket,asteroid,bullet;
private JLabel rocketlabel,ast1,ast2,ast3,bulletLabel;
public static int y=90,dy=0,bulletX=110,bulletY,i=0,canFire;
//public sound sound;
static boolean bulletFired=false;;
static JFrame f = new JFrame();
SpaceGame(){
this.setBackground(Color.black);
rocket = new ImageIcon(getClass().getResource("rocketFinal.png"));
rocketlabel= new JLabel(rocket);
this.add(rocketlabel);
asteroid = new ImageIcon(getClass().getResource("asteroid.png"));
ast1=new JLabel(asteroid);
ast2=new JLabel(asteroid);
ast3=new JLabel(asteroid);
bullet = new ImageIcon(getClass().getResource("bulletReal.png"));
bulletLabel = new JLabel(bullet);
canFire=1;
bulletLabel.setVisible(false);
this.add(ast1);this.add(ast2);this.add(ast3);this.add(bulletLabel);
f.addKeyListener(new controller());
this.setLayout(null);
this.setVisible(true);
}
public class controller implements KeyListener{
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode== KeyEvent.VK_UP) {
dy=-1;
}
if(keyCode== KeyEvent.VK_DOWN) {
dy=1;
}
if(keyCode== KeyEvent.VK_SPACE) {
if(canFire==0) {
System.out.println(String.valueOf(canFire));
bulletFired = true;
bulletY = y;
bulletX=110;
}canFire=1;
}
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch(key) {
case KeyEvent.VK_UP: dy=0; break;
case KeyEvent.VK_DOWN: dy=0; break;
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
rocketlabel.setBounds(45,y,rocket.getIconWidth(),80);
fireBullet();
paintStars(g);
t.start();
}
public void paintStars(Graphics g) {
g.setColor(Color.yellow);
for(int i=0; i<5;i++) {
Random rand = new Random();
int o = rand.nextInt(500);
int p = rand.nextInt(300);
g.fillOval(o, p, 3, 3);
}
}
public void actionPerformed(ActionEvent e) {
if(y==-20) y=249;
if(y==250)y=-20;
y+=dy;
if(bulletFired=true) {
bulletX++;
if(bulletX==455)bulletFired=false;bulletLabel.setVisible(false);System.out.println(String.valueOf(bulletX)); canFire=0;
}
repaint();
}
public void fireBullet(){
if(bulletFired=true) {
bulletLabel.setVisible(true);
bulletLabel.setBounds(bulletX,bulletY+25,bullet.getIconHeight(),bullet.getIconWidth());
}
}
public static void main(String[] args) {
String filepath = "SpaceGameMusic.wav";
musicStuff musicPlayer = new musicStuff();
musicPlayer.playMusic(filepath);
SpaceGame t = new SpaceGame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(t);
f.setSize(500,335);
f.setVisible(true);
f.setResizable(false);
}
}
For one, as soon as my code starts you can see a bullet flying across the screen.
The paintComponent() method is for painting only. You can't control when Swing will determine a component needs to be repainted.
So, for example:
t.start();
should NOT be in the painting method. As soon as the frame is made visible the panel will be painted and the Timer will be started.
You application code should control when the Timer is started.
Other issues:
you should not be using static variables. The variable should simply be instances of your class.
the paintStars() method should not generate random locations. Again. a painting method should only paint the current state of the class. So if you want to change the location of the stars you should have a method like randomizeStars(). In this method you would update an ArrayList of Point objects. Each Point instance would represent the location of a star. Then the paintStars() method would simply iterate through the ArrayList and paint each star.
you should not be using a KeyListener. A KeyListener only works if a component has focus. You can't guarantee that your component will lose focus. Instead you should be using Key Bindings. Key bindings allow you to handle a KeyEvent even if the component doesn't have focus. See Motion Using the Keyboard for more information and a working example.
you can only fire once until the other bullet disappears
Your canFire variable should be a boolean variable so it only has true/false values. Again you have a method that sets the state. Your game logic will then check the state before firing the bullet again.
if(y==-20) y=249;
if(y==250)y=-20;
Don't hardcode values. The number should be based on the size of your panel. So you use methods like getWidth() and getHeight() to determine the current size of the panel.
The problem was quite simply that I had forgotten to use == in my if(boolean) statements.

Java Drawing Multiple Squares in Same JFrame

I am trying to make an animation with multiple thread. I want to paint n squares where this n comes from commend-line argument. Every square has their x-y coordinates, colors and speed. They are moving to the right of the frame with different speed, color and coordinates. Since I am using multi thread I assume I have to control each squares. So I have to store each square object in the ArrayList. However, I am having trouble with painting those squares. I can paint one square but when I try to paint multiple squares, it does not show. Here what I have done so far:
DrawSquare.java
import java.awt.Graphics;
import javax.swing.JPanel;
public class DrawSquare extends JPanel {
public Square square;
public DrawSquare() {
square = new Square();
}
#Override
public void paintComponents(Graphics g) {
// TODO Auto-generated method stub
super.paintComponents(g);
}
#Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.setColor(square.getC());
g.fillRect(square.getX(), square.getY(), square.getR(), square.getR());
}
}
Square.java
import java.awt.Color;
import java.util.Random;
public class Square {
private int x,y,r,s;
private Color c;
private Random random;
public Square() {
random = new Random();
x = random.nextInt(100) + 30;
y = random.nextInt(100) + 30;
r = random.nextInt(50) + 20;
s = random.nextInt(20) + 5;
c = new Color(random.nextInt(255),random.nextInt(255),random.nextInt(255));
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getR() {
return r;
}
public int getS() {
return s;
}
public Color getC() {
return c;
}
}
Animation.java
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Animation extends JFrame implements Runnable {
private JPanel panel;
private DrawSquare square;
public Animation() {
}
public static void main(String[] args) {
Animation w = new Animation();
DrawSquare square = new DrawSquare();
JFrame f = new JFrame("Week 9");
int n = Integer.parseInt(args[0]);
f.setVisible(true);
f.setSize(700,700);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
for(int i=0; i<n; i++) {
f.getContentPane().add(square);
}
}
#Override
public void run() {
// TODO Auto-generated method stub
}
}
So, starting with...
public class DrawSquare extends JPanel {
public Square square;
public DrawSquare() {
square = new Square();
}
#Override
public void paintComponents(Graphics g) {
// TODO Auto-generated method stub
super.paintComponents(g);
}
#Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.setColor(square.getC());
g.fillRect(square.getX(), square.getY(), square.getR(), square.getR());
}
}
As general recommendation, it's preferred to put custom painting in the paintComponent method (note, there's no s at the end)
When paint is called, the Graphics context has already been translated to the component coordinate position. This means that 0x0 is the top/left corner of the component, this also means that...
g.fillRect(square.getX(), square.getY(), square.getR(), square.getR());
is painting the rect at x + x x y + y, which will, at the very least, paint the rect in the wrong position, at worst paint it beyond the visible scope of the component.
You're also not providing any sizing hints for the component, so it's default size will be 0x0, which prevent it from been painted.
Since I am using multi thread I assume I have to control each squares.
Well, since I can't really see what's driving the animation, I imagine that when you say "multi thread" you're suggesting that each square has it's own Thread. In this case, that's a bad idea. Let's put aside the thread synchronisation issues for a moment, more threads doesn't equate to more work you can do, at some point, it will begin to degrade the system performance.
In most cases, a single, well managed thread, is all you really need. You also have to understand that Swing is NOT thread safe. This means that you shouldn't update the UI (or states that the UI relies on) from outside the context of the Event Dispatching Thread.
So, while you're thread can update the position of the rects, you need to take care to ensure that they are not been painted while they are been update. Once you've updated the state, you then need to trigger a paint pass (which is trivial in of itself)
So I have to store each square object in the ArrayList.
Yep, good start
However, I am having trouble with painting those squares. I can paint one square but when I try to paint multiple squares, it does not show.
Okay, so instead of using multiple components, use one. Run through your ArrayList within the paintComponent method of this component and paint all the rects to it. This provides a much simpler way to manage things like bounds detection, as you have only one container to worry about.
I'd highly recommend you have a look at:
Java Bouncing Ball which demonstrates many of the concepts discussed here
Concurrency in Swing
How to use Swing Timers
Performing Custom Painting
Painting in AWT and Swing

Calling paint method from class which doesn't extend JFrame

I have a class Game which extends JFrame and create the window I want to paint on. Then I have this class Diewhich paints what I want. From Game I can just call the setup() method in the Die class, but how do I then call the paint() method?
public class Die
{
private int xA, yA;
private int dieNumber;
public void setup(int someX, int someY, int someValue) {
dieNumber = someValue;
xA = someX;
yA = someY;
}
public void paint(Graphics pane) {
drawBlank(pane);
if (dieNumber == 1){
drawOne(pane); }
else if (dieNumber == 2){
drawTwo(pane); }
else if (dieNumber == 3){
......
It is a far more better approach if your die extends JPanel and make the custom drawing overriding the paintComponent:
public class Die extends JPanel
{
private int xA, yA;
private int dieNumber;
public void setup(int someX, int someY, int someValue) {
dieNumber = someValue;
xA = someX;
yA = someY;
}
#Override
public void paintComponent(Graphics pane) {
super.painComponent(pane);
if (dieNumber == 1){
drawOne(pane); }
else if (dieNumber == 2){
drawTwo(pane); }
else if (dieNumber == 3){
......
}
You would likely do your graphics in the protected void paintComponent(Graphics g) method override of a JPanel, and inside that method, call die.paint(g) on any Die objects that you need to draw.
e.g.,
class DrawingPanel extends JPanel {
private Die die1 = new Die();
private Die die2 = new Die();
//.....
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
die1.paint(g);
die2.paint(g);
}
}
For more specific and detailed help, please try to create and post a minimal example program or MCVE, a small program that we can run and compile and that will show us your problem. There's a lot of pertinent code that you still need to show us -- but without showing us too much code, which is where the MCVE will help.
Also never do graphics in a JFrame's or Frame's paint method, and you shouldn't use Frame or AWT components anyway. Please read the Swing Graphics tutorials before going forward with this. With regards to why you can't call paint from setup -- Swing graphics are passive and cannot be called on command. You should instead do as I recommend, and suggest to the paint managher that painting be done by calling repaint() on the JPanel. But again, this is explained in the tutorial that you have not yet read. So first and foremost, fix this -- read the tutorial.
Swing tutorials can be found from this link: Swing Info.

Calling repaint from another class JFrame

I'm trying to call repaint from another class. But it does not work. I have to draw on a frame.
public class Tester extends JFrame{
public static dtest d ;
public static void main(String[] args) {
Tester t = new Tester();
d = new dtest();
test tnew = new test();
}
public static class dtest extends JFrame implements MouseMotionListener{
public static int x,y;
dtest()
{
super("title");
setSize(500,500);
setVisible(true);
addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
public void paint(Graphics g)
{
System.out.println("I am called");
}
}
public static class test {
public test()
{
for(int i = 0 ; i < 5 ; i++)
{
System.out.println("I am called from run");
d.repaint();
}
}
}
}
this prints
I am called from run
I am called from run
I am called from run
I am called from run
I am called from run
so it does not executing the paint() portion. d.repaint() is not working. why?
Take a look at this page and look at the first answer. It's a similar if not exact question to yours.
JFrame's paint() method has been deprecated. The compiler, or your IDE, should be complaining a bit, especially if you place the #Override tag directly above the method (use this to test if this method can be rewritten... aka what you're trying to do).
This means that its use has been discouraged and some functionality may have been removed. When using javax.swing, you'll want to learn the system completely about JPanels and JComponents. To paint something on a screen, you'll want to add a custom class that extends JPanel with the add(Component c) method. Then, override the paintComponent(Graphics g) method in that class. Make sure to have the first line in that method be super.paintComponent(g); so that the window can refresh itself.
For completeness:
public class MyWindow extends JFrame {
MyPanel thePanel;
public MyWindow(int x, int y) {
setSize(x, y);
thePanel = new MyPanel(x, y);
this.add(thePanel);
}
}
public class MyPanel extends JPanel {
public MyPanel(int x, int y)
setSize(x, y);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(ImageManager.getImage("Cute Puppy"), 40, 40, null); // Or whatever
}
}
So, when the repaint() or revalidate() method is called on the MyWindow, the Panel will recieve a paintComponent call.
Please let me know in the comments if you need any additional help.
Edited:
Since you need to use MouseMotionListener, and I'm still not quite understanding the context and trouble of "I need to call repaint from another class"... I will try my best.
Firstly, check out this tutorial on the Oracle pages. Also, check out the others on GUI's. You'll learn a lot about organization and displaying that will make you realize how their system can work with yours.
Now, for your questions:
i have to use MouseMotionListener.
Not quite... it is a good way for set up but you can run a Thread (something that constantly runs methods over and over) to check the Mouse coordinates. You'll want to start doing this when you get into games and other miscellaneous applications.
new Thread() {
public void run() {
Point mouse;
int mousex;
int mousey;
while (true) {
mouse = MouseInfo.getPointerInfo().getLocation();
mousex = mouse.x - theWindow.getLocationOnScreen().x - 3; // You'll need to get the
// x coordinate, subtract the window's x coordinate, and subtract 3 because of
// the blue border around a standard pc window.
mousey = mouse.y - theWindow.getLocationOnScreen().y - 29; // 29 is top bar height
SomeOtherClass.processMove(mousex, mousey);
}
}
}.start();
Next: I tried that with JPanel but i could not do that. If you read the tutorial at the top of my edit, you see they implement MouseMotionListener with ease.
Next: I prefer to do it with JFrame. If you wish to process the mouse in the JFrame, do the following: Have your JFrame the listener, but the JPanel be where the mouse data comes from. As follows:
public class MyWindow extends JFrame implements MouseMotionListener {
public MyPanel thePanel;
public int x;
public int y;
public MyWindow() {
thePanel = new MyPanel();
thePanel.addMouseMotionListener(this);
// Make this JFrame get called when the mouse
// moves across the panel.
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
thePanel.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Other painting stuff
}
}
Next: Now i have to update the frame from another class. I could not find a way to update the GUI(the frame) from another class.
Simple. Since the JPanel is what needs to be updated, add the following method to the MyWindow class:
public void repaintWindow() {
thePanel.repaint();
}
And add this to whenever you need to update it:
MyWindow theWindow = new MyWindow();
theWindow.repaintWindow();
Next: all the answers here extended JPanel. So i could not find my answer.
I apologize, but you NEED a panel. It is possible to do with JFrames, but if you want to start doing things raw and low-level, you need to learn how these things work by learning to read the oracle tutorials and the oracle documentation. For now, use JPanels in any ways I've shown you.
Next: from another class I have to draw something on JFrame.Is that possible?
Yes, indeed! Whenever you want to draw something:
MyWindow theWindow = new MyWindow();
Graphics g = theWindow.thePanel.getGraphics();
BufferedImage someRandomImage = SomeRandomClass.getRandomImage();
g.drawImage(someRandomImage, 200, 481, null);
theWindow.repaintWindow();
I really hope I've helped but to program in java you need to use the tools they give you, especially when it comes to high level things like Swing. There are tutorials everywhere for this stuff. Please read them before asking for specific help in the future.

How to delete an JPanel Object?

Im on to create a little "game", something like an 2d AirForce Shooter.
So, i have a problem with deleting unused enemys.
An Enemy is an simple JPanel, which is saved in the main logic as an array List.
public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();
The Enemy run logic does the following:
while(!destroyed){
if(Game.running){
x--;
if(getBounds().intersects(Field.player.getBounding())){
Player.death = true;
}
if(x < 0){
Field.deleteEnemy(this);
}
setBounds((int) x, (int) y, 100, 50);
try{Thread.sleep(10);}catch(InterruptedException e){}
}
}
So you can seem there i already tried to call the method deleteEnemy, and just give it the unused Enemy.
But it isnt possible - when i just do this:
public static void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
}
It will be just removed from the list, but coninues existing on the Main JPanel.
And i cannot say
remove(e);
Because then i try to call a non static function in a static.
So, how could i delete an Enemy? Someone knows?
Thanks for help!
The hole code: (Game.java)
And, Enemy.java:
package Game;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Field extends JPanel implements Runnable{
public static Player player = new Player();
public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();
private Thread moveBackground = new Thread(this);
private boolean bgMoving = false;
public static boolean addMob = false;
private int x = 0;
private int bgSpeed = -1;
public Field(){
setBounds(0, 0, 800, 600);
setFocusable(true);
setLayout(null);
addKeyListener(new Handler());
add(player);
}
public void paintComponent(Graphics g){
Field.super.paintComponent(g);
g.drawImage(Images.images[0], x, 0, this);
}
public static void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
}
public void run(){
while(!Player.death){
if(bgMoving){
bgMoving = true;
x += bgSpeed;
if(x < -(Images.images[0].getWidth(this) - this.getWidth() - 20)){
bgMoving = false;
}
repaint();
try { Thread.sleep(20); } catch (InterruptedException e) {}
}
if(addMob){
enemys.add(new Enemy());
add(enemys.get(enemys.size() - 1));
addMob = false;
}
}
JOptionPane.showMessageDialog(null, "DIED!");
}
public class Handler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
player.KeyPressed(e);
if(!bgMoving){
if(Game.running){
bgMoving = true;
if(moveBackground.getState().toString() == "NEW"){
moveBackground.start();
}
}
}
}
public void keyReleased(KeyEvent e) {
player.KeyReleased(e);
}
}
}
And, Enemy.java:
package Game;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Enemy extends JPanel implements Runnable{
Thread t = new Thread(this);
private double x = Game.width();
private double y = Math.random() * Game.height();
private double xF = 0, yF = 0;
private boolean destroyed = false;
public Enemy(){
setBounds((int) x, (int) y, 100, 50);
setOpaque(false);
t.start();
}
public void paintComponent(Graphics g){
Enemy.super.paintComponent(g);
g.setColor(Color.GREEN);
g.drawImage(Images.images[2], 0, 0, this);
}
public void run() {
while(!destroyed){
if(Game.running){
x--;
if(getBounds().intersects(Field.player.getBounding())){
Player.death = true;
}
if(x < 0){
Field.deleteEnemy(this);
}
setBounds((int) x, (int) y, 100, 50);
try{Thread.sleep(10);}catch(InterruptedException e){}
}
}
}
}
After removing you will need to call revalidate() and repaint()
[Too long for a comment]
I think the problem is in your logic on removing an Enemy/JPanel:
You are removing it from the ArrayList only, what about the containing JPanel/JFrame you added it to?
You must remove the JPanel from its container (maybe another JPanel or the JFrame) not just the ArrayList via Component#remove(Component c).
If you drew the Enemy images directly in paintComponent(...) of your container via iterating the ArrayList; removing it from the ArrayList would be sufficient, as it will no longer be in the Array and thus no longer drawn on the next repaint().
+1 to #Optional, you may need to call revalidate() and repaint() on the container for the affects of the removed JPanel/Enemy to be shown.
Also as #darijan mentioned, the use of static variables along with instance is not really a great design (though for certain designs this may be fine).
In your case if you need access to an instance method of another class, within another class, simply pass the instance of the class whos method you would like to access to the object which will access it.
Here is some psuedo code expressing much of the above mentioned problems / solutions:
public class Field extends JPanel {
private ArrayList<Enemy> enemies;
public Field() {
...
enemies.add(new Enemy(this));//create a new enemy and pas it the JPanel instance so it may access instance methods of this class
}
//ONLY USED IF JPanel for Enemy is ommited and Enemy class created which represents Enemy object and not Enemy object and aJPanel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
ArrayList<Enemy> enemiesClone = new ArrayList<>(enemies);//copy array into another so we don't get a ConcurrentModificaton exception if removeEnemy is called while iterating the list
if(!enemiesClone.isEmpty())
for(Enemy e:enemiesClone) {//iterate through array of images
draw(e.getImage(),e.getX(),e.getY(),this);
}
}
public void removeEnemy(Enemy e) {
enemies.remove(e);//remove from the array
//ONLY USED IF JPanels are used as Enemy
remove(e);//remove from the JPanel
//so the changes of removed panel can be visible seen
revalidate();
repaint();
}
}
class Enemy extends JPanel //extends JPanel should be ommited for paintComponent method of drawing an enemy onscreen
{
private int x,y;
private BufferedImage image;
private Field f;
public Enemy(Field f) {//constructor accepts Field instance to access instance method for the class
this.f=f;
}
public void update() {
if(offscreen||dead) {
f.removeEnemy(this);//call removeEnemy which is an instance method of Field
}
}
//BELOW METHODS ONLY USED WHEN Enemy represents object and not a JPanel which can draw its image itself (and update position by simply changing co-ordinates)
public BufferedImage getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
For a more detailed look check Game Development Loop, Logic and Collision detection Java Swing 2D I made which will give you the basics needed for most 2D games. However I do not use JPanels rather draw directly to a container.
Where do you add an Enemy to JPanel?
Basically, you should call remove on Field JPanel:
public void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
this.remove(e);
}
The method should not be static.

Categories