启动游戏视图时,我不断收到相同的错误消息。问题似乎与stacktrace所说的游戏线程有关,但我不太确定。当我不启动游戏视图中的第二个线程时,问题似乎消失了。
W/System.err: java.lang.IllegalArgumentException: millis < 0: -84
W/System.err: at java.lang.Thread.sleep(Thread.java:346)
at java.lang.Thread.sleep(Thread.java:314)
at com.zeropointengine.popper.GameThread.run(GameThread.java:69)
E/SurfaceHolder: Exception locking surface
java.lang.IllegalArgumentException: Surface was already locked
at android.view.Surface.lockCanvas(Surface.java:328)
at android.view.SurfaceView$3.internalLockCanvas(SurfaceView.java:1120)
at android.view.SurfaceView$3.lockCanvas(SurfaceView.java:1080)
at com.zeropointengine.popper.GameThread.run(GameThread.java:44)
这是代码本身。下面的类是游戏循环
package com.zeropointengine.popper;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
/**
* Created by GhostFreak on 2018-05-05.
*/
public class GameThread extends Thread {
private GameView gv;
private SurfaceHolder surfaceHolder;
private boolean running;
private static Canvas canvas;
private int targetFPS = 30;
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
this.running = running;
}
public GameThread(SurfaceHolder surfaceHolder, GameView gv){
this.surfaceHolder = surfaceHolder;
this.gv = gv;
}
@Override
public void run(){
long startTime;
long time;
long fps;
while(running){
startTime = System.nanoTime();
canvas = null;
try{
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder){
if(canvas != null){
this.gv.update();
this.gv.draw(canvas);
}
}
}catch(Exception e){
e.printStackTrace();
}finally {
if(canvas != null){
try{
surfaceHolder.unlockCanvasAndPost(canvas);
}catch(Exception e){
e.printStackTrace();
}
}
}
time = (System.nanoTime() - startTime)/ 1000000;
fps = targetFPS - time;
try{
this.sleep(fps);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
游戏视图
package com.zeropointengine.popper;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
/**
* Created by GhostFreak on 2018-05-05.
*/
public class GameView extends SurfaceView implements SurfaceHolder.Callback, Runnable, View.OnTouchListener {
GameActivity gActivity;
GameThread thread;
Thread spawn;
Bitmap scaled;
Random random;
Rect screen;
int height;
int width;
int ranX;
int score = 0;
boolean running;
List<Bubble> bubbles = new ArrayList<>();
Context context;
public GameView(Activity activity, Context context) {
super(activity);
gActivity = (GameActivity) activity;
this.setZOrderOnTop(true);
this.getHolder().addCallback(this);
this.context = context;
setOnTouchListener(this);
thread = new GameThread(this.getHolder(), this);
spawn = new Thread(this);
screen = new Rect(0, 0, width, height);
setFocusable(true);
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GameView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
bm.recycle();
return resizedBitmap;
}
@Override
public void onDraw(Canvas canvas){
super.onDraw(canvas);
Typeface font = Typeface.createFromAsset(context.getAssets(), "fonts/Delicious.ttf");
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
if(canvas != null){
canvas.drawRGB(8, 8, 8);
paint.setTypeface(font);
paint.setTextSize(112);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("Score: " + score, width/2, 90, paint);
drawBubble(canvas, paint);
}
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
thread.setRunning(true);
running = true;
thread.start();
spawn.start();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
restart();
}
public void update(){
updateBubble();
}
@Override
public void run() {
random = new Random();
try{
Thread.sleep(1000);
while(running){
ranX = random.nextInt((width-200));
addBubble(new Bubble(getResizedBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.bubble_white), 200, 200) , ranX, height, this));
Thread.sleep(3000);
}
}catch(Exception e){
System.out.println("You got an error mate:\n"+ e.getMessage());
e.printStackTrace();
}
}
public void addBubble(Bubble bubble){
bubbles.add(bubble);
}
public void removeBubble(Bubble bubble){
Iterator <Bubble> it = bubbles.iterator();
while(it.hasNext()){
Bubble bub = it.next();
//your stuff
it.remove();
}
}
public void drawBubble(Canvas canvas, Paint paint){
for(Bubble bubble: bubbles){
bubble.draw(canvas, paint);
}
}
public void updateBubble(){
for(Bubble bubble : bubbles){
bubble.update();
}
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
for(Bubble bubble: bubbles){
if(bubble.bounds.intersect((int) motionEvent.getX()-50, (int) motionEvent.getY()-50,(int) motionEvent.getX()-50 , (int) motionEvent.getY()-50)){
if(bubble.poppable){
bubble.popped();
}
}
}
if(screen.intersect((int) motionEvent.getX(), (int) motionEvent.getY(), (int) motionEvent.getX(), (int) motionEvent.getY())){
System.out.println("Screen clicked");
}
return true;
}
public void restart(){
score = 0;
boolean retry = true;
thread.setRunning(false);
running = false;
while(retry){
try{
thread.join();
spawn.join();
retry = false;
}catch(Exception e){
e.printStackTrace();
}
}
}
}
任何其他建议,我们将不胜感激。我仍然是android的初学者。