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

2018/4/11

Help with stoping actors spawing to close to another actor

MrBB MrBB

2018/4/11

#
the game I'm trying to make (for programming practice purposes), is just a small thing with rocks attacking a base that can turn and fire missiles that destroys the rocks (all rocks gone you win, 3 rocks hit and you lose). the problem I'm having is that the rocks are spawning too close to the base. after lots of attempts and a lot of googling I'm finally submitting it on here, this is my code currently:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class GameWorld here.
 * 
 * @author (MrBB) 
 * @version (a version number or a date)
 */
public class GameWorld extends World
{
    public int Lives;
    int z = 0;
    int i;
    public GameWorld()
    {
        super(600, 400, 1); 
        addObject(new MissileBase(),getWidth() / 2, getHeight() / 2);
        Lives = 3;
        PlaceRocks();
    }

    public void PlaceRocks()
    {
        for(i = 0; i <= 4; i = i +1){
            int x = 20 + Greenfoot.getRandomNumber(getWidth()- 20);
            int y = 20 + Greenfoot.getRandomNumber(getHeight()- 20);
            int rtcx1 = getWidth() / 2 - 50;
            int rtcx2 = getWidth() / 2 + 50;
            int rtcy1 = getHeight() / 2 - 50;
            int rtcy2 = getHeight() / 2 + 50;
            
            if(x >= rtcx1 && x <= rtcx2 || y >= rtcy1 && y <= rtcy2){
                Rock rock = new Rock();
                addObject(rock, x, y);
                i--;
            }
            else{
                System.out.println("else" + z);
                
            }
            z++;
        }
    }

    public void removeLives()
    {
        Lives--;
        if(Lives == 0){
            Greenfoot.stop();
            Lives = 3;
        }
    }
}
The problems lie within the "PlaceRocks" method, what I want it to do is spawn 50 (or maybe 100) ~units~ away from the middle of the world where the base (MissileBase) is. currently, it will either spawn none to five (and sometimes more) or just not work at all with no error message in the terminal (the "System.ou.println("else" + z)" is just for debugging). like I said I have tried a lot of different ways including inside the "Rock" class any help would be appreciated. this is my first piece of programming and I also have dyslexia so I apologizes for any grammar or spelling mistakes in this post, thankfully I have Grammarly so it shouldn't be too bad.
danpost danpost

2018/4/11

#
Okay. Let us say 100 pixels from the middle as 50 seems a bit too close (even 100 may be). At any rate, at 100, that means there is a 200 range that must not be set either horizontally (along the x-axis) or vertically (along the y-axis). The choice of axis will need to be random to give a fair chance at any valid location. So:
int baseX = getWidth()/2, baseY = getHeight()/2;
int edgeGap = 20, range = 100;
if (Greenfoot.getRandomNumber(2) == 0) // choose an axis to limit range on
{
    int possibleXs = getWidth()-2*(edgeGap+range);
    int possibleYs = getHeight()-2*edgeGap;
    x = edgeGap+(Greenfoot.getRandomNumber(possibleXs)+baseX+range-edgeGap)%(getWidth()-2*edgeGap);
    y = 20+(Greenfoot.getRandomNumber(possibleYs )) ;
}
else
{
    int possibleXs = getWidth()-2*edgeGap;
    int possibleYs = getHeight()-2*(edgeGap+range);
    x = 20+(Greenfoot.getRandomNumber(possibleXs )) ;
    y = edgeGap+(Greenfoot.getRandomNumber(possibleYs)+baseY+range-edgeGap)%(getHeight()-2*edgeGap);
}
addObject(new Rock(), x, y);
The formulas for x and y look a bit ominous, but it is better than a bunch of if statements and adjustments to the value to come up with the proper valid values. Obviously the generated number gives equals chance to any valid value. The addition to it shifts the range from 0 to 359 for x to the range 380 to 739. The modulus splits that range into two ranges of (1) 0 to 179; and (2) 380 to 559. The addition of the edge gap at the beginning shifts those ranges to (1) 20 to 199; and (2) 400 to 579, which fits perfect for what you want.
MrBB MrBB

2018/4/11

#
@danpost Thanks for the help, it worked perfectly and after looking it over for a while I (think) I understand it. Dealing with just one axis at a time makes so much sense, and I know I never would have thought of if it myself. I also didn't know that you could declare multiple variables with one "int". So, thank you for all your help not only on this but on countless of your past (and likely future) posts where your reply has shown me a method that I could adapt to fit my requirements. Thank you.
danpost danpost

2018/4/11

#
MrBB wrote...
it worked perfectly
Actually, I thought about it and was inclined to believe it might favor the corners. So, I tested it out and the tested-approved version is this:
int baseX = getWidth()/2, baseY = getHeight()/2;
int edgeGap = 20, range = 100;
int x = 0, y = 0;
if (Greenfoot.getRandomNumber(2) == 0) // choose an axis to limit range on
{
    int possibleXs = getWidth()-2*(edgeGap+range);
    int possibleYs = getHeight()-2*edgeGap;
    x = edgeGap+(Greenfoot.getRandomNumber(possibleXs)+baseX+range-edgeGap)%(getWidth()-2*edgeGap);
    y = edgeGap+(Greenfoot.getRandomNumber(possibleYs+2*range)+baseY-range-edgeGap)%(getHeight()-2*edgeGap) ;
}
else
{
    int possibleXs = getWidth()-2*edgeGap;
    int possibleYs = getHeight()-2*(edgeGap+range);
    x = edgeGap+(Greenfoot.getRandomNumber(possibleXs+2*range)+baseX-range-edgeGap)%(getWidth()-2*edgeGap) ;
    y = edgeGap+(Greenfoot.getRandomNumber(possibleYs)+baseY+range-edgeGap)%(getHeight()-2*edgeGap);
}
addObject(new Rock(), x, y);
Because locations near the corners were being chosen regardless of which axis was limited (meaning they had twice the chance of being picked over others), the chance for the other locations needed to be doubled. So, by adding another set of possibilities for those coordinates, the chance is evened out.
You need to login to post a reply.