1

尝试为测试动画设置游戏循环线程时,我遇到了一些问题。启动过程中显示错误,Android 程序通过启动屏幕运行,但随后终止。这是红色突出显示的 Logcat 错误。

09-24 16:09:18.731: E/AndroidRuntime(569): FATAL EXCEPTION: GLThread 76
09-24 16:09:18.731: E/AndroidRuntime(569): java.lang.NullPointerException
09-24 16:09:18.731: E/AndroidRuntime(569):  at 
com.spacewrecksoftware.iceward.GLrenderer.onSurfaceCreated(GLrenderer.java:22)
09-24 16:09:18.731: E/AndroidRuntime(569):  at 
android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1446)
09-24 16:09:18.731: E/AndroidRuntime(569):  at 
android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)

该程序创建一个在横向屏幕上来回移动的纹理,并通过插值渲染的测试实现以更高的帧速率实现更流畅的动画。这是按顺序排列的游戏循环、渲染器、菜单、对象和状态文件。

游戏循环:

import android.os.SystemClock;

public class GameLoop extends Thread {
public static int deltaTime;
boolean gameRunning = true;
public void setRunning(boolean running) {
    this.gameRunning = running;
}
public ObjectState previous= new ObjectState(0, 0, 10/1000, 0);
public ObjectState current= new ObjectState(0, 0, 10/1000, 0);
public Globject button= new Globject(previous, current);
public void run() {

    int ticksPerSec = 30;
    int skipTicks = 1000 / ticksPerSec;
    int maxFrameskip = 5;
    long nextGameTick = SystemClock.uptimeMillis();
    int loops;
    long interpolation;
    long oldTimeSinceStart = 0;

    while (gameRunning) {


        loops = 0;
        while( SystemClock.uptimeMillis() > nextGameTick & loops < maxFrameskip){
            long timeSinceStart = SystemClock.uptimeMillis();
              deltaTime = (int) (timeSinceStart - oldTimeSinceStart);
             oldTimeSinceStart = timeSinceStart;
            updateGame();
             nextGameTick += skipTicks;
                loops++;
            }
        interpolation = SystemClock.uptimeMillis() + skipTicks - nextGameTick 
                /  skipTicks ;
        drawGame(interpolation);
    }
}
int switchit = 1;
private void updateGame() {
    if (switchit==1){   
        if (button.now.position_x<=-10){        
             switchit=0;
             button.past.velocity_x=0-button.past.velocity_x;
        }
        else{
    button.past=button.now.copy(button.now);
    button.now=button.past.addDt(button.past, deltaTime);
        }
    }
    else if(switchit==0){   
        if (button.now.position_x>=10){     
             switchit=1;
             button.past.velocity_x=0-button.past.velocity_x;
        }
        else{
            button.past=button.now.copy(button.now);
            button.now=button.past.addDt(button.past, deltaTime);
        }
    }

}
private void drawGame(float interpolation) {
    button.past=button.past.interpolate(button.past, button.now, interpolation);
    Menu.menuSurface.requestRender();

}
}

渲染器:

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;


public class GLrenderer implements Renderer {

private Globject object1;   
private Context context;
long startTime;
public GLrenderer(Context context) {
    this.context = context;
    object1 = new Globject(null, null);
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {       
    //Load the texture for the cube once during Surface creation
    object1.now.position_x=0;
    object1.past.position_x=0;
    object1.loadGLTexture(gl, this.context);
    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
    gl.glEnable(GL10.GL_TEXTURE_2D);            //Enable Texture Mapping
    gl.glShadeModel(GL10.GL_SMOOTH);            //Enable Smooth Shading
    gl.glClearColor(0.0f, 0.666f, 0.831f, 1f); 
    gl.glClearDepthf(1.0f);                     //Depth Buffer Setup
    gl.glEnable(GL10.GL_DEPTH_TEST);            //Enables Depth Testing
    gl.glDepthFunc(GL10.GL_LEQUAL);             //The Type Of Depth Testing To Do

    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 
}
/**
 * Here we do our drawing
 */
public void onDrawFrame(GL10 gl) {
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);    
    gl.glLoadIdentity();        

    gl.glTranslatef(0.0f, 0.0f, -20f);  
    gl.glPushMatrix();
    gl.glTranslatef( object1.past.position_x, 0, 0);    
    object1.draw(gl);
    gl.glPopMatrix();

}

/**
 * If the surface changes, reset the view
 */
public void onSurfaceChanged(GL10 gl, int width, int height) {
    if(height == 0) {                       //Prevent A Divide By Zero By
        height = 1;                         //Making Height Equal One
    }

    gl.glViewport(0, 0, width, height);     //Reset The Current Viewport
    gl.glMatrixMode(GL10.GL_PROJECTION);    //Select The Projection Matrix
    gl.glLoadIdentity();                    //Reset The Projection Matrix

    //Calculate The Aspect Ratio Of The Window
    GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);

    gl.glMatrixMode(GL10.GL_MODELVIEW);     //Select The Modelview Matrix
    gl.glLoadIdentity();                    //Reset The Modelview Matrix
}
}

菜单:

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

