Android 2D Game With OpenGL

柔情痞子 提交于 2019-12-12 09:15:45

问题


Recently I worked on a 2D Game using SurfaceView and I learned a lot about game loops and everything. But now I want to make the same game using OpenGL. I read that the GLSurfaceView is the class that would be relative to what SurfaceView was. But I'm not sure about other things as:

Using SurfaceView, I used the Bitmap class to load a image resource that would be lets say a character. And that bitmap would be a property of my Character class. And for the gameloop I used a different Thread

I'm new to OpenGL so I'd like to know how to load image resources (do I load them using the Bitmap class?), or what to use instead of a Thread for the game loop?


回答1:


do I load them using the Bitmap class?

Yes, you can load bitmap and use it as textImage2D.

Example:

public void loadTextures(GL10 gl, Context context) {
    Log.e(LOG_TAG, "ExplosionSprite :: loadTextures");  

    mFrame = 0;

    InputStream is;
    Bitmap bitmap;
    is = context.getResources().openRawResource(DRAW_SOURCE);


    bitmap = BitmapFactory.decodeStream(is);
    try {
        is.close();
        is = null;
    } catch (IOException e) {
    }

    gl.glGenTextures(TEXTURE_COUNT, textures, 0);

    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle(); 
}

Before 4 month I did the same, because of performance switched to OpenGL ES 2D.

Its a bit complicated but after some time seems easy enough.

I don't have right now example for single image but have pretty good example for sprite sheet where I animate my Image. I'm sure you can remove not relevant data to make it for one static image. Google has enough resources "how to" so I'll point what I used for my purposes:

link 1

link 2

link 3

Cast_001_Sprite_.java

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

import javax.microedition.khronos.opengles.GL10;

import net.obviam.droidz.R;
import net.obviam.droidz.model.components.ESpriteDirection;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
import android.util.Log;

public class Cast_001_Sprite_ {

    private static final String LOG_TAG = Cast_001_Sprite.class.getSimpleName();

    /** Sprite sheet definition */
    private static final int SPRITE_WIDTH = 5;
    private static final int SPRITE_HEIGHT = 4;
    private int DRAW_SOURCE = R.drawable.a1;

    private int mX = Location._1[0]; // 100;
    private int mY = Location._1[1]; // 100;


    private float mScreenWidth, mScreenHeight, wRatio, hRatio;
    private int mFrame = 0;
    private int mSwitcher = 0;
    private final static int TEXTURE_COUNT = 1; // for sprite sheet we use 1 image all the time.
    private int[] textures = new int[TEXTURE_COUNT]; // frame animation

    protected FloatBuffer vertexBuffer;

    private final static ESpriteDirection mDirection = ESpriteDirection.TOP_TO_DOWN_LEFT_TO_RIGHT;


    public float x, y, initPos, finalPos, initSpeed, currentPos;

    private ByteBuffer bb1;

    private final static int TOTAL_IMAGE_COUNT_IN_SPRITE = SPRITE_WIDTH * SPRITE_HEIGHT;

    private FloatBuffer[] floatBufferArray = new FloatBuffer[TOTAL_IMAGE_COUNT_IN_SPRITE];

    private float xOffset = 1.0f/SPRITE_WIDTH;
    private float yOffset = 1.0f/SPRITE_HEIGHT;


    float[] vertices = new float[] {
            -1.0f, -1.0f, 0.0f,
            -1.0f, 1.0f, 0.0f,
           1.0f,  -1.0f, 0.0f,
            1.0f, 1.0f, 0.0f };


    private float storage[][] = new float[TOTAL_IMAGE_COUNT_IN_SPRITE][];
    private int[] sprite_X_Indexes = new int[SPRITE_WIDTH];//{1,2,3,4}; 
    private int[] sprite_Y_Indexes = new int[SPRITE_HEIGHT];//{1,2,3,4};





