0

我正在使用 AndEngine 开发一款适用于 Android 的游戏,并且我有一系列汽车对象,它们在屏幕上的不同车道上从左到右移动。当汽车超过相机宽度(屏幕尺寸)时,我将其位置设置为 0(屏幕左侧)- spriteWidth()(就在屏幕视口的左侧)。我的问题是,由于返回的随机坐标,这些汽车一直在彼此重叠。我尝试了很多事情,但它一直在发生。

这是用于在游戏开始时设置汽车坐标的方法,以及向右离开屏幕的方法。

public Vector2 randomRoadCoord()
{
    int Y;
    int X;

    int arrayLength = rManager.getInstance().roadPosition.length;
    int arrayFirstValue = 1;

    Random xR = new Random();
    int Low = (int) (5 *(0 - rManager.getInstance().car_region.getWidth()));
    int High = (int) (0 - rManager.getInstance().car_region.getWidth());
    X = xR.nextInt(High-Low) + Low;

    Random yR = new Random();

    int LowY = arrayFirstValue;
    int HighY = arrayLength;
    Y = yR.nextInt(HighY-LowY) + LowY;;

    if (firstLoad)
    {
        for(int i = 0; i < rManager.getInstance().carArray.length; i++)
        {
            for(int j = 0; j < rManager.getInstance().carArray.length; j++)
            {
                while(rManager.getInstance().carArray[i].getCarSprite().collidesWith(rManager.getInstance().carArray[j].getCarSprite()))
                    X-= 150;
            }
        }
    }

    lastX = X;
    lastY = Y;
    return new Vector2(X, Y);
}

