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

2019/3/21

Prevent different objects from completely overlapping with each other

1
2
Abwatts Abwatts

2019/3/21

#
Hello, I'm not sure why this code does not work properly as it seems that the method that I use here makes complete sense to me. I want to prevent my roach objects from spawning on the car objects and I don't understand why this code that I have come up with doesn't do the trick. The method for some reason sometimes works while sometimes it doesn't, and some roaches spawn directly on the car object. Here's my code:
public boolean getReady() {
        readyToStart = false;

        do {
        if(this.isAtEdge() && !this.getIntersectingObjects(Car.class).isEmpty()) {
        int newRandX = 1 + Greenfoot.getRandomNumber(getWorld().getWidth());
        int newRandY = 1 + Greenfoot.getRandomNumber(getWorld().getHeight());
        this.setLocation(newRandX, newRandY);
        System.out.println("problem fixed");
        } 
        else {
        readyToStart = true;
        }

        } while(!readyToStart);
        //Returning whether overlapping had occurred. False stands for yes,
        //while true for no.
        return readyToStart;
    }
and that's what sometimes happens: I would highly appreciate any kind of help along with an explanation, thanks!
Abwatts Abwatts

2019/3/21

#
And also the isAtEdge() method is getting ignored, which I don't exactly get why
danpost danpost

2019/3/21

#
Chances are very slim that "at edge" and "intersects car" both occur simultaneously. Note line 5 and what it is saying. On the side: I do not understand why the getReady method would return any value since it will always be true.
Abwatts Abwatts

2019/3/21

#
Thank you! I mistook the && operator with || and that was indeed the problem. I'm just a beginner and so I thought to use this variable to make the loop execute until no overlapping occurs. and then return true whether everything went according to plan to prevent more errors from occurring later on. I also call it in the main method to make sure all these conditions are met.
private boolean placeRoach()
    {
        //Getting a random location and size for the ball to be placed at
        int randX = 1 + Greenfoot.getRandomNumber(getWidth()); 
        int randY = 1 + Greenfoot.getRandomNumber(getHeight());
        int randSize = 1 + Greenfoot.getRandomNumber(7);

        java.util.List roachList = getObjects(RoachPopulation.class);

        for (int i =0; i < roachList.size(); i++) {
            tempRoach.getReady();
        }

        if (getObjectsAt(randX, randY, RoachPopulation.class).isEmpty()) {
           
            RoachPopulation roach = new RoachPopulation(randSize);

            addObject (roach,randX,randY); //if size is too great

            //Returns true if the task was successfully completed
            return true;
        }

        //Something went wrong, so returning a false value
        return false;
    }
Could you please elaborate a little as to why you think it's redundant to declare the method as type boolean? I know that if everything goes according to plan, the method will in the end always return true, but could you please be a little bit more specific?
danpost danpost

2019/3/21

#
Abwatts wrote...
Could you please elaborate a little as to why you think it's redundant to declare the method as type boolean? I know that if everything goes according to plan, the method will in the end always return true, but could you please be a little bit more specific?
You set a boolean to false at the beginning of the method. The do loop will execute indefinitely until that boolean becomes true. Only then will the method be returned from.
Abwatts Abwatts

2019/3/21

#
So for this purpose do think you having a void method would be the best fit?
danpost danpost

2019/3/21

#
Abwatts wrote...
So for this purpose do think you having a void method would be the best fit?
Probably. I mean, you do not even try to make use of the returned value anyway (see line 11 of the placeRoach method). There seems to be something amiss there also. That which tempRoach refers to does not seem to change for the entirety of the execution of the for loop.
danpost danpost

2019/3/21

#
Since you do not appear to want a roach intersecting anything when placed into the world, it does no make sense to only look for an intersecting car. You could change Car.class to Actor.class in the getReady method and then use the following placeRoach method:
public void placeRoach()
{
    RoachPopulation roach = new RoachPopulation(randSize);
    addObject(roach, 0, 0);
    roach.getReady();
}
In fact, you could remove line 5 here if you:
// change
public void getReady()

