I'm building a web-app using Two.js which generates shapes and then removes them again after their lifespan is up.
When making the shapes I push them into a new array which I then loop through every frame to check if the lifespan is up. If it is then the shape is removed and spliced from the array.
This works 99% of the time, but sometimes a shape does not get removed from the stage, even though it gets removed from the array. So it gets stuck and there is no reference to it so I can't remove it.
Also if I remove the 'if shape' check in the loop I get this error a lot: Uncaught TypeError: Cannot read property 'creationTime' of undefined which I'm sure means something is not right.
onPeak: (col) =>
circle = @_two.makeCircle @_two.width, @_two.height, @_two.height*0.75
circle.fill = col
circle.lifeSpan = Math.floor @convertToRange(@_bpm, [60,600], [1000, 400])
circle.creationTime = new Date().getTime()
circle.noStroke()
@_shapes.push circle
onTwoUpdate: () =>
if @_shapes.length >= 1
@removeShapes()
removeShapes: () =>
time = new Date().getTime()
for shape in @_shapes
if shape and time - shape.creationTime >= shape.lifeSpan
shape.remove()
@_shapes.splice shape.index, 1
You're removing things from
@_shapes
while you're looping over it. Consider a simplified example:That will give you this in the console:
Demo: http://jsfiddle.net/ambiguous/9fsYL/
You'll notice that things start out fine but as soon as you
splice
the array to remove an element, everything falls apart in a pile of nonsense. Theundefined
s appear in the console because the loop caches the array's length (which changes when remove things) so you end up running off the end of the array.When you
@_shapes.splice shape.index, 1
, you shift everything aftershape.index
towards the beginning of the array but yourfor
loop doesn't know that. The result is that you've removed the desired element and the loop won't see the next element.A common solution to this problem is to iterate backwards. That way, when you remove something, you only affect the positions of things that you've already seen. For example, if you change the above loop to:
then you'll get something sensible in the console:
Demo: http://jsfiddle.net/ambiguous/Yngk8/
In your case, saying:
should fix the problem.