如您所见,在某些区域之间返回随机 x 和 y 值;具体来说,相机的顶部和底部(静态相机,所以基本上是视口),以及屏幕外的 -50 到 -450 之间(类似的东西)。我的问题是我需要他们停止加载,因为如果发生碰撞,用户就会输掉游戏。我尝试检查每辆汽车的精灵,看看它在加载时是否已经与另一辆汽车发生碰撞(尽管这肯定会产生减速,如果确实如此,请将 X 坐标进一步向左移动,但它似乎没有做任何事情。

/*if (firstLoad)
        {
        for(int i = 0; i < rManager.getInstance().carArray.length; i++)
        {
            while(rManager.getInstance().carArray[i].getCarX() + 100 > X && X > rManager.getInstance().carArray[i].getCarX() - 100)
                X-= 150;
        }       
        firstLoad = true;
    }   */

我也试过检查这辆车是否在其他车的 x + 150 和 x - 150 之间,但这也无济于事。不是所有的车都装在彼此的顶部,但肯定不止1辆,这太多了。

谢谢。请随时提出任何问题。

- - - - - - - - - - - - - - - - - 更新:

我尝试使用整形外科医生的建议,但同样的问题仍然存在。尽管将汽车装载在另一辆汽车上的可能性要小得多,但仍然偶尔会发生。这次我把代码注释了,应该更容易理解。

for (int i = 0; i < rManager.getInstance().carArray.length; i++)
            {
                if(rManager.getInstance().carArray[i].getCarSprite().getX() < (rManager.camera.getWidth() + rManager.getInstance().carArray[i].getCarSprite().getWidth()))
                {
                    // moves car from left to right
                    rManager.getInstance().carArray[i].getCarSprite().setPosition(rManager.getInstance().carArray[i].getCarSprite().getX() + (rManager.getInstance().carArray[i].getSpeed() * 4), rManager.getInstance().carArray[i].getCarSprite().getY()); 
                } 

                else //if out of the screen
                {       
                    //set the position to the left of the screen
                    rManager.getInstance().carArray[i].getCarSprite().setPosition(randomRoadCoord().x, rManager.getInstance().roadPosition[(int) randomRoadCoord().y].y);

                    //if colliding with another car
                    while(collidesWithExisting(rManager.getInstance().carArray[i]))
                    {   //set a new random pos
                        rManager.getInstance().carArray[i].getCarSprite().setPosition(randomRoadCoord().x, rManager.getInstance().roadPosition[(int) randomRoadCoord().y].y);
                    }
                }
            }

方法:

boolean collidesWithExisting(Car pCar)
{
    for(int j = 0; j < rManager.getInstance().carArray.length; j++)
    {
        if (rManager.getInstance().carArray[j] == pCar)
            return false;

        if(rManager.getInstance().carArray[j].getCarSprite().collidesWith(pCar.getCarSprite()))
            return true;
    }
    return false;
}

再次感谢。

4

1 回答 1

2

您的循环至少存在一个问题:当 X 值更改时,您检查 .collidesWith() 的条件不会改变。因此可能会发生额外的误报。

第二个问题是,如果发生 collidesWith() 事件,则无法知道新的 x 是否也会在循环的早期对另一辆车造成 collidesWith() 事件。想象一下在两辆车之间放置第三辆车,两辆车之间的距离太近而无法容纳一辆汽车。没有办法在单循环或双循环中解决这个问题。

所以这里有一个不同的策略:只让一个轴完全随机。一次通过 X 轴(汽车的行驶方向)一辆车。随机确定该位置是否应该有汽车。如果是,则沿 Y 轴随机定位该车。没有太多麻烦,您可以让每一步放置一辆或多辆汽车。

如果您不希望网格如此明显,您可以将您的 X 循环提前 1/2 车长。然后,您只需要检查与上一次迭代中放置的汽车或汽车的碰撞,您只需在 Y 轴上偏移以防止碰撞。

这也是第二种策略: 将每辆车随机放置在一个循环中。循环测试以查看当前汽车是否与任何其他汽车发生碰撞。继续随机重新分配它的 x 和 y 直到它不碰撞。最后,您将拥有一系列不接触的汽车。

   Car newCar = new Car();
   newCar.setPosition(randomXPostion, randomYPosition);
   while(testCarCollidesWithExisting(newCar)){
       newCar.setPosition(randomXPostion, randomYPosition);
   }

"testCarCollidesWithExisting" 方法循环遍历已经放置的汽车数组,如果新车重叠,则返回 true,如果汽车不重叠,则返回 false。

== 更新完整示例 ==

这是一个工作示例。使用的图形是 andengine 示例中的“坦克”。有一个警告:如果您放置的坦克数量超过了容纳的数量,脚本将会挂起,因为它会卡在一个 while 循环中。我认为大约 20 与您可以使用该尺寸的图像和舞台尺寸一样多。

包 com.example.andenginetestbed;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.util.FPSLogger;
import org.andengine.opengl.texture.ITexture;
import org.andengine.opengl.texture.bitmap.BitmapTexture;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegionFactory;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.adt.io.in.IInputStreamOpener;
import org.andengine.util.debug.Debug;

import android.os.Bundle;
import android.view.Menu;

public class TestBed extends SimpleBaseGameActivity {

    // ===========================================================
    // Constants
    // ===========================================================

    private static final int CAMERA_WIDTH = 720;
    private static final int CAMERA_HEIGHT = 480;

    // ===========================================================
    // Fields
    // ===========================================================

    private ITexture mTexture;
    private ITextureRegion mFaceTextureRegion;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_test_bed);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.test_bed, menu);
        return true;
    }

    @Override
    public EngineOptions onCreateEngineOptions() {
        final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);

        return new EngineOptions(true, ScreenOrientation.LANDSCAPE_SENSOR, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
    }

    @Override
    public void onCreateResources() {
        try {
            this.mTexture = new BitmapTexture(this.getTextureManager(), new IInputStreamOpener() {
                @Override
                public InputStream open() throws IOException {
                    return getAssets().open("tank.png");
                }
            });

            this.mTexture.load();
            this.mFaceTextureRegion = TextureRegionFactory.extractFromTexture(this.mTexture);
        } catch (IOException e) {
            Debug.e(e);
        }
    }
    ArrayList<Sprite> placedSprites = new ArrayList<Sprite>();
    @Override
    protected Scene onCreateScene() {
        this.mEngine.registerUpdateHandler(new FPSLogger());

        final Scene scene = new Scene();
        scene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));

        /* Calculate the coordinates for the face, so its centered on the camera. */
        final float centerX = (CAMERA_WIDTH - this.mFaceTextureRegion.getWidth()) / 2;
        final float centerY = (CAMERA_HEIGHT - this.mFaceTextureRegion.getHeight()) / 2;

        /* Create the face and add it to the scene. */
        for (int i = 0; i < 20; i++) {
            final Sprite face = new Sprite(centerX, centerY, this.mFaceTextureRegion, this.getVertexBufferObjectManager());
            scene.attachChild(face);
            face.setPosition((float)(Math.random()*CAMERA_WIDTH), (float)(Math.random()*CAMERA_HEIGHT));
            while(faceDoesNotOverlap(face)){
                face.setPosition((float)(Math.random()*CAMERA_WIDTH), (float)(Math.random()*CAMERA_HEIGHT));                
            }
            placedSprites.add(face);

        }

        return scene;
    }

    private boolean faceDoesNotOverlap(Sprite face) {
        for (int i = 0; i < placedSprites.size(); i++) {
            if(face.collidesWith(placedSprites.get(i))){
                return true;
            }
        }
        return false;
    }



}
于 2013-04-17T17:58:20.400 回答