public class Menu extends Activity
{
static GLSurfaceView menuSurface;
private GameLoop thread;
@Override
public void onCreate(Bundle savedInstanceState) 
{

    super.onCreate(savedInstanceState);
    menuSurface = new GLSurfaceView(this);
        menuSurface.setRenderer(new GLrenderer(this));
        menuSurface.setRenderMode(0);
    setContentView(menuSurface);
    thread = new GameLoop();
    thread.setRunning(true);
    thread.start();
}

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

@Override
protected void onPause() 
{   
    super.onPause();
    menuSurface.onPause();
}   
public boolean onTouchEvent(MotionEvent event) {
            return super.onTouchEvent(event);   
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
while (retry) {
    try {
        thread.join();
        retry = false;
    } catch (InterruptedException e) {
        // try again shutting down the thread
    }
}
}
}

对象:注意-图像是 2 的幂,四乘一纹理。

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 android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;

public class Globject {

private FloatBuffer vertexBuffer;

private FloatBuffer textureBuffer;

private ByteBuffer indexBuffer;


private int[] textures = new int[1];
public ObjectState past;
public ObjectState now;

private float vertices[] = {
                    //Vertices according to faces
                    -4.0f, 1.0f,  //Vertex 0
                    -4.0f, -1.0f,  //v1
                    4.0f, 1.0f,   //v2
                    4.0f, -1.0f   //v3

                                        };

/** The initial texture coordinates (u, v) */   
private float texture[] = {         
                    //Mapping coordinates for the vertices  
                    0.0f, 0.0f,
                    0.0f, 1.0f,             
                    1f, 0.0f,
                    1f, 1.0f


                                        };

/** The initial indices definition */   
private byte indices[] = {

        0,1,2,3             
                                        };

public Globject(ObjectState past2,ObjectState now2) {

    now=now2;
    past=past2;

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

    //
    byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
    byteBuf.order(ByteOrder.nativeOrder());
    textureBuffer = byteBuf.asFloatBuffer();
    textureBuffer.put(texture);
    textureBuffer.position(0);

    //
    indexBuffer = ByteBuffer.allocateDirect(indices.length);
    indexBuffer.put(indices);
    indexBuffer.position(0);
}

public void draw(GL10 gl) {
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

    //Point to our buffers
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    //Set the face rotation
    gl.glFrontFace(GL10.GL_CW);

    //Enable the vertex and texture state
    gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

    //Draw the vertices as triangles, based on the Index Buffer information
    gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);

    //Disable the client state before leaving
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}

public void loadGLTexture(GL10 gl, Context context) {
    //Get the texture from the Android resource directory
    InputStream is = context.getResources().openRawResource(R.drawable.custom_button1);
    Bitmap bitmap = null;
    try {
        bitmap = BitmapFactory.decodeStream(is);

    } finally {
        //Always clear and close
        try {
            is.close();
            is = null;
        } catch (IOException e) {
        }
    }

    //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_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    //Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);

    //Use the 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 class ObjectState {
public float position_x;
public float position_y;
public float velocity_x;
public float velocity_y;
public ObjectState(float position_x2, float position_y2, float velocity_x2, float velocity_y2) {
    position_x = position_x2;
    position_y = position_y2;
    velocity_x = velocity_x2;
    velocity_y = velocity_y2;
}
public ObjectState copy(ObjectState state0) {
ObjectState state1= new ObjectState(state0.position_x, state0.position_y,
        state0.velocity_x, state0.velocity_y);
return state1;
}  
public ObjectState subtract(ObjectState state, ObjectState state1){
    ObjectState  state2=state.copy(state);
    state2.position_x=(state1.position_x-state.position_x);
    state2.position_y=(state1.position_y-state.position_y);
    state2.velocity_x=(state1.velocity_x-state.velocity_x);
    state2.velocity_y=(state1.velocity_y-state.velocity_y);
return state2;
}
public ObjectState addDt(ObjectState state, int deltaTime){
    ObjectState  state1=state.copy(state);
    state1.position_x=(state1.velocity_x*deltaTime)+state1.position_x;
    state1.position_y=(state1.velocity_y*deltaTime)+state1.position_y;
return state1;
}
public ObjectState interpolate(ObjectState state, ObjectState state2,float interpolate){
    ObjectState  state1=state.copy(state);
    state1.position_x=(state1.subtract(state2, state).position_x*interpolate)+state.position_x;
    state1.position_y=(state1.subtract(state2, state).position_y*interpolate)+state.position_y;
    state1.velocity_x=(state1.subtract(state2, state).velocity_x*interpolate)+state.velocity_x;
    state1.velocity_y=(state1.subtract(state2, state).velocity_y*interpolate)+state.velocity_y;
return state1;
}
}

我一直无法找到问题,非常感谢帮助!谢谢!

4

1 回答 1

1

这是一个空指针异常。

在您的GLrenderer构造函数中,您具有以下内容:

object1 = new Globject(null, null);

在您的GLobject代码中:

public Globject(ObjectState past2,ObjectState now2) {

    now=now2;
    past=past2;
    //...

然后回到GLRenderer你有:

public void onSurfaceCreated(GL10 gl, EGLConfig config) {       
    //Load the texture for the cube once during Surface creation
    object1.now.position_x=0;
    object1.past.position_x=0;

now,并且past仍然为空。它们需要在被访问之前被分配。

于 2012-11-01T15:50:15.827 回答