我尝试了一个小项目" 。它基本上是一种生存游戏。使用W,A,S,D移动,使用箭头键向不同方向拍摄。你基本上必须尽可能长久地生存。敌人跟着你,他们会在命中时冻结并在大约3秒后再次开始移动。
代码如下(执行"窗口"类)
窗口级
package TestGame;
import java.awt.Graphics;
public class Window extends GameIntern{
public void init(){
setSize(windowX,windowY);
Thread th = new Thread(this);
th.start();
offscreen = createImage(windowX,windowY);
d = offscreen.getGraphics();
addKeyListener(this);
}
public void paint(Graphics g){
d.clearRect(0,0,windowX,windowY);//clear window
d.drawString(numberEnemies.toString(), 10, 10);//"Score" number of enemies displayed
d.drawRect(x, y, playerWidth, playerHeight);//draw player
for(Enemy e : enemies){//draw all enemies
d.drawRect(e.getx(), e.gety(), playerWidth, playerHeight);
}
for(Bullet b : bullets){//draw all bullets
d.drawOval(b.getx(), b.gety(), bulletSize, bulletSize);
}
g.drawImage(offscreen,0,0,this);
}
public void update(Graphics g){
paint(g);
}
}
GameIntern级
package TestGame;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
public class GameIntern extends Applet implements Runnable , KeyListener {
public int windowX = 854;//size of the window in x direction
public int windowY = 460;//size of the window in y direction
public static int x;//x-coordinate of player
public static int y;//y-coordinate of player
public int playerpositionX = x;
public int playerpositionY = y;
public int playerHeight = 20;//player height
public int playerWidth = 20;//player width
public int playerSpeed = 3;//pixel per frame
public int bulletSize = 5;//diameter of bullets
public int spawnTime = 4;//time for new enemies to spawn in seconds
public int enemySleepTime = 180;//Time an enemy does nothing in Frames per second (180 in 60fps = 3sec)
public boolean alive = true;
public Image offscreen;
public Graphics d;
public boolean up,down,left,right;
private int delay;
private Random random= new Random();
public Integer numberEnemies = new Integer(enemies.size());
protected static ArrayList<Enemy> enemies = new ArrayList<Enemy>(); //List of all enemies
protected static ArrayList<Bullet> bullets = new ArrayList<Bullet>();//List of all bullets
protected static ArrayList<PowerUps> pUps = new ArrayList<PowerUps>();//List of all powerUps
public void run() {
this.x = 400;//startingposition x
this.y = 240;//startingposition y
double ns = 1000000000.0 / 60.0; //60 "frames"
double delta = 0;
long lastTime = System.nanoTime();
while (alive) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
repaint();
tick();
collisionEnemy();
// collisionPowerUp();
delta--;
}
}
}
/**
* Method to calculate all objects and their positions per frame
*/
private void tick() {
if(left == true){
if(x>=0 + playerSpeed){
x-=playerSpeed;
}else{ x=0;}//Farthest left x-coordinate
repaint();
}
if(right == true){
if(x<=windowX - playerWidth - playerSpeed){
x+=playerSpeed;
}else{ x=windowX - playerWidth;}//Farthest right x-coordinate
repaint();
}
if(up == true){
if(y>=0 + playerSpeed){
y-=playerSpeed;
}else{ y=0;}//Highest y-coordinate
repaint();
}
if(down == true){
if(y<=windowY - playerHeight - playerSpeed){
y+=playerSpeed;
}else{y=windowY - playerHeight;}//Lowest y-coordinate
repaint();
}
for (Enemy e : enemies) { //Tick every enemy
e.tick();
}
for (Bullet b : bullets){ //Tick every bullet
b.tick();
}
if(delay % (60 * spawnTime) == 0){ //Spawn enemy
enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
numberEnemies++;
}
delay++;
for(Enemy e : enemies){ //collision : enemy & bullet
for(Bullet b : bullets){
if(b.getx()+bulletSize >= e.getx() && b.getx() <= e.getx()+20){
if(b.gety()+bulletSize >= e.gety() && b.gety() <= e.gety()+20){
e.setHit();
b.setRemove();
}
}
}
}
for(int i = 0; i< bullets.size(); i++){ //Remove bullets from ArrayList
if(bullets.get(i).remove){
bullets.remove(i);
}
}
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 65){//W
left=true;
}
if(e.getKeyCode() == 87){//A
up=true;
}
if(e.getKeyCode() == 68){//S
right=true;
}
if(e.getKeyCode() == 83){//D
down=true;
}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == 65){//Arrowkey left
left=false;
}
if(e.getKeyCode() == 87){//Arrowkey up
up=false;
}
if(e.getKeyCode() == 68){//Arrowkey right
right=false;
}
if(e.getKeyCode() == 83){//Arrowkey dowm
down=false;
}
if(e.getKeyCode() == 37){//Arrowkey left
bullets.add(new Bullet(x,y,false,false,true,false)); //Direction the bullet has to go
}
if(e.getKeyCode() == 38){//Arrowkey up
bullets.add(new Bullet(x,y,true,false,false,false));//Direction the bullet has to go
}
if(e.getKeyCode() == 39){//Arrowkey right
bullets.add(new Bullet(x,y,false,false,false,true));//Direction the bullet has to go
}
if(e.getKeyCode() == 40){//Arrowkey down
bullets.add(new Bullet(x,y,false,true,false,false));//Direction the bullet has to go
}
}
public void keyTyped(KeyEvent e){}
/**
* Method to see if the player collided with an enemy
*/
public void collisionEnemy(){
for(Enemy e : enemies){
for(int i = 0;i <= playerWidth; i++){
if(GameIntern.x+i >= e.getx() && GameIntern.x+i <= e.getx()+playerWidth){
if(GameIntern.y+i >= e.gety() && GameIntern.y+i <= e.gety()+playerHeight){
alive = false;
}
}
}
}
}
// public void addEnemy(){
// enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
//
// //Spawn enemies inside the filed, not outside the boarder
// if (playerpositionX < playerWidth * 2 || playerpositionX * 2 > windowX - 2*playerWidth || playerpositionY * 2 > windowY - 2*playerHeight || playerpositionY < playerHeight * 2){
// enemies.add(new Enemy(random.nextInt(windowX - 3*playerWidth), random.nextInt(windowY - 3*playerHeight)+3*playerHeight));
// }else {
// int temp1 = random.nextInt(windowX-3*playerWidth);
// if (temp < playerpositionX){
//
// }
// enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
// }
//
// }
}
子弹级
package TestGame;
public class Bullet extends GameIntern{
public int x,y;
public boolean up,down,left,right;
public boolean remove;
public Bullet(int x, int y,boolean up,boolean down, boolean left, boolean right){
this.x = x + 8;
this.y = y + 8;
this.up = up;
this.down = down;
this.left = left;
this.right = right;
}
public int getx(){
return this.x;
}
public int gety(){
return this.y;
}
public void setRemove(){
remove=true;
}
public void tick() {
if (up == true) y-=2;
if (down == true) y+=2;
if (left == true) x-=2;
if (right == true) x+=2;
if(x < 0){
remove = true;
}
if(x > 840){
remove = true;
}
if(y < 0){
remove = true;
}
if(y > 470){
remove = true;
}
}
}
敌人级
package TestGame;
public class Enemy extends GameIntern {
public int x,y;
public boolean hit = false;
public int counter = 0;
public Enemy(int x, int y) {
this.x = x;
this.y = y;
}
public int getx(){
return this.x;
}
public int gety(){
return this.y;
}
public void setHit(){
hit = true;
counter = enemySleepTime;
}
public void tick() {
if(counter == 0){
if(hit == true){
hit=false;
}
if (x < GameIntern.x) x++;
if (x > GameIntern.x) x--;
if (y < GameIntern.y) y++;
if (y > GameIntern.y) y--;
}else {counter--;}
}
}
玩了一会儿后我得到了
java.util.ConcurrentModificationException
这是什么意思?
另外,我努力改善敌人的产卵进程。现在它有时会发生,敌人在玩家内部产生。我希望在玩家周围有一个假想的盒子,敌人不会在里面产生,敌人应该总是在窗口内产卵。
如果您有任何疑问,请随时问:)
真诚 尤
答案 0 :(得分:1)
来自JavaDocs:
此类的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除非通过迭代器自己的删除或者添加方法,迭代器将抛出一个ConcurrentModificationException。
问题可能是因为您在尝试在单独的线程中绘制项目时从ArrayList
删除项目符号。问题是两个线程同时在bullets
列表上进行迭代。
//The following for loop is likely the cause
for(int i = 0; i< bullets.size(); i++){
if(bullets.get(i).remove){
bullets.remove(i); // <-- this is the problem
}
}
相反,请尝试使用线程安全的实现,例如
protected static List<Enemy> enemies =
Collections.synchronizedList(new ArrayList<Enemy>()); //List of all enemies
protected static List<Bullet> bullets =
Collections.synchronizedList(new ArrayList<Bullet>());//List of all bullets
此外,您应该更改删除代码以避免IndexOutOfBoundsException
:
LinkedList<Bullet> bulletsToRemove = new LinkedList<>();
for(Enemy e : enemies){ //collision : enemy & bullet
for(Bullet b : bullets){
if(b.getx()+bulletSize >= e.getx() && b.getx() <= e.getx()+20){
if(b.gety()+bulletSize >= e.gety() && b.gety() <= e.gety()+20){
e.setHit();
bulletsToRemove.add(b);
}
}
}
}
for(Bullet b : bulletsToRemove){ //Remove bullets from ArrayList
bullets.remove(b);
}
关于产生过程,一个简单的方法是定义与玩家的最小距离,称之为minDist
。现在只需在屏幕上的任意位置选择一个随机位置,将其称为p1
。如果p1
距离播放器小于minDist
,请选择一个新的随机位置。只要玩家和敌人的精灵与屏幕区域相比相对较小,这种方法应该可以很好地运作。