This site requires JavaScript, please enable it in your browser!
Greenfoot back
Connorg1215
Connorg1215 wrote ...

2024/10/2

Help: getBackground() to remove images in world?

Connorg1215 Connorg1215

2024/10/2

#
Hello, I hope you all are having a good day. I am trying to work on a guitar hero project for school and I was using the setWorld() method to change worlds when a button is pressed, but after I add a third setWorld() it breaks so I am now trying to make it so when a button is pressed the background is changed and then the world checks if the background is equal to that image then removes the buttons on the previous screen and adds a new button for the new screen. (I am using Greenfoot 3.5.1) This is my code:
public Start()
    {    

        super(613, 502, 1);

    }

    public void act()
    {
       StartButton star = new StartButton(new MyWorld());
       ControlButton y = new ControlButton();
       GreenfootImage img = new GreenfootImage("StartScreen.png");
       GreenfootImage con = new GreenfootImage("Controls.png");
       if(getBackground() == img)
       {
           addObject(star,151, getHeight()/2);
           addObject(y, 151, 350);
           if(getBackground() == con)
           {
               BackToMenu k = new BackToMenu();
               addObject(k, 470, 445);

               removeObject(star);
               removeObject(k);
               if(Greenfoot.mouseClicked(k))
               {
                   setBackground("StartScreen.png");
                   if(getBackground() == img)
                   {
                       removeObject(k);
                   }
               }
           }  
       }
    }
I have tried many things but the if statement does not seem to even check if the background has changed.
Connorg1215 Connorg1215

2024/10/2

#
line 24 is meant to say removeObject(y);
Super_Hippo Super_Hippo

2024/10/2

#
Let’s say every line itself works as expected. One issue is that in line 18, you check if “con” is your background. However, the condition that this is even executed is that “img” is the background (line 14). So the condition in line 18 can never be true. A more general thing: Every act cycle, you create a new StartButton (line 10) including an entire new MyWorld and a ControlButton. If “img” is your background, you add both to the world – every act cycle a new one. The act method should contain those things which need to be checked every act cycle. So in your case, if the BackToMenu button is pressed. Adding it (and everything else) to the world should only happen one single time, so it belongs in the constructor, not the act method.
danpost danpost

2024/10/2

