1

so i'm trying to make it where if these two shapes touch each other the window closes. Here is the first part

public class Mayflower {

JFrame f = new JFrame();

public static void main(String[] args) {

    Mayflower bob = new Mayflower();
    bob.Start();

}

private void Start(int clothes, int food, int repair, int money) {
    int complete = 0;
    Mayflower bob = new Mayflower();
    //JOptionPane.showMessageDialog(null, "Your equipment:\nClothes - " + clothes + "\nFood - " + food + "\nrepair equipment - " + repair + "\nMoney left - $" + money);
    bob.epic(complete);
}

public void epic(int complete) {


    if (complete == 0){
    Iceberg Tim = new Iceberg();

    f.add(Tim);
    f.setVisible(true);
    f.setSize(600, 600);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setTitle("SAILIN BABEEEEY");
    f.setLocation(600, 200);

    }

    if(complete == 1){
        System.out.println("odeyladoeijoo");
        f.dispose();
     }


}

}

Then it calls to the constructor iceberg where the minigame is, I deleted all the movement input because it wasn't relevant:

package mayflower;


public class Iceberg extends JPanel implements ActionListener, KeyListener {

Timer time = new Timer(5, this);
int x = 260;
int y = 500;
int velx = 0;
int vely = 0;

int hitscany = -4000;
int hitscanvely = -1;


public Iceberg() {

    time.start();
    addKeyListener(this);
    setFocusable(true);
    setFocusTraversalKeysEnabled(false);

}

@Override
public void paintComponent(Graphics g) {

    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;

g.setColor(MyColor1);
    g.fillRect(x, y, 40, 60);

    g.setColor(Color.GRAY);
    g.fillRect(0, hitscany, 650, 0);

    if (y == hitscany) {
        int complete = 1;
        Mayflower bob = new Mayflower();
        bob.epic(complete);

    }

    time.start();

}

So i made it to where The "hitscan" object moves down the screen and when it touches the object the window is supposed to close. When my if statement (for if the y coordinates of the two objects are equal) calls the public void epic its supposed to "activate" the if statement for if complete is == 1 and dispose of the frame but for some reason it doesn't

  • Every time you call epic, you create a new instance of JFrame, so you’re not actually talking to the instance which was last created, and been a local variable, I’d be impossible to make it work. You will need to maintain a reference of the frame independent of the epic method – MadProgrammer Nov 20 '18 at 00:48
  • I tried making the JFrame a global variable instead but got the same result could you possibly elaborate on maintaining a reference independent of the epic method? – Max Stephenson Nov 20 '18 at 01:20
  • For better help sooner, [edit] to add a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). – Andrew Thompson Nov 20 '18 at 01:39
  • @MaxStephenson Without more context, it's going to be impossible to suggest an "actual" fix to the problem. Since you're also creating a new instance `Mayflower`, you have a double issue – MadProgrammer Nov 20 '18 at 01:51
  • I updated my code, if its still too vague don't worry about it I will just ask my teacher about it after thanksgiving break. – Max Stephenson Nov 20 '18 at 02:20

2 Answers2

0

So, I assume that, this (previously, now removed) code goes some where in your Iceberg key handler code...

if ((((x - icex)) >= -40 && ((x - icex) - 180) <= -130) && (((y - icey)) >= -60 && ((y - icey) - 180) <= -130)) {
    int complete = 1;
    Mayflower bob = new Mayflower();
    bob.epic(complete);
}

This highlights a number of issues. First, you are creating another instance of Mayflower, which is creating another instance of JFrame, which is what's getting disposed, not the original frame.

Iceberg really has no need to interact with Mayflower, it's beyond it's realm of responsibility. Instead, Iceberg "should" be generating event notifications to interested parties about its change in state.

For that, we need an observer pattern!

Let's start with a simple interface which describes all the notifications Iceberg is willing to make...

public interface GameListener {
    public void completed(Iceberg berg);
}

Next, we need some way to manage these listeners in Iceberg...

public class Iceberg extends JPanel implements ActionListener, KeyListener {

    private List<GameListener> listeners = new ArrayList<>(25);


    public void addGameListener(GameListener listener) {
        listeners.add(listener);
    }

    public void removeGameListener(GameListener listener) {
        listeners.remove(listener);         
    }

And finally, some way to generate the notifications...

public class Iceberg extends JPanel implements ActionListener, KeyListener {
    //...       
    protected void fireCompleted() {
        for (GameListener listener : listeners) {
            listener.completed(this);
        }
    }

Now, when you have a "completed" state, you can notify the interested parties...

if ((((x - icex)) >= -40 && ((x - icex) - 180) <= -130) && (((y - icey)) >= -60 && ((y - icey) - 180) <= -130)) {
    fireCompleted();
}

Now, in your start method, you simply need to create an instance of Iceberg, register a GameListener and get it all started...

private void Start(int clothes, int food, int repair, int money) {
    Iceberg Tim = new Iceberg();
    Tim.addGameListener(new GameListener() {
        @Override
        public void completed(Iceberg berg) {
            f.dispose();
        }
    });

    f.add(Tim);
    f.setVisible(true);
    f.setSize(600, 600);
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setTitle("SAILIN BABEEEEY");
    f.setLocation(600, 200);
}

Observations...

Okay, there is plenty about your code sample to be worried about, but let's start with...

@Override
public void paintComponent(Graphics g) {

    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;

    g.setColor(Color.RED);
    g.fillRect(x, y, 40, 60);

    g.setColor(Color.GRAY);
    g.fillRect(0, hitscany, 650, 0);

    if (y == hitscany) {
        int complete = 1;
        Mayflower bob = new Mayflower();
        bob.epic(complete);

    }

    time.start();

}
  • paintComponent should never be public, no-one should ever be calling it directly.
  • You declare but never use g2

This...

if (y == hitscany) {
    int complete = 1;
    Mayflower bob = new Mayflower();
    bob.epic(complete);

}

is a bad idea on a number of levels. Paint should paint the current state of the component, nothing else, it should not be making decisions about the state of the component. This belongs in your main loop

And...

time.start();

I can't begin to tell you how horrible this is. paintComponent will be called often (if you're performing animation), meaning you are continuously reseting the Timer. The Timer's state should never be modified inside paintComponent. Instead, it should control through other means, like the constructor or start/stop methods

KeyListener is a poor choice now days. It suffers from a number of well known and documented short comings. A better, all round solution, is to use the Key Bindings API which has been designed to help solve these issues in a reliable and robust way

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
-1

You could use

f.setVisible(false)

This just hides the window, and f.dispose() deletes the actual object.

If you want it to act like you clicked the X button, then use this:

f.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));

(got from How to programmatically close a JFrame)

(f being your JFrame)

oriont
  • 684
  • 2
  • 10
  • 25