Exception: Concurrent modification during iteratio

2020-03-12 01:56发布

问题:

I make game. In //ERROR ZONE is called Exception. I don't understand it. Class game has List recrangles.

void spawnt(){
var rnd = new Random();
var rnd2 = new Random();
rnd = rnd.nextInt(100);
if(rnd2.nextBool())
  rnd2 = rnd2.nextInt(100);
else
  rnd2 = -rnd2.nextInt(100);
var x = flappy.position["x"]+lastx+sw+rnd;
var y = rnd2*pomer-100-1800*pomer-168*pomer;
Rectangle vrch = new Rectangle("img/tube1.png", sw, sh, {"x":x, "y":y, "z":0});
Rectangle spodek = new Rectangle("img/tube2.png", sw, sh, {"x":x, "y":sh+mezeray*pomer+y, "z":0});

vrch.onCollision((_){
  checkover();
});

spodek.onCollision((_){
  checkover();
});
game.addObject(spodek);
game.addObject(vrch);
var cp = new Checkpoint(sw, mezeray, {"x":x+sw, "y":y+sh, "z":0});
cp.onCollision((e){
  scoore++;
  querySelector("#scoore").text="SCOORE: ${scoore}";
  sounds[1].play();
  //THIS IS ERROR ZONE
  spawnt();
});
game.addObject(cp);

rnd = new Random();
rnd = rnd.nextInt(300);
rnd2 = new Random();
rnd2 = rnd2.nextInt(300);
var rnd3 = new Random();
rnd3 = new Random();
rnd3 = rnd3.nextInt(10);
Grab w;
if(rnd3 == 0 || rnd3 == 1 || rnd3 == 2){
  w = new Grab("img/cigarette.png", 600*pomer, 418*pomer, {"x":x+sw+rnd,"y":sh+mezeray*pomer+y-mezeray*pomer+rnd2-168*pomer, "z":0});
  w.scale(0.2);
  w.onCollision((c){
    smokescreen = true;
    smoketimer.cancel();
    smoketimer = new Timer(const Duration(milliseconds: 10000), (){
      smokescreen = false;
    });
    kucky.play();
    if(csong)
      cig.play();
    csong = false;
  });
  game.addObject(w);
}
else if(rnd3 == 3 || rnd3 == 4){
  w = new Grab("img/whiskey.png", 162*pomer, 398*pomer, {"x":x+sw+rnd,"y":sh+mezeray*pomer+y-mezeray*pomer+rnd2-168*pomer, "z":0});
  w.scale(0.2);
  w.onCollision((c){
    AudioElement pr = new AudioElement("sounds/yes.${koncovka}");
    pr.play();
    whiskey++;
    if(whiskey>=10 && whiskey<20){
      speedotoceni = 30;
      zhoupni();
    }
    else if(whiskey>=20 && whiskey<30){
      speedotoceni = 25;
      zhoupni();
    }
    else if(whiskey>=30 && whiskey<40){
      speedotoceni = 20;
      zhoupni();
    }
    else if(whiskey>=40 && whiskey<50){
      speedotoceni = 15;
      zhoupni();
    }
    else if(whiskey>=50 && whiskey<60){
     speedotoceni = 10;
      zhoupni();
    }
    else if(whiskey>=60 && whiskey<70){
      speedotoceni = 5;
      zhoupni();
    }
    else if(whiskey>=70 && whiskey<80){
      speedotoceni = 1;
      zhoupni();
    }
    querySelector("#scoore").text="SCOORE: ${scoore}";
  });
  game.addObject(w);
}
else if(rnd3 == 9){
  w = new Grab("img/jatra.png", 539*pomer, 521*pomer, {"x":x+sw+rnd,"y":sh+mezeray*pomer+y-mezeray*pomer+rnd2-168*pomer, "z":0});
  w.scale(0.1);
  w.onCollision((c){
    AudioElement pr = new AudioElement("sounds/yes.${koncovka}");
    pr.play();
    jatra++;
    document.cookie = "jatra=${jatra}; expires=Thu, 24 Dec 4000 00:00:00 GMT; path=/";
    querySelector("#jatracount").text = jatra.toString();
  });
  game.addObject(w);
 }
lastx = lastx+300*pomer+rnd;
}