    public Cast_001_Sprite_(float screenWidth, float screenHeight){

        generateSpriteIndexes();

        updateScreenData(screenWidth, screenHeight);

        int index = 0;

        switch (mDirection) {
        case TOP_TO_DOWN_LEFT_TO_RIGHT:

            for(int row = 0; row<SPRITE_HEIGHT; row++){
                for(int column = 0; column<SPRITE_WIDTH; column++){
                    storage[index] = generateTextures(column, row);
                    index++;
                }
            }
            break;
        case DOWN_TO_TOP_LEFT_TO_RIGHT:
            //TODO
            //          for(int row = spriteLength; row>0; row--){
            //              for(int column = 0; column<spriteHeight; column++){
            //                  storage[index] = generateTextures( row-1, column);
            //                  index++;
            //              }
            //          }
            break;

        default:
            break;
        }       


        // vertices buffer
        bb1 = ByteBuffer.allocateDirect(vertices.length * 4);
        bb1.order(ByteOrder.nativeOrder());
        vertexBuffer = bb1.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        for(int i=0; i<TOTAL_IMAGE_COUNT_IN_SPRITE; i++){
            bb1 = ByteBuffer.allocateDirect(storage[i].length * 4);
            bb1.order(ByteOrder.nativeOrder());
            FloatBuffer textureBuffer = bb1.asFloatBuffer();
            textureBuffer.put(storage[i]);
            textureBuffer.position(0);

            floatBufferArray[i] = textureBuffer;
        }
    }

    private void generateSpriteIndexes() {      

        for(int indexX = 0; indexX<SPRITE_WIDTH; indexX++){
            sprite_X_Indexes[indexX] = indexX+1;
        }

        for(int indexY = 0; indexY<SPRITE_HEIGHT; indexY++){
            sprite_Y_Indexes[indexY] = indexY+1;
        }
    }

    public void updateScreenData(float screenWidth, float screenHeight){
        // takes screen Height and Width
        this.mScreenWidth = (screenWidth > 0) ? screenWidth : 1f;
        this.mScreenHeight = screenHeight;
        wRatio = 10f/mScreenWidth;
        hRatio = mScreenHeight/10f;
        addExplosion(mX,mY);
    }


    public void addExplosion(float x, float y) {        
        this.x = x;
        this.y = y;
        this.initPos = y;
    }


    /**
     * Generates texture by location
     * 
     * @param texture - fill current texture
     * @param placeX - image place in sprite scale X
     * @param placeY - image place in sprite scale Y
     * @return 
     */
    private float[] generateTextures(int placeX, int placeY) {

        float texture[] = new float[8];

        /*
        V1 _____ V3 
          |     |
          |     |
        V2|_____|V4 
         */
        //StringBuffer buff = new StringBuffer();

        /** V1 */   
        texture[0] = (placeX == 0)?0.0f : xOffset*sprite_X_Indexes[placeX-1];  
        texture[1] = yOffset*sprite_Y_Indexes[placeY];

        /** V2 */
        texture[2] = (placeX == 0)?0.0f : xOffset*sprite_X_Indexes[placeX-1];
        texture[3] = (placeY == 0)?0.0f : yOffset*sprite_Y_Indexes[placeY-1];

        /** V3 */
        texture[4] = xOffset*sprite_X_Indexes[placeX];
        texture[5] = yOffset*sprite_Y_Indexes[placeY];

        /** V4 */
        texture[6] = xOffset*sprite_X_Indexes[placeX];
        texture[7] = (placeY == 0)?0.0f : yOffset*sprite_Y_Indexes[placeY-1];


        return texture;

    }


    private void update() {
        if(mSwitcher == 1){
            mFrame = ++mFrame % TOTAL_IMAGE_COUNT_IN_SPRITE;
            mSwitcher = 0;
            // Log.e(LOG_TAG, "DevQuestSpriteBase :: " + mFrame);   
        }
        else{
            mSwitcher++; 
        }   
    }

    public void reset(){
        mFrame = 0;
    }


    public void loadTextures(GL10 gl, Context context) {
        Log.e(LOG_TAG, "ExplosionSprite :: loadTextures");  

        mFrame = 0;

        InputStream is;
        Bitmap bitmap;
        is = context.getResources().openRawResource(DRAW_SOURCE);


        bitmap = BitmapFactory.decodeStream(is);
        try {
            is.close();
            is = null;
        } catch (IOException e) {
        }

        gl.glGenTextures(TEXTURE_COUNT, textures, 0);

        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

        bitmap.recycle(); 

    }

    public void draw(GL10 gl){
//      if(mFrame == TOTAL_IMAGE_COUNT_IN_SPRITE - 1){
//          return;
//      }

        gl.glPushMatrix();
        try {
            float transx =  + (wRatio * x);
            float transy =  + (mScreenHeight*wRatio) - (wRatio * y) - 1/hRatio;

            // Log.e(LOG_TAG, "transx: " + transx + "; transy: " + transy + "; sprite.x: "+  sprite.x + "; sprite.y: " + sprite.y);  

            gl.glTranslatef(transx, transy, 0.0f);

            //###########  draw ##############

            gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
            gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, floatBufferArray[mFrame]);

            update();

            gl.glColor4f(1f, 1f, 1f, 0.2f);

            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
            gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

            //###############################

        } catch (NullPointerException e) {
        }
        gl.glPopMatrix();           
    }
} 