#
First thing is that the initial world building code should go in the constructor of the class. Any changes from that can be determined later depending on user actions through the act method. You need to keep in mind that it will take many act steps just waiting for a button to be clicked. Therefore, you cannot program the entire thing as simply as you have tried (or, in a single block of code). In fact, you said:
line 24 is meant to say removeObject(y);
Is line 25 supposed to be with "y" also, instead of "k"? Either way, both y and k are created before and during the same act step as this check for the click on one of those objects. There is no way these can be clicked on if they were just created and not added into the world. Even if you add them into the world, they would need to exist there for multiple act steps before the user could possibly click on them (meaning you need to leave this act step to get that chance and pick up the click on a subsequent act step. But, again, you would be creating new objects and check on them instead of the ones already in the world. Adding fields to hold the buttons can assist in checking on any clicks on them. You could add a field to track what is going on at that time. If it helps, you could even give names to the different states as far as what is going on. That would be something along these lines (just a skeleton):
import greenfoot.*;

public class MyWorld extends World {
    private static final int START_MENU = 0, CONTROLS = 1, GAME_PLAY = 2;  // the different states

    GreenfootImage[] bgImages = new GreenfootImage[3]; // background images DEPENDENT on state (index refers to state)
    int mode = START_MENU; // current state
    Actor btnStart, btnControls; // clickable buttons
    
    public MyWorld() {
        super(613, 502, 1);

        // set up the background images
        bgImages[0] = new GreenfootImage("StartScreen.png");
        bgImages[1] = .new GreenfootImage(/** image string name */);
        bgImages[2] = new GreenfootImage(/** image string name */);
        
        // initiate mode
        setMode(START_MENU);
    }
    
    public void act() {
        // what to do in each state
        switch(mode) {
            case 0:
                if (Greenfoot.mouseClicked(btnStart)) {
                    setMode(GAME_PLAY);
                }
                if (Greenfoot.mouseClicked(btnControls)) {
                    setMode(CONTROLS);
                }
                break;
            case 1:
                // actions within CONTROLS
                break;
            case 2:
                // actions within GAME_PLAY
                break;
        }
    }
    
    private void setMode(int newMode) {
        // clear world of object
        removeObjects(getObjects(null));

        // set mode and set new background
        mode = newMode;
        setBackground(bgImages[mode]);
        // build world according to state (mode)
        switch(mode) {
            case START_MENU:
                btnStart = new Button("Start");
                addObject(btnStart, 151, getHeight()/2);
                btnControl = new Button("Controls");
                addObject(btnControls, 151, 350);
                break;
            case CONTROLS:
                // CONTROLS set up
                break;
            case GAME_PLAY:
                // GAME_PLAY set up
                break;
        }
    }
}
Connorg1215 Connorg1215

2024/10/3

#
Thank you so much when I saw this code I was very confused on what it meant (this is only my 2nd year of java in school), but after I tried it and looked through what each thing did I started to understand. The only issue I am having is the GAME_PLAY screen mostly because the actual game is in a separate subclass of World.
    public void act() {

        switch(mode) {
            case 0:
            if (Greenfoot.mouseClicked(StartButton)) {
                setMode(GAME_PLAY);
            }
            if (Greenfoot.mouseClicked(ControlButton)) {
                setMode(CONTROLS);
            }
            break;
            case 1:
            if(Greenfoot.mouseClicked(BackToMenu)) {
                setMode(START_MENU);
            }
            break;
            case 2:
            if( mode == GAME_PLAY)
            {
                Greenfoot.setWorld(new MyWorld());
            }
            break;
        }

    }
I tried making it so when the mode is set equal to GAME_PLAY it sets the world to MyWorld() which does work, but for some reason no matter what button I press the screen only changes to the control menu. I did check the size of the images to check if it was just overlapping and it wasn't that and I also just to double check if there was overlap I moved the buttons to opposite sides of the screen but it still did not work. After that I removed the button meant to swap to the control screen and then checked if Start even worked and it swapped to the control screen so I // the line what set mode to CONTROLS and then it worked, but I cant seem to be able to have both work at the same time.
danpost danpost

2024/10/3

#
Connorg1215 wrote...
The only issue I am having is the GAME_PLAY screen mostly because the actual game is in a separate subclass of World.
Then, remove the field GAME_PLAY and all cases in switch blocks that referred to GAME_PLAY. Afterwards, if issue persist (which I believe it will), provide the entire class coding for review (starting at line 1 in your editor). Explain exactly what is happening and how you want it improved.
Connorg1215 Connorg1215

2024/10/3

#
I removed all cases of GAME_PLAY and now I am having the opposite issue where both buttons swap to the game and no longer swaps to controls. For how I want to to be improved I just need it where when the start button is pressed it swaps to MyWorld() and when ControlButton gets pressed it swaps to the control screen background and spawns the BackToMenu button.
import greenfoot.*;

public class Start extends World {
    private static final int START_MENU = 0, CONTROLS = 1;

    GreenfootImage[] bgImages = new GreenfootImage[2];
    int mode = START_MENU;
    Actor StartButton, ControlButton, BackToMenu;
    
    public Start() {
        super(613, 502, 1);

        bgImages[0] = new GreenfootImage("StartScreen.png");
        bgImages[1] = new GreenfootImage("Controls.png");
        
        setMode(START_MENU);
    }

    public void act() {

        switch(mode) {
            case 0:
            if (Greenfoot.mouseClicked(StartButton)) {
                Greenfoot.setWorld(new MyWorld());
            }
            if (Greenfoot.mouseClicked(ControlButton)) {
                setMode(CONTROLS);
            }
            break;
            case 1:
            if(Greenfoot.mouseClicked(BackToMenu)) {
                setMode(START_MENU);
            }
            break;
        }

    }

    private void setMode(int newMode) 
    {
        removeObjects(getObjects(null));
        mode = newMode;
        setBackground(bgImages[mode]);
         switch(mode) {
            case START_MENU:
            
            StartButton u = new StartButton("MyWorld");
            //addObject(u, 151, getHeight()/2);
            ControlButton v = new ControlButton("Controls");
            addObject(v, 151, 350);
            break;
            
            case CONTROLS:
            BackToMenu i = new BackToMenu();
            addObject(i, 470, 450);
            break;

        }
    }
}
danpost danpost

2024/10/3

#
The (same) problem is with lines 47, 49 and 54. They do not retain the objects in the fields provided on line 8. The values for those fields remains null and the checks for clicks will fail on these, or, at least, not work as you intended. To retain the buttons in the fields, you must not create a new variable (which those lines do). Look back at what I gave to see how they get retained. Also, note that the field names I gave are not (at least case-wise) the same as the class name. This helps for readability of your code (letting you know it is a variable name, not a class name).
You need to login to post a reply.