使用 OpenGL 的 Android 2D 游戏 [英] Android 2D Game With OpenGL

查看:28
本文介绍了使用 OpenGL 的 Android 2D 游戏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我使用 SurfaceView 开发了一个 2D 游戏,我学到了很多关于游戏循环和一切的知识.但现在我想使用 OpenGL 制作相同的游戏.我读到 GLSurfaceView 是与 SurfaceView 相关的类.但我不确定其他事情:

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:

使用 SurfaceView,我使用 Bitmap 类加载一个图像资源,可以说是一个字符.该位图将是我的 Character 类的一个属性.对于游戏循环,我使用了不同的 Thread

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

我是 OpenGL 的新手,所以我想知道如何加载图像资源(我是否使用 Bitmap 类加载它们?),或者如何加载使用 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?

推荐答案

我是否使用 Bitmap 类加载它们?

do I load them using the Bitmap class?

是的,您可以加载位图并将其用作 textImage2D.

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

示例:

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(); 
}

在 4 个月之前,我做了同样的事情,因为性能切换到 OpenGL ES 2D.

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.

我现在没有单个图像的示例,但有一个很好的精灵表示例,我可以在其中为我的图像设置动画.我相信您可以删除不相关的数据以使其成为一张静态图像.Google 有足够的资源如何做",所以我会指出我用于我的目的:

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:

链接 1

链接 2

链接 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
}

这是我使用的图像:

这篇关于使用 OpenGL 的 Android 2D 游戏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