0

みんな、またあなたの助けが必要です:)

MainRenderer.java:

package com.example.galaga2d;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.ByteOrder;
import java.util.Random;
import java.util.Vector;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLUtils;

public class MainRenderer implements Renderer {
    Random rand = new Random();
    float chance = 0.0f;
    private Context context;

    public Ship playerShip = new Ship();

    Vector<Asteroid> asteroidVector = new Vector<Asteroid>();

    public MainRenderer(Context context) {
        this.context = context;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        //! TEXTURES
        playerShip.loadGLTexture(gl, this.context);

        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_SRC_COLOR);
        //gl.glShadeModel(GL10.GL_SMOOTH);
        //! TEXTURES

        gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    }


    @Override
    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        gl.glLoadIdentity();


        chance = rand.nextFloat() * (100.0f - 1.0f) + 1.0f;

        if (chance <= 4.0f) {
            asteroidVector.addElement(new Asteroid());
        }


        if (playerShip.life != 0) {

            playerShip.draw(gl);

            gl.glLoadIdentity();

            for (int i = 0; i < asteroidVector.size(); i++) {
                if(asteroidVector.elementAt(i).textured == 0) {
                    asteroidVector.elementAt(i).loadGLTexture(gl,  this.context);
                    asteroidVector.elementAt(i).textured |= 1;
                    //gl.glLoadIdentity();
                } else {
                    asteroidVector.elementAt(i).textured &= ~1;
                }

            }

            for (int i = 0; i < asteroidVector.size(); i++) {
                asteroidVector.elementAt(i).collisionCheck();
                asteroidVector.elementAt(i).draw(gl);
                if (asteroidVector.elementAt(i).Y > 480.0f) {
                    asteroidVector.remove(i);
                }

                gl.glLoadIdentity();
            }

        } else {
            gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
        }


    }



    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrthof(0, width, height, 0, 1, -1);
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

// --------------------------------------------------------------------------------

    class Ship {
        public int life = 3;                    // Количество жизней игрока

        public FloatBuffer ShipVertexBuffer;    // Vertex буффер
        public FloatBuffer ShipTextureBuffer;   // Texture буффер

        public float X = 100.0f;                // Начальные координаты игрока по X
        public float Y = 300.0f;                // Начальные координаты игрока по Y

        //! TEXTURES
        private int[] textures = new int[1];
        //! TEXTURES

        public float ShipVerticles[] = {        // Вертикли прямоугольника - корабль
            0, 0,
            0, 30,
            30, 0,
            30, 30
        };

        //! TEXTURES
        public float ShipTextures[] = {         // Разметка наложения текстуры, соответствует
                0.0f, 0.0f,                     // разметке вертиклей
                0.0f, 1.0f,
                1.0f, 0.0f,
                1.0f, 1.0f
            };
        //! TEXTURES

        public Ship() {
            //! Буффер вертексов
            ByteBuffer bb = ByteBuffer.allocateDirect(36);
            bb.order(ByteOrder.nativeOrder());
            ShipVertexBuffer = bb.asFloatBuffer();
            ShipVertexBuffer.put(ShipVerticles);
            ShipVertexBuffer.position(0);

            //! TEXTURES
            bb = ByteBuffer.allocateDirect(ShipTextures.length * 4);
            bb.order(ByteOrder.nativeOrder());
            ShipTextureBuffer = bb.asFloatBuffer();
            ShipTextureBuffer.put(ShipTextures);
            ShipTextureBuffer.position(0);
            //! TEXTURES
        }

        public void loadGLTexture(GL10 gl, Context context) {
            // loading texture
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.ship);

            // generate one texture pointer
            gl.glGenTextures(1, textures, 0);
            // ...and bind it to our array
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

            // create nearest filtered texture
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

            // Use Android GLUtils to specify a two-dimensional texture image from our bitmap 
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

            // Clean up
            bitmap.recycle();
        }

        public void draw(GL10 gl) {
            //! TEXTURE
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            //! TEXTURE

            gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
            gl.glTranslatef(playerShip.X, playerShip.Y, 0.0f);
            gl.glVertexPointer(2, GL10.GL_FLOAT, 0, ShipVertexBuffer);

            //! TEXTURE         
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, ShipTextureBuffer);
            //! TEXTURE         

            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

            //! TEXTURE             
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            //! TEXTURE 
        }

    }

    class Asteroid {
        private float colorR = rand.nextFloat()* (1.0f - 0.3f) + 0.3f;
        private float colorG = rand.nextFloat()* (1.0f - 0.3f) + 0.3f;
        private float colorB = rand.nextFloat()* (1.0f - 0.3f) + 0.3f;

        private float X = rand.nextFloat() * (300.0f - 1.0f) + 1.0f;
        private float Y = -30.0f;

        private float size = rand.nextFloat() * (30.0f - 20.0f) + 20.0f;

        private float speed = rand.nextFloat() * (10.0f - 1.0f) + 1.0f;

        private int collision = 0;

        private int textured = 0;

        private FloatBuffer AsteroidVertexBuffer;
        private FloatBuffer AsteroidTextureBuffer;

        //! TEXTURES
        private int[] textures = new int[1];
        //! TEXTURES

        public float AsteroidVerticles[] = {
                0, 0,       // лево низ
                0, size,        // лево вверх
                size, 0,        // право низ
                size, size      // право вверх
            };

        //! TEXTURES
        public float AsteroidTextures[] = {
                0.0f, 0.0f,
                0.0f, 1.0f,
                1.0f, 0.0f,
                1.0f, 1.0f
            };
        //! TEXTURES

        public Asteroid() {


            ByteBuffer bb = ByteBuffer.allocateDirect(36);
            bb.order(ByteOrder.nativeOrder());
            AsteroidVertexBuffer = bb.asFloatBuffer();
            AsteroidVertexBuffer.put(AsteroidVerticles);
            AsteroidVertexBuffer.position(0);

            //! TEXTURES
            bb = ByteBuffer.allocateDirect(AsteroidTextures.length * 4);
            bb.order(ByteOrder.nativeOrder());
            AsteroidTextureBuffer = bb.asFloatBuffer();
            AsteroidTextureBuffer.put(AsteroidTextures);
            AsteroidTextureBuffer.position(0);
            //! TEXTURES
        }

        public void collisionCheck() {
            float result = (float)Math.sqrt(Math.pow((playerShip.X-X), 2)+Math.pow((playerShip.Y-Y), 2));

            if (result < size)
            {
                if(collision == 0)
                {
                    playerShip.life = playerShip.life - 1;
                    collision |= 1;
                }
            } else {
                collision &= ~1;
            }
        }

        public void loadGLTexture(GL10 gl, Context context) {
            // loading texture
            Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.asteroid);

            // generate one texture pointer
            gl.glGenTextures(1, textures, 0);
            // ...and bind it to our array
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

            // create nearest filtered texture
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

            // Use Android GLUtils to specify a two-dimensional texture image from our bitmap 
            GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

            // Clean up
            bitmap.recycle();
        }

        public void draw(GL10 gl) {
            Y += speed;
            //! TEXTURE
            gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            //! TEXTURE

            gl.glColor4f(colorR, colorG, colorB, 1.0f);

            gl.glTranslatef(X, Y, 0.0f);
            gl.glVertexPointer(2, GL10.GL_FLOAT, 0, AsteroidVertexBuffer);

            //! TEXTURE         
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, AsteroidTextureBuffer);
            //! TEXTURE         

            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);

            //! TEXTURE             
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            //! TEXTURE 
        }

    }