DevQuest1Activity.java

public class DevQuest1Activity extends Activity {
private DevQuestGLSurfaceView mGLView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    mGLView = new DevQuestGLSurfaceView(this);
    setContentView(mGLView);
}

@Override
protected void onPause() {
    super.onPause();
    mGLView.onPause();
}

@Override
protected void onResume() {
    super.onResume();
    mGLView.onResume();
}
}

DevQuestGLRenderer.java

public class DevQuestGLRenderer implements GLSurfaceView.Renderer {

private static final String LOG_TAG = "Fess";//DevQuestGLRenderer.class.getSimpleName();

private Context context;
private float ratio;
private int screenWidth, screenHeight;


public Cast_001_Sprite Cast_001_Sprite;


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

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig confid) {
    gl.glEnable(GL10.GL_TEXTURE_2D);
    gl.glShadeModel(GL10.GL_SMOOTH);
    gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    gl.glClearDepthf(1.0f);
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
    gl.glEnable(GL10.GL_BLEND);
    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
    gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, /*GL10.GL_REPLACE*/ GL10.GL_MODULATE);  


}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {

    Log.e(LOG_TAG, "onSurfaceChanged"); 

    // prevent 0 divise
    if(height == 0) { height=1;}
    screenWidth = width; screenHeight = height;
    ratio = (float) width/height;
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    gl.glOrthof(0, width, 0, height, -10f, 10f);
    gl.glViewport(0, 0, screenWidth, screenHeight);

    Cast_001_Sprite = new Cast_001_Sprite(width, height);

    Cast_001_Sprite.loadTextures(gl, context);      
}

@Override
public void onDrawFrame(GL10 gl) {

    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();

    gl.glPushMatrix();
    gl.glScalef((screenWidth)/10, (screenHeight*ratio)/10, 1.0f);

    Cast_001_Sprite.draw(gl);

    gl.glPopMatrix();
}   
}

DevQuestGLSurfaceView.java

 public class DevQuestGLSurfaceView extends GLSurfaceView {
 private DevQuestGLRenderer mRenderer;

  private int count = 0;

  public DevQuestGLSurfaceView(Context context) {
    super(context);
    mRenderer = new DevQuestGLRenderer(context);
    setRenderer(mRenderer);
  }

 @Override
  public boolean onTouchEvent(MotionEvent event) {

   return true;
  }
}

ESpriteDirection.java

public enum ESpriteDirection {
 TOP_TO_DOWN_LEFT_TO_RIGHT,
 DOWN_TO_TOP_LEFT_TO_RIGHT,
 TOP_TO_DOWN_RIGHT_TO_LEFT,
 DOWN_TO_TOP_RIGHT_TO_LEFT
}

And this is an image I used:




回答2:


USE THIS CODE TO LOAD YOUR IMAGE..

public static int loadTexture(Context context, int resourceId) {
        final int[] textureObjectIds = new int[1];
        glGenTextures(1, textureObjectIds, 0);

        if (textureObjectIds[0] == 0) {
            if (LoggerConfig.ON) {
                Log.w(TAG, "Could not generate a new OpenGL texture object.");
            }
            return 0;
        } 

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;

        // Read in the resource
        final Bitmap bitmap = BitmapFactory.decodeResource(
            context.getResources(), resourceId, options);

        if (bitmap == null) {
            if (LoggerConfig.ON) {
                Log.w(TAG, "Resource ID " + resourceId + " could not be decoded.");
            }

            glDeleteTextures(1, textureObjectIds, 0);
            return 0;
        } 
        // Bind to the texture in OpenGL
        glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);

        // Set filtering: a default must be set, or the texture will be
        // black.
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        // Load the bitmap into the bound texture.
        texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);

        // Note: Following code may cause an error to be reported in the
        // ADB log as follows: E/IMGSRV(20095): :0: HardwareMipGen:
        // Failed to generate texture mipmap levels (error=3)
        // No OpenGL error will be encountered (glGetError() will return
        // 0). If this happens, just squash the source image to be
        // square. It will look the same because of texture coordinates,
        // and mipmap generation will work.

        glGenerateMipmap(GL_TEXTURE_2D);

        // Recycle the bitmap, since its data has been loaded into
        // OpenGL.
        bitmap.recycle();

        // Unbind from the texture.
        glBindTexture(GL_TEXTURE_2D, 0);

        return textureObjectIds[0];
    }


来源:https://stackoverflow.com/questions/18791983/android-2d-game-with-opengl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!