// to
protected void addedToWorld(World world)
Abwatts Abwatts

2019/3/22

#
I'm not entirely sure what's the use of this line
protected void addedToWorld(World world)
Does this mean that this method will be executed automatically when the world will be first created?
danpost danpost

2019/3/22

#
Abwatts wrote...
I'm not entirely sure what's the use of this line << Code Omitted >> Does this mean that this method will be executed automatically when the world will be first created?
The method is called via the addObject method. Anytime an Actor object is added into a world, a method with this name is called on that actor. By adding the method into your subclass of Actor, you are essentially overriding a method in the Actor class (see Actor class API documentation). The Actor class method has no implementation (an empty method -- does nothing) and is provided so that you can perform initial setup of an actor in a world (when you override it).
Abwatts Abwatts

2019/3/22

#
This method will be extremely useful for me when doing future work. Thanks a lot!
Abwatts Abwatts

2019/3/22

#
Hey Dan, I actually have another quick question: when using a while loop, can I still execute different code while the loop is still being executed? I'm working on a method that will prevent the program from freezing when using Greenfoot.delay or Thread.sleep. I'm just not sure if this solution is actually valid and will allow me to execute more than one method at the same time. Here's my method in case you want to take a look:
// Method used to prevent the program from freezing (only freezes one method at a time)
    public static boolean waitUntil(int numOfSecs) {
        long timeElapsed = Instant.now().toEpochMilli();
        long timeToReach = timeElapsed + numOfSecs;
        System.out.println("\nWaiting for " + numOfSecs + " seconds\n");
        System.out.println("\nTime now:" + timeElapsed + "seconds\n");
        System.out.println("\nWait until:" + timeToReach + "seconds\n");
        //System.out.println(timeElapsed - timeNow + "secs passed thus far");

        while(timeToReach != timeElapsed)
        {
            timeElapsed = Instant.now().toEpochMilli();
            if(timeToReach == timeElapsed){
                System.out.println(timeElapsed);
                System.out.println(numOfSecs + "secs passed thus far");
                return true;
            }
        }
        
        return false;
    }
danpost danpost

2019/3/22

#
Abwatts wrote...
Hey Dan, I actually have another quick question: when using a while loop, can I still execute different code while the loop is still being executed? I'm working on a method that will prevent the program from freezing when using Greenfoot.delay or Thread.sleep.
Do not use thread in greenfoot -- does not work well. And, using Greenfoot.delay will cause the entire program to "wait". Best to add a int counter field to count act cycles. Normally, about 60 acts will execute per second. Something like:
private static int timer = 0;

public static void setWait(int seconds)
{
    timer = 60*waitTime;
}

public static boolean waiting()
{
    return timer > 0 && --timer > 0;
}
Always call waiting and only call setWait when waiting returns false and your other condition is true to begin a wait.
Abwatts Abwatts

2019/3/22

#
Thanks once again! For some reason, I can't really get the timer method to work properly, am I doing something wrong? Is there a way to use this code without inserting it into the act() method?
setWait(1000);

        while(true) {
            System.out.println(waiting());
            System.out.println(timer);
            if(!waiting()){
                System.out.println("Success");
                sizePopulation -= sizePopulation * 0.9;
                break;
            }
        }
danpost danpost

2019/3/23

#
Abwatts wrote...
Thanks once again! For some reason, I can't really get the timer method to work properly, am I doing something wrong? Is there a way to use this code without inserting it into the act() method? << Code Omitted >>
Your code would have to be executed by way of some act method somewhere. Since I do not know exactly what you are trying to do with this timer, it is difficult to give good advice. What triggers the timer? What is it suspending? What kind of class are you using in? Information related to questions like these should be supplied before a good response can be given. Also, you terminal print lines are temporary -- right? They are only currently there for debugging purposes?
There are more replies on the next page.
1
2