gpt4 book ai didi

android - 使用 Sprite 数组列表时出现并发错误

转载 作者:搜寻专家 更新时间:2023-11-01 07:38:09 24 4
gpt4 key购买 nike

目前,我正在详细研究游戏开发,并创建了(在一些在线教程的帮助下)以下示例游戏。目标是触摸屏幕上的 Sprite 并杀死它们(即它们从屏幕上移除)。截图如下

screenshot

当我杀死他们中的一些人时,我得到以下异常

E/AndroidRuntime(  277): FATAL EXCEPTION: Thread-8
E/AndroidRuntime( 277): java.util.ConcurrentModificationException
E/AndroidRuntime( 277): at java.util.ArrayList$ArrayListIterator.next(ArrayList.java:573)
E/AndroidRuntime( 277): at cz.trada.gd101.GameView.draw(GameView.java:65)
E/AndroidRuntime( 277): at cz.trada.gd101.GameLoopThread.run(GameLoopThread.java:32)

源代码如下所示。不幸的是,我不知道如何在 SO 上突出显示确切的代码行,所以我在它们前面添加了以下注释://ERROR COMING因此,您可以轻松找到这些行。

请帮助我了解并发错误的原因并找到解决方案。

附言游戏中使用的图片资源my_sprite_girlmy_sprite_boy附在文末。

主.java

package cz.trada.gd101;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;

public class Main extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new GameView(this));
}
}

GameView.java

package cz.trada.gd101;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class GameView extends SurfaceView {
private static final String TAG = "GameView";
SurfaceHolder holder;

GameLoopThread gameLoopThread;
List<Sprite> sprites = new ArrayList<Sprite>();

long lastClick;

public GameView(Context context) {
super(context);

gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new Callback() {

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry) {
try {
gameLoopThread.join();
retry = false;
} catch (InterruptedException e) {
Log.d(TAG, e.getMessage());
}
}
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
});

}

@Override
public void draw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
for (Sprite sprite : sprites) {
//ERROR COMING
sprite.draw(canvas);
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 500) {
lastClick = System.currentTimeMillis();
float x = event.getX();
float y = event.getY();
synchronized (getHolder()) {
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
if (sprite.isCollision(x, y)) {
sprites.remove(sprite);
break;
}
}
}
}
return true;
}

private void createSprites() {
for (int i = 0; i < 10; i++) {
sprites.add(createSprite(R.drawable.my_sprite_girl));
sprites.add(createSprite(R.drawable.my_sprite_boy));
}
}

private Sprite createSprite(int resource) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
return new Sprite(this, bmp);
}
}

GameLoopThread.java

package cz.trada.gd101;
import android.graphics.Canvas;
import android.util.Log;

public class GameLoopThread extends Thread {
private static final String TAG = "GameLoopThread";
private static final int FPS = 10;

private GameView view;
private boolean running = false;

public GameLoopThread(GameView view) {
this.view = view;
}

public void setRunning(boolean run) {
running = run;
}

@Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHandler()) {
//ERROR COMING
view.draw(c);
}
}
finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}

sleepTime = ticksPS - (System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
}
}
}

资源

my_sprite_girl my_sprite_boy

最佳答案

您的错误可能是由于在 onTouchEvent() 中调用 remove()draw() 中的循环正在迭代 Sprite 。

如果您的 Sprite 类已经有 equals()hashCode() (或者您添加它们),您可以使用 ConcurrentSkipListSet相反,它在 log(n) 中为您提供了无锁的 containsremoveadd 操作。

CopyOnWriteArrayList也可能会解决问题,但性能不是很好(由于写时复制部分)。

作为样式说明,您还可以在 onTouchEvent() 循环中使用 Iterator 及其 remove() 方法:

Iterator<Sprite> it = sprites.iterator();
while (it.hasNext()) {
Sprite sprite = sprites.next();
if (sprite.isCollision(x, y)) {
it.remove();
break;
}
}

关于android - 使用 Sprite 数组列表时出现并发错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7840563/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com