class Game.dart

  import 'dart:html';
  import 'dart:math';
  import 'dart:async';
  import 'Entity.dart';
  import 'Gravity.dart';
  import 'Rectangle.dart';
  import 'Camera.dart';
  import 'Checkpoint.dart';

  class Game {
    CanvasElement canvas;
    Gravity gravity;
    List<Entity> entities = new List();
    List<Rectangle> rectangles = new List();
    Camera camera;
    var leftSpace = 0;
    var topSpace = 0;
    var _onCollision;
    var _over = (_){};
    var _render = (_){};
    num _lastFrame = 0;
    bool isOver = false;


Game(this.canvas, this.gravity){
  window.animationFrame.then((e){this.render(e);});
}

void addEntity(Entity entita){
  this.entities.add(entita);
}

void addObject(Rectangle rectangle){
  this.rectangles.add(rectangle);
}

void render(num delta){
  num fps = 1000/(delta-this._lastFrame);
  this._lastFrame = delta;
  CanvasRenderingContext2D ctx = this.canvas.context2D;
  ctx.clearRect(0, 0, this.canvas.width+this.leftSpace.abs(), this.canvas.height+this.topSpace.abs());
  this._render(true);
  this.rectangles.forEach((s){
    ctx.fillStyle=s.color;
    if(s.hasColor()){
      ctx.fillStyle=s.color;
      ctx.fillRect(s.position["x"]-this.leftSpace,s.position["y"]-this.topSpace,s.width,s.height);
    }
    else{
      ctx.drawImageScaled(s.texture, s.position["x"]-this.leftSpace,s.position["y"]-this.topSpace,s.width,s.height);
    }
  });
  this.entities.forEach((e){
    e.move(fps);
    e.power["y"] += this.gravity.operate(e)*(60/fps);
    ctx.save(); 
    ctx.translate(e.position["x"]-this.leftSpace+e.width/2, e.position["y"]-this.topSpace+e.height/2);
    ctx.rotate(e.rotation* PI/180);
    ctx.drawImageScaled(e.img, -(e.width/2), -(e.height/2), e.width, e.height);
    ctx.restore(); 
  });
  collisionResponse();
  checkCollisions();
  if(!this.camera.fixed["x"])
    this.leftSpace = this.camera.target.position["x"]-this.canvas.width/2+this.camera.target.width/2;
  else
    this.leftSpace = this.camera.fixedPos["x"];

  if(!this.camera.fixed["y"])
    this.topSpace = this.camera.target.position["y"]-this.canvas.height/2+this.camera.target.height/2;
  else
    this.topSpace = this.camera.fixedPos["y"];
  this._render(false);
  ctx.closePath();
  window.animationFrame.then((e){this.render(e);});
}

void onCollision(e){
  this._onCollision = e;
}

void collisionResponse(){
  this.rectangles.forEach((s){
    num x1 = s.position["x"];
    num y1 = s.position["y"];
    num z1 = s.position["z"];
    num w1 = s.width;
    num h1 = s.height;

    this.entities.forEach((e){
      num rot = e.rotation * (PI / 180);
      num x2 = e.position["x"];
      num y2 = e.position["y"];
      num z2 = e.position["z"];
      num w2 = e.width;
      num h2 = e.height;
      if(x2>=x1-w2 && x2<=x1+w1 && y2>y1-h2 && y2<y1+h1 && z1==z2){
        s.collisionResponse(e);
        e.collision(s);
        s.collision(e);
      }
    });
  });
}

void checkCollisions(){
  List<Entity> kolize = new List();
  for(Entity e1 in this.entities){
    num x1 = e1.position["x"];
    num y1 = e1.position["y"];
    num z1 = e1.position["z"];
    num w1 = e1.width;
    num h1 = e1.height;

    for(Entity e2 in this.entities){
      if(e1 == e2 || (kolize.indexOf(e1) != -1 && kolize.indexOf(e2) != -1)) continue;
      num x2 = e2.position["x"];
      num y2 = e2.position["y"];
      num z2 = e2.position["z"];
      num w2 = e2.width;
      num h2 = e2.height;
      if(x2>=x1-w2 && x2<=x1+w1 && y2>y1-h2 && y2<y1+h1 && z1==z2){
        kolize.add(e1);
        kolize.add(e2);
      }
    }
  }
}

void over(){
  if(!this.isOver)
    this._over();
  this.isOver = true;
}

void onOver(e){
  this._over = e;
}

void onRender(f){
  this._render = f;
}
}

Uncaught Error: Concurrent modification during iteration: Instance(length:17) of '_GrowableList'. Stack Trace: #0 List.forEach (dart:core-patch/growable_array.dart:241)

#1 Game.collisionResponse (FlappyBird/web/classes/Game.dart:83:28)

#2 Game.render (FlappyBird/web/classes/Game.dart:62:22)

#3 Game.render. (FlappyBird/web/classes/Game.dart:75:47)

#4 _rootRunUnary (dart:async/zone.dart:717)

#5 _RootZone.runUnary (dart:async/zone.dart:854)

#6 _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:439)

#7 _Future._propagateToListeners (dart:async/future_impl.dart:522)

#8 _Future._complete (dart:async/future_impl.dart:303)

#9 _SyncCompleter.complete (dart:async/future_impl.dart:44)

#10 Window.animationFrame. (file:///E:/b/build/slave/dartium-win-full-stable/build/src/build/Release/obj/global_intermediate/blink/bindings/dart/dart/html/Window.dart:62)

Exception: Concurrent modification during iteration: Instance(length:17) of '_GrowableList'. undefined (undefined:0:0)

Is it enough? Does somebody know how to repair it? Thanks for answer. :)

回答1:

This error means that you are adding or removing objects from a collection during iteration. This is not allowed since adding or removing items will change the collection size and mess up subsequent iteration.

The error is likely from one of these lines which you haven't posted the source for:

 s.collisionResponse(e);
 e.collision(s);
 s.collision(e);

I assume one of these calls is removing an item from either the entities list or the rectangles list, during the forEach, which is not allowed. Instead you must restructure the code to remove the items outside of the list iteration, perhaps using the removeWhere method.

Consider the following attempt to remove odd numbers from a list:

var list = [1, 2, 3, 4, 5];
list.forEach( (e) {
 if(e % 2 == 1) 
   list.remove(e);
});

This will fail with a concurrent modification exception since we attempt to remove the items during the list iteration.

However, during the list iteration we can mark items for removal and then remove them in a bulk operation with removeWhere:

var list = [1, 2, 3, 4, 5];
var toRemove = [];

list.forEach( (e) {
 if(e % 2 == 1) 
   toRemove.add(e);
});

list.removeWhere( (e) => toRemove.contains(e));


回答2:

New documentation on latest Dart release 2.1.0 from https://api.dartlang.org/stable/2.1.0/dart-core/Map/removeWhere.html

Implementation

Map.removeWhere((key, value) => toRemove.contains(key));