繁体   English   中英

Libgdx重构具有纹理的类

[英]Libgdx Refactor a class with texture

我正在教自己LibGdx并且正在关注简单的游戏教程,遗憾的是大多数代码都在一个类中。 我想重构代码,以便我可以根据随机数使用多个纹理来降雨。

我将为主程序附上代码,然后我开始上课。

到目前为止一切正常,除了Rain纹理/ img没有在屏幕上显示。

    public class GameScreen implements Screen {
    public static FruitHarvest game;
    protected final Texture dropImage;
    //protected final Texture dropImage2;
    private final Texture bucketImage;
    public static Rectangle bucket;
    public static Sound dropSound;
    //private static Music rainMusic;
    private final OrthographicCamera camera;
    public static Array<Rectangle> raindrops;
    private long lastDropTime;
    public static int dropsGathered;
    //    private int random = MathUtils.random(0,1);
    private Drops drop;
    //Iterator<Rectangle> iterator = raindrops.iterator();

    public GameScreen(final FruitHarvest game) {
        this.game = game;


        // load the images for the droplet and the bucket, 64x64 pixels each
        dropImage = new Texture(Gdx.files.internal("droplet.png"));
        //dropImage2 = new Texture(Gdx.files.internal("droplet1.png"));
        bucketImage = new Texture(Gdx.files.internal("bucket.png"));

        // load the drop sound effect and the rain background "music"
        dropSound = Gdx.audio.newSound(Gdx.files.internal("drop.wav"));
        //rainMusic = Gdx.audio.newMusic(Gdx.files.internal("rain.mp3"));
        //rainMusic.setLooping(true);

        // create the camera and the SpriteBatcher
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 480);

        // create a Rectangle to logically represent the bucket
        bucket = new Rectangle();
        bucket.x = 800 / 2 - 64 / 2; // Center the bucket horizontally
        bucket.y = 20; // Bottom left corner of the bucket is 20 pixels above the bottom screen edge;
        bucket.width = 64;
        bucket.height = 64;

        // Create the raindrops array and spawn the first raindrop
        raindrops = new Array<Rectangle>();

        long delta = 0;
        drop = new Drops(dropImage, 64, 64, raindrops, delta);
    }

    @Override
    public void render(float delta) {
        // clear the screen with a dark blue color. The arguments to glClearColor are the
        // red, green, blue, and alpha component in the range [0,1] of the color to be
        // used to clear the screen
        Gdx.gl.glClearColor(0, 0, .5f, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // tell the camera to update its matrices.
        camera.update();

        // tell the SpriteBatch to render in the coordinate system specified by the camera.
        game.batch.setProjectionMatrix(camera.combined);

        // begin a new batch and draw the bucket and all drops
        game.batch.begin();
        game.font.draw(game.batch, "Drops collected: " + dropsGathered, 0, 480);
        game.batch.draw(bucketImage, bucket.x, bucket.y, bucket.width, bucket.height);

        // Draws the Items Falling
        for (Rectangle raindrop : raindrops) {
            game.batch.draw(dropImage, raindrop.x, raindrop.y);
        }
        game.batch.end();

        // process user input
        if (Gdx.input.isTouched()) {
            Vector3 touchPos = new Vector3();
            touchPos.set(Gdx.input.getX(), Gdx.input.getY(), 0);
            camera.unproject(touchPos);
            bucket.x = touchPos.x - 64 / 2;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) bucket.x -= 200 * Gdx.graphics.getDeltaTime();
        if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) bucket.x += 200 * Gdx.graphics.getDeltaTime();

        // make sure the bucket stays within the screen bounds
        if (bucket.x < 0) bucket.x = 0;
        if (bucket.x > 800 - 64) bucket.x = 800 - 64;

        // check if we need to create a new raindrop
        if (TimeUtils.nanoTime() - drop.getLastDropTime() > 1000000000) {
            drop.spawnRaindrop();
        }

        // move the raindrops, remove any that are beneath the bottom edge of the screen
        // or that hit the bucket. In the later case we increase the value our drops counter
        // and add a sound effect.
        Iterator<Rectangle> iter = raindrops.iterator();
        drop.update(delta);
//        while (iter.hasNext()) {
//            Rectangle raindrop = iter.next();
//            raindrop.y -= 200 * Gdx.graphics.getDeltaTime();
//            if (raindrop.y + 64 < 0) iter.remove();
//            if (raindrop.overlaps(bucket)) {
//                dropsGathered++;
//                dropSound.play();
//                iter.remove();
//            }
//        }
    }

    private void spawnRaindrop() {
        Rectangle raindrop = new Rectangle();
        raindrop.x = MathUtils.random(0, 800 - 64);
        raindrop.y = 480;
        raindrop.width = 64;
        raindrop.height = 64;
        raindrops.add(raindrop);
        lastDropTime = TimeUtils.nanoTime();
    }

//    public void randomDrop(int value, float dropX, float dropY) {
//        switch (value) {
//            case 0:
//                game.batch.draw(dropImage, dropX, dropY);
//                break;
//            case 1:
//                //game.batch.draw(dropImage2, dropX, dropY);
//                break;
//            default:
//                game.batch.draw(dropImage, dropX, dropY);
//                break;
//        }
//    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void show() {
        // start the playback of the background music when the screen is shown
        //rainMusic.play();
    }

    @Override
    public void hide() {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
        dropImage.dispose();
        bucketImage.dispose();
        dropSound.dispose();
        //rainMusic.dispose();
    }
}