// --------------------------------------------------------------------------------

}

すべてのフレームで、オブジェクトの小惑星が偶然に描画されます:

chance = rand.nextFloat() * (100.0f - 1.0f) + 1.0f;

if (chance <= 4.0f) {
    asteroidVector.addElement(new Asteroid());
}

つまり、毎秒描画するすべての新しいオブジェクトのテクスチャをロードする必要がありますが、1 つのオブジェクトのテクスチャを何度もロードする必要はありません。オブジェクトがテクスチャ化されているかどうかを確認するフラグを追加します。

    for (int i = 0; i < asteroidVector.size(); i++) {
        if(asteroidVector.elementAt(i).textured == 0) {
            asteroidVector.elementAt(i).loadGLTexture(gl,  this.context);
            asteroidVector.elementAt(i).textured |= 1;
            //gl.glLoadIdentity();
        } else {
            asteroidVector.elementAt(i).textured &= ~1;
        }

    }

オブジェクトを作成してテクスチャリングした後、画面の境界線を越えた場合はオブジェクトを削除する必要があるため、次のようにします。

        for (int i = 0; i < asteroidVector.size(); i++) {
            asteroidVector.elementAt(i).collisionCheck();
            asteroidVector.elementAt(i).draw(gl);
   //! THIS
            if (asteroidVector.elementAt(i).Y > 480.0f) {
                asteroidVector.remove(i);
            }
   //! THIS
            gl.glLoadIdentity();
        }

しかし、それだけでは十分ではありません。Tuxture バッファーがクリアされず、アプリケーションの実行で 10 ~ 20 秒後に遅延と低 fps が見られるためです。

問題は、テクスチャ バッファまたはメモリをクリアするにはどうすればよいかということです。遅延と低 fps を修正するには?

4

1 に答える 1

0

それはできると思いますが、そもそも必要な状況に陥ってはいけません。

現状では、これまでに構築されたすべてのものに対して新しいテクスチャ オブジェクトを作成しています(決して解放することはありません!)。Asteroidこれは絶対に必要ではありません。これを修正する優れた方法は、すべてのAsteroidインスタンスに共有テクスチャ オブジェクトを使用することです。 .

静的関数 ( onceと呼ばれる) では、画像リソースを raw ピクセル データにデコードするだけです -> glGenTextures-> glBindTexture->glTexParam...呼び出し -> GLUtils.TexImage2D-> (クライアント側) デコードされた raw ピクセル データを解放し、テクスチャ ID ( で指定glGenTextures) をAsteroidクラス内の静的変数。これを行うと、レンダリング段階 (つまり ) でこの共有drawテクスチャ オブジェクトにバインドし、通常どおりに処理を進めることができます。

前に述べたように、決して呼び出しを行わないことglDeleteTexturesが問題の 2 番目の部分ですが、(できれば)Asteroidインスタンスに共有テクスチャ オブジェクトを使用しているため、それほど重要ではなくなります。

(さらに、頂点/texcoord バッファでさえ、それらが同一であれば、インスタンス間で共有できます:P)

于 2013-08-22T08:45:44.913 に答える