尝试为测试动画设置游戏循环线程时,我遇到了一些问题。启动过程中显示错误,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;
}
}
我一直无法找到问题,非常感谢帮助!谢谢!