0
\$\begingroup\$

i'm new to java and was hoping if anyone can help me out. So my game has meteors which spawns off screen and sometimes as they spawn, they overlap each other which I don't want. I want them to spawn from a certain distance from each other.

From pseudo code I know what I want which is to find the centre point of sprite, find other meteors on screen and calculate the distance and then spawn from a certain distance from each other. I know the distance to point formula (distance = Math.sqrt(Math.pow(x2 - x1, 2) + (Math.pow(y2 - y1, 2)));), but how do I do that within an array. Here is my code so far:

Meteor Class

public class Meteors {
    private Texture bigMeteor;
    private Vector2 posBigMeteor;
    private Random yrand;

    //Constructor
    public Meteors(float x){
        bigMeteor = new Texture("meteor.png");
        yrand = new Random();

        //Spawn location of meteor
        posBigMeteor = new Vector2(x, yrand.nextInt(AstroDemo.HEIGHT/2 - bigMeteor.getHeight()));
    }

    public Texture getBigMeteor() {
        return bigMeteor;
    }

    public Vector2 getPosBigMeteor() {
        return posBigMeteor;
    }

    public void reposition(float x){
        posBigMeteor.set(x, yrand.nextInt(AstroDemo.HEIGHT/2 - bigMeteor.getHeight()));
    }
}

Playstate Class

public class PlayState extends State {
    //Total meteor count on screen
    private static final int METEOR_COUNT = 8;

    private Naught naught;
    private Texture bg;
    private Random xrand;
    private Array <Meteors> meteors;

    public PlayState(GameStateManager gsm) {
        super(gsm);
        //Starting co-ordinates of main character (Naught)
        naught = new Naught(50, 100);
        //Setting viewport of the camera
        cam.setToOrtho(false, AstroDemo.WIDTH/2, AstroDemo.HEIGHT/2);
        bg = new Texture("bg.png");
        xrand = new Random();

        meteors = new Array <Meteors>();

        //Spawn meteors randomly off screen
        for (int i = 1; i <= METEOR_COUNT; i++){
            meteors.add(new Meteors(AstroDemo.WIDTH/2 + (xrand.nextInt(300))));
        }
    }


    @Override
    protected void handleInput() {
        //If screen/mouse is held
        if(Gdx.input.isTouched()){
            //Main Character jumps/flys
            naught.jump();
        }
    }

    @Override
    public void update(float dt) {
        handleInput();
        naught.update(dt);
        //If meteors are left side of the screen, re-position to the right side of the screen
        for(Meteors meteor : meteors){
            if (cam.position.x - (cam.viewportWidth/2) > meteor.getPosBigMeteor().x + meteor.getBigMeteor().getWidth()){
                meteor.reposition(meteor.getPosBigMeteor().x + (AstroDemo.WIDTH/2 + 20 + (xrand.nextInt(300))));
            }
       }
        cam.position.x = naught.getPosition().x + 80;

        cam.update();
    }

    @Override
    public void render(SpriteBatch sb) {
        //Adjust the spritebatch for co-ordinate system in relation to camera
        sb.setProjectionMatrix(cam.combined);
        sb.begin();
        //Draw background where the camera is
        sb.draw(bg, cam.position.x - (cam.viewportWidth/2), 0);
        sb.draw(naught.getTexture(), naught.getPosition().x, naught.getPosition().y);
        for (Meteors meteor : meteors) {
            sb.draw(meteor.getBigMeteor(), meteor.getPosBigMeteor().x, meteor.getPosBigMeteor().y);
        }
        sb.end();
    }

    @Override
    public void dispose() {

    }
}
\$\endgroup\$
  • \$\begingroup\$ It's not clear to me what kind of help you need here. Why would applying the distance formula to objects selected from an array be different than applying the formula to anything else? You seem to understand for-loops, so I'm not sure what the step you're missing might be. \$\endgroup\$ – DMGregory Jan 22 '17 at 0:32
  • \$\begingroup\$ If you are going to spawn only 8 meteors one time (as your code do) you can put an array of random x distances to the constructor, where minDistance (between meteors) would be meteorWidth and maxDistance would be based on cordinates of previous meteor and screenWidth. \$\endgroup\$ – Андрей Юсупов Jan 22 '17 at 17:08
1
\$\begingroup\$

So you want to generate meteor and you don't want them to spawn at a location where they overlap. Plus, you want them to be spaced by a minimal amount.

In my opinion, you should not compute y positions that way. I'll do the y generation at the same time of x. I'll assume you build a meteor by x AND y positions.

I usually make a function for this. This code will do those things :

  1. Make meteor at 0,0 location
  2. Compute random x and y
  3. Compute distance between x/y and already existing meteors
  4. Compute new random x and y until distance between new meteor and already existing meteors is superior or equal to the minimal distance autorized between meteors
  5. Set position of the meteor
  6. Return the meteor

// This will create a meteor, and compute positions until they don't overlap with other meteors
private Meteors generateMeteor(int maxX, int maxY, float minDistanceBetweenMeteors)
{
    // Make the meteor
    Meteors meteor = new Meteor(0, 0) // You don't care at the moment

    // Init positions
    float x = rand.nextInt(maxX); // Your boundaries
    float y = rand.nextInt(maxY); // Your boundaries

    // Now you want to check if the min distance is good enough
    float distance;
    boolean minDistanceRespected = true; // The first meteor is always in respect of min distance

    do
    {
        for (Meteors m : meteors)
        {
            // Compute distance between your new meteor and the existing ones
            distance = Math.sqrt(Math.pow(m.getX() - x, 2) + (Math.pow(m.getY() - y, 2));

            // Check if distance is good enough
            if (distance < minDistanceBetweenMeteors)
            {
                minDistanceRespected = false;

                // Compute positions again
                x = rand.nextInt(maxX);
                y = rand.nextInt(maxY);

                break; // Don't need to check for others
            }
            else
            {
                minDistanceRespected = true;
            }
       }
    } while (!minDistanceRespected);

    // Reach this point means you finally get good positions
    meteor.reposition(x, y); // Change your reposition method to actually take x and y as position (you compute a random y each time you set a new X, here we want to set both of them
}

To use :

 meteors.add(generateMeteor(maxX, maxY, minDistanceBetweenMeteors));    
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.