Ich will in die 2D Spielprogrammierung einsteigen, ich verwende dabei eine SurfaceView auf der ich ein Sprite zeichnen möchte. Ich bekomme aber eine NPE und weiss nicht so genau wo ich etwas falsch gemacht habe. Hier der Stacktrace:
02-21 17:52:24.309: E/AndroidRuntime(21430): FATAL EXCEPTION: main
02-21 17:52:24.309: E/AndroidRuntime(21430): java.lang.NullPointerException
02-21 17:52:24.309: E/AndroidRuntime(21430): at com.example.canvastest.GameView.draw(GameView.java:36)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13020)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13062)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.draw(View.java:13839)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.drawChild(ViewGroup.java:3086)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2923)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13015)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13062)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.draw(View.java:13839)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.drawChild(ViewGroup.java:3086)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2923)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13015)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13062)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.draw(View.java:13839)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.drawChild(ViewGroup.java:3086)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2923)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13015)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13062)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.draw(View.java:13839)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.drawChild(ViewGroup.java:3086)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2923)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.draw(View.java:14129)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.widget.FrameLayout.draw(FrameLayout.java:471)
02-21 17:52:24.309: E/AndroidRuntime(21430): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2231)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13020)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.View.getDisplayList(View.java:13062)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.HardwareRenderer$GlRenderer.buildDisplayList(HardwareRenderer.java:1411)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1359)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewRootImpl.draw(ViewRootImpl.java:2375)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2247)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1880)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1008)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5508)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.Choreographer.doCallbacks(Choreographer.java:562)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.Choreographer.doFrame(Choreographer.java:532)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.os.Handler.handleCallback(Handler.java:730)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.os.Handler.dispatchMessage(Handler.java:92)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.os.Looper.loop(Looper.java:213)
02-21 17:52:24.309: E/AndroidRuntime(21430): at android.app.ActivityThread.main(ActivityThread.java:5225)
02-21 17:52:24.309: E/AndroidRuntime(21430): at java.lang.reflect.Method.invokeNative(Native Method)
02-21 17:52:24.309: E/AndroidRuntime(21430): at java.lang.reflect.Method.invoke(Method.java:525)
02-21 17:52:24.309: E/AndroidRuntime(21430): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:741)
02-21 17:52:24.309: E/AndroidRuntime(21430): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
02-21 17:52:24.309: E/AndroidRuntime(21430): at dalvik.system.NativeStart.main(Native Method)
und hier mein bisheriger code:
[XML]
<com.example.canvastest.GameView
android:id="@+id/surfaceViewGame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80000000" >
</com.example.canvastest.GameView>
<LinearLayout
android:id="@+id/linearLayoutButtons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right" >
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="l" >
</Button>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="r" >
</Button>
</LinearLayout>
[/XML]
import android.app.Activity;
import android.os.Bundle;
public class GameActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
}
}
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private Bitmap bmp;
private GameLoopThread theGameLoopThread;
private Sprite sprite;
public GameView(Context context) {
super(context);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.square);
sprite = new Sprite(bmp);
theGameLoopThread = new GameLoopThread(this);
}
public GameView(Context context, AttributeSet attrSet, int defStyle) {
super(context, attrSet, defStyle);
}
public GameView(Context context, AttributeSet attrSet) {
super(context, attrSet);
}
@Override
public void draw(Canvas canvas) {
canvas.drawColor(Color.DKGRAY);
sprite.draw(canvas);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
theGameLoopThread.setRunning(true);
theGameLoopThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
theGameLoopThread.setRunning(false);
while (retry) {
try {
theGameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}```
```package com.example.canvastest;
import android.graphics.Canvas;
public class GameLoopThread extends Thread {
private static final long FPS = 60;
private GameView gameView;
private boolean isRunning = false;
public GameLoopThread(GameView gameView) {
this.gameView = gameView;
}
public void setRunning(boolean run) {
isRunning = run;
}
@Override
public void run() {
long TPS = 1000 / FPS;
long startTime, sleepTime;
while (isRunning) {
Canvas theCanvas = null;
startTime = System.currentTimeMillis();
try {
theCanvas = gameView.getHolder().lockCanvas();
synchronized (gameView.getHolder()) {
gameView.draw(theCanvas);
}
} finally {
if (theCanvas != null) {
gameView.getHolder().unlockCanvasAndPost(theCanvas);
}
}
sleepTime = TPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {
}
}
}
}
import android.graphics.Bitmap;
import android.graphics.Canvas;
public class Sprite {
private int x = 0;
private int y = 0;
private int xSpeed;
private int ySpeed;
private int width;
private int height;
private Bitmap bmp;
public Sprite(Bitmap bmp) {
this.bmp = bmp;
this.width = bmp.getWidth();
this.height = bmp.getHeight();
ySpeed = 2;
xSpeed = 2;
}
/*
* private void bounceOff() { if (x > theGameView.getWidth() - width -
* xSpeed || x + xSpeed < 0) { xSpeed = -xSpeed; } x = x + xSpeed; if (y >
* theGameView.getHeight() - height - ySpeed || y + ySpeed < 0) { ySpeed =
* -ySpeed; } y = y + ySpeed; }
*/
public void draw(Canvas canvas) {
x += xSpeed;
y += ySpeed;
canvas.drawBitmap(bmp, x, y, null);
}
}
Der Fehler tritt gleich nach dem Start der App auf und wie ihr in den ST sehen könnt, bei der Zeile wo ich den Sprite zeichnen möchte.
*** Edit ***
Ich habe ein paar Änderungen in der Klasse GameView vorgenommen und nun zeichnet sich mein Sprite, jedoch wird es nicht update aktualisiert (d.h. der Sprite bleibt bei der selben Position obwohl ich die x und y Werte ändere).
Hier mal der neue Code der Klasse GameView:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class GameView extends SurfaceView implements SurfaceHolder.Callback {
private Bitmap bmp;
private GameLoopThread theGameLoopThread;
private Sprite sprite;
private boolean isCreated = false;
public GameView(Context context) {
super(context);
getHolder().addCallback(this);
theGameLoopThread = new GameLoopThread(this);
}
public GameView(Context context, AttributeSet attrSet, int defStyle) {
super(context, attrSet, defStyle);
}
public GameView(Context context, AttributeSet attrSet) {
super(context, attrSet);
}
private void createOneSprite() {
if (!isCreated) {
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.square);
sprite = new Sprite(bmp);
isCreated = true;
}
}
@Override
public void draw(Canvas canvas) {
createOneSprite();
canvas.drawColor(Color.DKGRAY);
sprite.draw(canvas);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
theGameLoopThread.setRunning(true);
theGameLoopThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
theGameLoopThread.setRunning(false);
while (retry) {
try {
theGameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
}```