继承我的班级滴水

public class Drops {
    private Rectangle raindrop;
    private int imageHeight, imageWidth, x, y;
    private Array<Rectangle> raindrops;
    private long lastDropTime;
    private Texture dropImage = new Texture(Gdx.files.internal("droplet.png"));
    Iterator<Rectangle> iter = GameScreen.raindrops.iterator();
    private float runTime = 0;

    public Drops(Texture img, int imageHeight, int imageWidth, Array<Rectangle> drop, float delta) {
        this.imageHeight = imageHeight;
        this.imageWidth = imageWidth;
        this.raindrops = drop;
        this.dropImage = img;
    }

    public void update(float delta) {
        while (iter.equals(true)) {
            raindrop = iter.next();
            raindrop.y -= 200 * Gdx.graphics.getDeltaTime();
            if (raindrop.y + 64 < 0) iter.remove();
            onCollision();
        }

    }

    public void onCollision() {
        if (raindrop.overlaps(bucket)) {
            GameScreen.dropsGathered++;
            GameScreen.dropSound.play();
            iter.remove();
        }
    }

    public void spawnRaindrop() {
        Rectangle raindrop = new Rectangle();
        raindrop.x = MathUtils.random(0, 800 - 64);
        raindrop.y = 480;
        raindrop.width = imageWidth;
        raindrop.height = imageHeight;
        raindrops.add(raindrop);
        lastDropTime = TimeUtils.nanoTime();

    }

    public long getLastDropTime() {
        return lastDropTime;
    }

}

通过drop.spawnRaindrop(); 你将drop添加到Array<Rectangle> raindrops; 在您的Drops类中,但是为了绘制您的使用

for (Rectangle raindrop : raindrops) {
        game.batch.draw(dropImage, raindrop.x, raindrop.y);
    }

这将循环槽raindrop数组列表中你GameScreen里面是空的。

因此要么在Dropsh中绘制数组列表,要么在GameScreen中填充数组列表。

重构时需要更加小心。 您在屏幕类中留下了原始的矩形阵列数组,并且您正在绘制它(现在为空)。 然后在Drops类中,您将引用屏幕类中现在无用数组的迭代器。 而且你正在屏幕的渲染方法中更新那个空数组。

基本上,需要在一个地方处理掉落,但是你要处理两个不同类中的冗余数组,并将它们全部混合起来。

我不清楚为什么你甚至有一个名为Drops的类试图处理与桶的冲突。 没有理由将顶级游戏逻辑移动到单独的类中,因为这会使代码复杂化。 如果你有一个更复杂的游戏,有一个单独的类来跟踪和更新游戏的各个方面可能是有意义的。

顺便说一句,你正在泄漏你在这一行加载的纹理:

private Texture dropImage = new Texture(Gdx.files.internal("droplet.png"));

因为在构造函数中用另一个引用替换引用之前,你从不处理它。 在LibGDX中,任何实现Disposable的对象必须在其引用丢失之前被丢弃,否则它将泄漏本机内存。

允许多个丢弃图像的直接方式:

1)使用屏幕类中的所有游戏逻辑返回到原始单个类。

2)将您的拖放图像加载到阵列中以便于访问。

private final Array<Texture> dropImages = new Array<Texture>();  // replaces your dropImage declaration

//...

// in constructor:
dropImages.add(new Texture(Gdx.files.internal("droplet.png")));
dropImages.add(new Texture(Gdx.files.internal("droplet1.png")));
// etc. as many variations as you like

// don't forget to dispose of them:
@Override
public void dispose() {
    for (Texture dropImage : dropImages) dropImage.dispose();
    bucketImage.dispose();
    dropSound.dispose();
}

3)创建一个扩展Rectangle的类Drop,并为图像类型添加一个附加参数。 您可能还希望通过图像索引进行这些排序,以避免在绘制时多次在Textures之间进行交换,这会导致批量刷新,因为您没有使用TextureAtlas。

public class Drop extends Rectangle implements Comparable<Drop>{

    public int imageIndex;

    public Drop (){
        super();
    }

    public int compareTo(Drop otherDrop) {
        return (int)Math.signum(imageIndex - otherDrop.imageIndex);
    }

}

4)将Array<Rectangle>更改为Array<Drop> 当你产生一个drop时,也给它一个随机的图像索引:

private void spawnRaindrop() {
    Drop raindrop = new Drop ();
    raindrop.x = MathUtils.random(0, 800 - 64);
    raindrop.y = 480;
    raindrop.width = 64;
    raindrop.height = 64;
    raindrop.imageIndex = MathUtils.random(dropImages.size); // <-- HERE
    raindrops.add(raindrop);
    lastDropTime = TimeUtils.nanoTime();
}

5)绘制水滴时,使用drop的imageIndex来绘制正确的纹理。 您可以先对它们进行排序,以避免来回交换纹理:

// Draws the Items Falling
raindrops.sort();
for (Drop raindrop : raindrops) {
    game.batch.draw(dropImages.get(raindrop.imageIndex), raindrop.x, raindrop.y);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM