How can repair this error? "java.lang.IndexOutOfBoundsException" - java

I'm trying to do a game with andengine library.
When the Sprite Enemy1Sprite reach the top of the camera, and I detach it, this exception is thrown :
java.lang.IndexOutOfBoundsException Invalid Index 12 size is 12
I have to detach the enemy1Sprite because it keep creating Sprites of bullets out of the camera.
This is the code.
Class enemy1 :
package es.uah.juegomentos;
import org.anddev.andengine.engine.handler.timer.ITimerCallback;
import org.anddev.andengine.engine.handler.timer.TimerHandler;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.opengl.texture.region.TextureRegion;
public class Enemy1 extends Sprite {
boolean abajo = true;
public Enemy1(TextureRegion pTextureRegion) {
super(0, 0, pTextureRegion);
this.setPosition(JuegoMentosActivity.RANDOM.nextInt(JuegoMentosActivity.CAMERA_WIDTH), -10);
TimerHandler Enemy1fire = new TimerHandler(0.75f, true, enemigo1fireCallback);
JuegoMentosActivity.getmGameScene().registerUpdateHandler(Enemy1fire);
}
#Override
protected void onManagedUpdate(float pSecondsElapsed) {
super.onManagedUpdate(pSecondsElapsed);
float y = getY();
if (y >= 275) {abajo = false;}
if (abajo) {y = y + pSecondsElapsed * 125.0f;}
else {y = y - pSecondsElapsed * 125.0f;}
this.setPosition(getX(), y);
if (getY()<-10){this.getParent().detachChild(this);}
}
ITimerCallback enemigo1fireCallback = new ITimerCallback(){
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
bala1 mbala1;
mbala1 = new bala1(getX()+(64*1/2),getY()+64,JuegoMentosActivity.getMbala1Texture().getTextureRegion(),true);
JuegoMentosActivity.getmGameScene().attachChild(mbala1);
}
};
}
Create new enemy in the scene :
//Creamos el sprite del enemigo uno
ITimerCallback enemigo1CreatorCallback = new ITimerCallback(){
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
mEnemy1Sprite = new Enemy1(mEnemy1Texture.getTextureRegion());
mGameScene.attachChild(mEnemy1Sprite);
}
};
TimerHandler Enemy1Creator = new TimerHandler(3.0f, true, enemigo1CreatorCallback);
mGameScene.registerUpdateHandler(Enemy1Creator);
Thanks

You've answered your own question really - Marcelo is correct, the issue is not in the code you posted, it's where you are doing the detachChild call - you need to call that on the Update Thread, as in
runOnUpdateThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
yourScene.detachChild(yourEnemySprite);
}
});

This says that your actual array size is 12 so your last index is 11. But you are trying to access index 12 which does not exist. Try to find out the line which throws this error. Make a condition there that if size of index is >= size of array brake.
Also you may try using try{}catch(IndexOutOfBondException e){} and continue the process.

detach entity in onManagedUpdate of scene.

Related

How do you solve lagging in Java awt/swing image printing?

I am trying to make a simple game with Java swing/awt.
I am have issue with lagging while printing and moving images on the screen.
Here is my code below:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.File;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.*;
public class StarDef extends JFrame implements Runnable, KeyListener{
private BufferedImage back;
private boolean start = false, end = false;
public int w = 1500, h = 800, commandx = 200, commandy = 100, ground = 500, mineral = 100;
private int mineralx = 0, mineraly = commandy + 104;
private int dronecnt = 0;
private ArrayList<Drone> DrList = null;
private ArrayList<Enemy> EnList = null;
private ArrayList<Building> BuildList = null;
private ArrayList<Allies> AlyList= null;
public Image imagearr[] = new Image[10];
private boolean makedrone = false, NeedMinerals = false;
public int picnum = 1;
private int OrderBuild = 0;
public static void main(String[] args){
Thread t = new Thread(new StarDef());
t.start();
}
public StarDef(){
back = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
DrList = new ArrayList<>();
BuildList = new ArrayList<>();
EnList = new ArrayList<>();
AlyList = new ArrayList<>();
this.addKeyListener(this);
this.setSize(w,h);
this.setTitle("Starcraft");
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
try {
imagearr[0] = ImageIO.read(new File("Char/Command.png"));
imagearr[1] = ImageIO.read(new File("Char/droneleft.png"));
imagearr[2] = ImageIO.read(new File("Char/droneright.png"));
imagearr[3] = ImageIO.read(new File("Char/Mineral.png"));
imagearr[4] = ImageIO.read(new File("Char/barracks.png"));
} catch (Exception e){
e.printStackTrace();
}
}
public void initGame(){
DrList.clear();
mineral = 100;
}
public void draw(){
Graphics gs = back.getGraphics();
gs.setColor(Color.white);
gs.fillRect(0,0,w,h);
gs.setColor(Color.DARK_GRAY);
gs.fillRect(0,ground,w,200);
if (!end) {
gs.drawImage(imagearr[0], commandx, commandy, null); // First Image-Command Center
gs.drawImage(imagearr[3], mineralx,mineraly,null); // Second Image-Mineral
for (int i = 0; i < DrList.size(); i++) { //Printing Drones
Drone m = DrList.get(i);
gs.drawImage(imagearr[m.state], m.x, m.y, null); //Drawing Drones
m.moveDr(); // Moving the Drone
}
for (int i = 0; i < BuildList.size(); i++){ //Printing Building
Building bd = BuildList.get(i);
if(bd.buildingtype == 'R'){
gs.drawImage(imagearr[4], bd.x, bd.y, null); // Drawing Building-Problem starts..?
}
}
gs.drawImage(imagearr[0], commandx, commandy, null);
}
gs.setColor(Color.black);
gs.drawString("mineral : " + mineral, 10,50);
gs.drawString("Drones : " + DrList.size(), 10, 70);
Graphics ge = this.getGraphics();
ge.drawImage(back, 0,0,w,h,this);
}
public void run(){
try{
int timer = 10;
while (true){
Thread.sleep(timer);
if(start){
if (makedrone) {
makedrone();
}
if (OrderBuild>0){
makeBuilding(OrderBuild);
}
}
draw();
}
} catch (Exception e){
e.printStackTrace();
}
}
public void makeBuilding(int buildingnumber){
int bdx, bdy;
char BuildingType;
if(buildingnumber == 1){
bdx = 500;
bdy = 100;
BuildingType = 'R';
Building barracks = new Building(this, bdx, bdy, BuildingType);
BuildList.add(barracks);
}
}
public void makedrone() {
if (mineral >= 50) {
int dronex = commandx;
int droney = commandy+129;
Drone dr = new Drone(this ,dronex, droney);
DrList.add(dr);
dronecnt++;
mineral -= 50;
makedrone = false;
} else if (mineral < 50) {
NeedMinerals = true;
makedrone = false;
}
}
public void keyPressed(KeyEvent ke){
switch (ke.getKeyCode()){
case KeyEvent.VK_ENTER:
start = true;
end = false;
break;
case KeyEvent.VK_D:
makedrone = true;
break;
case KeyEvent.VK_R:
OrderBuild = 1;
break;
}
}
public void keyReleased(KeyEvent ke){
switch ((ke.getKeyCode())){
}
}
public void keyTyped(KeyEvent ke) {
}
}
When you compile the code, the first few stationary images appear fine.
After moving images(Drones) appear nicely, but when you summon the next stationary image(Building), heavy lag starts to appear and the speed of the moving drones decrease visibly.
The building is about 300*150 pixels and the drones are 40*30 pixels.
What is the cause of this problem? Is this because of the code(the way of summoning the image), or the picture's size, or the computer(I am using a notebook(LG Gram 14in)).?
Start by not using Graphics ge = this.getGraphics();.
Because you're also using your own Thread, you're running the risk of thread race conditions which could result in dirty reads/ paints.
Start by understanding how Swing painting actually works and work within the API functionality.
Start by having a look at Performing Custom Painting, Painting in AWT and Swing and Concurrency in Swing
KeyListener is also a poor choice for monitor key input and you should be using the Key Bindings API - see How to use key bindings for more details.
Adding content to the ArrayList can cause the ArrayList to go through a growth cycle, which can consume time and force a longer GC cycle. Consider seeding the ArrayList with initial capacity, it will help reduce the interval between growth cycles.
Focus on separating the "update" logic from the "paint" logic, it can help you find performance issues
You could also have a look at
java what is heavier: Canvas or paintComponent()?
Swing animation running extremely slow
Rotating multiple images causing flickering. Java Graphics2D
Which demonstrate a verity of techniques for improving performance of rendering in Swing.
If these still are't getting your to the level you want, then you will want to explore using a BufferStrategy
Better draw in JPanel and use repaint() method to update your JPanel

Swing animation flickers and makes GUI slow to respond

I'm trying to write a simple program: a bouncing ball that appears and starts bouncing after you press the "Start" button on the screen. The program should be closed by pressing "X".
For some reason, it runs very slowly. The ball is blinking, and I have to wait for a long time after I press the "X" for program to close.
Here is the code:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class Bounce
{
public static void main(String[] args)
{
JFrame frame = new BounceFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.show();
}
}
class BounceFrame extends JFrame
{
public BounceFrame()
{
setSize(WIDTH, HEIGHT);
setTitle("Bounce");
Container contentPane = getContentPane();
canvas = new BallCanvas();
contentPane.add(canvas, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
addButton(buttonPanel, "Start", new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
addBall();
}
});
contentPane.add(buttonPanel, BorderLayout.SOUTH);
}
public void addButton(Container c, String title, ActionListener listener)
{
JButton button = new JButton(title);
c.add(button);
button.addActionListener(listener);
}
public void addBall()
{
try
{
Ball b = new Ball(canvas);
canvas.add(b);
for (int i = 1; i <= 10000; i++)
{
b.move();
Thread.sleep(10);
}
}
catch (InterruptedException exception)
{
}
}
private BallCanvas canvas;
public static final int WIDTH = 300;
public static final int HEIGHT = 200;
}
class BallCanvas extends JPanel
{
public void add(Ball b)
{
balls.add(b);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for (int i = 0; i < balls.size(); i++)
{
Ball b = (Ball)balls.get(i);
b.draw(g2);
}
}
private ArrayList balls = new ArrayList();
}
class Ball
{
public Ball(Component c) { canvas = c; }
public void draw(Graphics2D g2)
{
g2.fill(new Ellipse2D.Double(x, y, XSIZE, YSIZE));
}
public void move()
{
x += dx;
y += dy;
if (x < 0)
{
x = 0;
dx = -dx;
}
if (x + XSIZE >= canvas.getWidth())
{
x = canvas.getWidth() - XSIZE;
dx = -dx;
}
if (y < 0)
{
y = 0;
dy = -dy;
}
if (y + YSIZE >= canvas.getHeight())
{
y = canvas.getHeight() - YSIZE;
dy = -dy;
}
canvas.paint(canvas.getGraphics());
}
private Component canvas;
private static final int XSIZE = 15;
private static final int YSIZE = 15;
private int x = 0;
private int y = 0;
private int dx = 2;
private int dy = 2;
}
The slowness comes from two related problems, one simple and one more complex.
Problem #1: paint vs. repaint
From the
JComponent.paint docs:
Invoked by Swing to draw components.
Applications should not invoke paint directly, but should instead use the repaint method to schedule the component for redrawing.
So the canvas.paint() line at the end of Ball.move must go.
You want to call
Component.repaint
instead...
but just replacing the paint with repaint will reveal the second problem, which prevents the ball from even appearing.
Problem #2: Animating inside the ActionListener
The ideal ActionListener.actionPerformed method changes the program's state and returns as soon as possible, using lazy methods like repaint to let Swing schedule the actual work for whenever it's most convenient.
In contrast, your program does basically everything inside the actionPerformed method, including all the animation.
Solution: A Game Loop
A much more typical structure is to start a
javax.swing.Timer
when your GUI starts, and just let it run
"forever",
updating your simulation's state every tick of the clock.
public BounceFrame()
{
// Original code here.
// Then add:
new javax.swing.Timer(
10, // Your timeout from `addBall`.
new ActionListener()
{
public void actionPerformed(final ActionEvent ae)
{
canvas.moveBalls(); // See below for this method.
}
}
).start();
}
In your case, the most important
(and completely missing)
state is the
"Have we started yet?"
bit, which can be stored as a boolean in BallCanvas.
That's the class that should do all the animating, since it also owns the canvas and all the balls.
BallCanvas gains one field, isRunning:
private boolean isRunning = false; // new field
// Added generic type to `balls` --- see below.
private java.util.List<Ball> balls = new ArrayList<Ball>();
...and a setter method:
public void setRunning(boolean state)
{
this.isRunning = state;
}
Finally, BallCanvas.moveBalls is the new
"update all the things"
method called by the Timer:
public void moveBalls()
{
if (! this.isRunning)
{
return;
}
for (final Ball b : balls)
{
// Remember, `move` no longer calls `paint`... It just
// updates some numbers.
b.move();
}
// Now that the visible state has changed, ask Swing to
// schedule repainting the panel.
repaint();
}
(Note how much simpler iterating over the balls list is now that the list has a proper generic type.
The loop in paintComponent could be made just as straightforward.)
Now the BounceFrame.addBall method is easy:
public void addBall()
{
Ball b = new Ball(canvas);
canvas.add(b);
this.canvas.setRunning(true);
}
With this setup, each press of the space bar adds another ball to the simulation.
I was able to get over 100 balls bouncing around on my 2006 desktop without a hint of flicker.
Also, I could exit the application using the 'X' button or Alt-F4, neither of which responded in the original version.
If you find yourself needing more performance
(or if you just want a better understanding of how Swing painting works),
see
"Painting in AWT and Swing:
Good Painting Code Is the Key to App Performance"
by Amy Fowler.
I would suggest you to use 'Timer' class for running your gameloop.It runs infinitely and you can stop it whenever you want using timer.stop()
You can also set its speed accordingly.

Processing, redraw on mouse click within a class

I'm trying to make a simple click to change color in class draw. I tried to print the statement to see if it would re-draw but it's not re-drawing at all. The click works. Does anybody know why this is happening?
Here's the code so far.
Monster firstmonster;
Monster secondmonster;
void setup() {
size(600,400);
firstmonster = new Monster(100,200);
secondmonster = new Monster(300,200);
firstmonster.draw();
secondmonster.draw();
noLoop();
}
class Monster {
float xpos;
float ypos;
boolean isAngry;
int timeAngry;
Monster(float x, float y) {
xpos = x;
ypos = y;
isAngry = false;
timeAngry = 0;
}
void draw() {
if(isAngry = true && timeAngry<60){
print(int(timeAngry));
timeAngry=timeAngry+1;
rectMode(CENTER);
fill(127-timeAngry*5,0,0);
rect(xpos+100,ypos+100,20,100);
fill(255,200,200);
ellipse(xpos+100,ypos+70,60,60);
ellipse(xpos+81,ypos+70,16,32);
ellipse(xpos+119,ypos+70,16,32);
line(xpos+90,ypos+150,xpos+80,ypos+160);
line(xpos+110,ypos+150,xpos+120,ypos+160);
} else {
timeAngry = 0;
rectMode(CENTER);
print(int(timeAngry));
fill(127,0,0);
rect(xpos+100,ypos+100,20,100);
fill(255,200,200);
ellipse(xpos+100,ypos+70,60,60);
ellipse(xpos+81,ypos+70,16,32);
ellipse(xpos+119,ypos+70,16,32);
line(xpos+90,ypos+150,xpos+80,ypos+160);
line(xpos+110,ypos+150,xpos+120,ypos+160);
}
}
void mousePressed(){
poke();
}
void poke(){
isAngry = true;
print(timeAngry);
timeAngry=timeAngry+1;
redraw();
}
}
void mousePressed(){
firstmonster.mousePressed();
}
Also I can't seem to make the two models differentiate. If I put firstmonster.poke() then both the first and second model color change.
You don't have a global void draw() { .. } in your code, so there is nothing for redraw to trigger. Move code that should be draw as part of a frame out of setup(). Setup is for, unsurprisingly, one time setup code.
void setup() {
size(600,400);
firstmonster = new Monster(100,200);
secondmonster = new Monster(300,200);
noLoop();
}
void draw() {
firstmonster.draw();
secondmonster.draw();
}
Should do the trick.

Cellular Automaton Not Woorking [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
Update: Just to specify, depending on how I change the rules I can set it so within a couple of generations all cells are either permanently alive or dead. I have checked this by echoing statements to console. HOWEVER, this doesn't reflect in the GUI which shows all cells as always the same color.
I am trying to implement a simple Cellular Automaton to replicate the game of life. This uses the MASON library. My three classes:
Cell.java
package sim.app.gol;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.field.grid.IntGrid2D;
import sim.util.IntBag;
public class Cell implements Steppable {
public IntGrid2D grid = new IntGrid2D(0,0);
public void step(SimState state) {
Matrix matrix = (Matrix) state;
grid.setTo(matrix.matrix);
for(int x = 0; x < grid.getWidth(); x++) {
for(int y = 0; y < grid.getHeight(); y++) {
IntBag nei = grid.getMooreNeighbors(x, y, 2, 0, false, new IntBag(), new IntBag(), new IntBag());
int count = 0;
for(int i = 0; i < nei.size(); i++) {
count += nei.get(i);
}
int currentState = grid.get(x, y);
if(currentState == 0) {
if(count > 3)
matrix.matrix.set(x, y, 1);
} else if(currentState == 1) {
matrix.matrix.set(x,y,0);
}
}
}
}
}
Matrix.java
package sim.app.gol;
import ec.util.MersenneTwisterFast;
import sim.engine.SimState;
import sim.field.grid.IntGrid2D;
public class Matrix extends SimState {
public final int HEIGHT = 10;
public final int WIDTH = 10;
public IntGrid2D matrix = new IntGrid2D(HEIGHT, WIDTH);
public final int NUM_CELLS = 80;
public Matrix(long seed) {
super(seed);
}
public void start() {
super.start();
// Utils for random number generator
MersenneTwisterFast g = new MersenneTwisterFast();
// We set everything to 0, no cells are active
matrix.setTo(0);
// Populating
for(int i = 0; i < NUM_CELLS; i++) {
int x = 0;
int y = 0;
// We don't want to mark as 'active' a cell that is already active
do {
x = g.nextInt(WIDTH);
y = g.nextInt(HEIGHT);
} while(matrix.get(x, y) == 1);
matrix.set(x, y, 1);
}
schedule.scheduleRepeating(new Cell());
}
public static void main(String[] args) {
doLoop(Matrix.class, args);
System.exit(0);
}
}
MatrixWithUI.java
package sim.app.gol;
import java.awt.Color;
import javax.swing.JFrame;
import sim.app.students.Students;
import sim.display.Console;
import sim.display.Controller;
import sim.display.Display2D;
import sim.display.GUIState;
import sim.engine.SimState;
import sim.portrayal.continuous.ContinuousPortrayal2D;
import sim.portrayal.grid.ObjectGridPortrayal2D;
import sim.portrayal.grid.ValueGridPortrayal2D;
import sim.portrayal.simple.OvalPortrayal2D;
public class MatrixWithUI extends GUIState {
public Display2D display;
public JFrame displayFrame;
public ValueGridPortrayal2D matrixPortrayal = new ValueGridPortrayal2D();
public static void main(String[] args) {
MatrixWithUI mwu = new MatrixWithUI();
Console c = new Console(mwu);
c.setVisible(true);
}
public void start() {
super.start();
setupPortrayals();
}
public void load(SimState state) {
super.load(state);
setupPortrayals();
}
public void setupPortrayals() {
Matrix matrix = (Matrix) state;
matrixPortrayal.setField(matrix.matrix);
matrixPortrayal.setPortrayalForAll(new OvalPortrayal2D());
display.reset();
display.setBackdrop(Color.white);
display.repaint();
}
public void init(Controller c) {
super.init(c);
display = new Display2D(600,600,this);
display.setClipping(true);
displayFrame = display.createFrame();
displayFrame.setTitle("Schoolyard Display");
c.registerFrame(displayFrame);
displayFrame.setVisible(true);
display.attach(matrixPortrayal, "Yard");
}
public void quit() {
super.quit();
if (displayFrame != null) displayFrame.dispose();
displayFrame = null;
display = null;
}
public MatrixWithUI() {
super(new Matrix (System.currentTimeMillis()));
}
public MatrixWithUI(SimState state) {
super(state);
}
public static String getName() {
return "Student Schoolyard Cliques";
}
}
However, for some reason all cells are continuously set to 0 (or off). Any thoughts?
Note: this is a tentative answer as I have no way of verifying it at the moment.
First, let's look at the documentation of ValueGridPortrayal2D. It says:
Like other FieldPortrayal2Ds, this class uses an underlying SimplePortrayal2D to draw each separate element in the grid. A default SimplePortrayal2D is provided which draws squares. In the default, the color for the square is determined by looking up the value of the square in a user-provided color-table, or if there is none, by interpolating it between two user-provided colors. See the setColorTable() and setLevels() methods.
So, if you settle for squares rather than ovals, you can drop this line:
matrixPortrayal.setPortrayalForAll(new OvalPortrayal2D());
And instead, add:
java.awt.Color[] colorTable = new java.awt.Color[2];
colorTable[0] = new java.awt.Color(1.0F,0.0F,0.0F,0.0F);
colorTable[1] = new java.awt.Color(1.0F,0.0F,0.0F,1.0F);
matrixPortrayal.setMap( new SimpleColorMap(colorTable) );
This should give you white squares (transparent on a white backdrop) for 0, and red squares for 1.
If you want to draw ovals, this default implementation of a SimplePortrayal2D that uses a map is not available. The documentation goes further to say:
You can also provide your own custom SimplePortrayal2D (use setPortrayalForAll(...) ) to draw elements as you see fit rather than as rectangles. Your SimplePortrayal2D should expect objects passed to its draw method to be of type MutableDouble.
So we need to override the draw() method and treat the passed object - the cell value - as a MutableDouble (by which I assume they mean the one from org.apache.commons.lang):
matrixPortrayal.setPortrayalForAll(new OvalPortrayal2D() {
public void draw(Object object, Graphics2D graphics, DrawInfo2D info) {
MutableDouble valueObj = (MutableDouble)object;
if ( valueObj.intValue() == 0 ) {
paint = new java.awt.Color(1.0F,0.0F,0.0F,0.0F);
} else {
paint = new java.awt.Color(1.0F,0.0F,0.0F,1.0F);
}
filled = true;
super.draw(object, graphics, info);
}
});
So we have created an anonymous subclass of OvalPortrayal2D. It inherits the fields paint, filled and scale from AbstractShapePortrayal2D. So we override paint (java.awt.Paint, which java.awt.Color extends) with the color we need for the particular value, and make sure the oval is filled.

LibGDX - IllegalArgumentException causes my game to crash whenever my main character touches a Coin

Trying to figure out why my Android game crashes whenever the player touches an animated coin. I have attached an image of the LogCat and my code is below (NOTE: all game objects in ![Renderer] are in an arraylist called toRender. the 2 coins in the game are currently held in the 3rd and 4th position in the list). Renderer and Coin classes respectively:
public class Renderer extends ApplicationAdapter {
private SpriteBatch batch;
private Texture background;
private ArrayList<GameObject> toRender;
private Timer timer;
private float delta;
private Game game;
public Renderer(ArrayList<GameObject> toRender) {
batch = new SpriteBatch();
background = new Texture(Gdx.files.internal("background2.png"));
this.toRender = toRender;
timer = Timer.getInstance();
}
public void collect() {
// for every object in toRender (an arraylist of objects)
for (GameObject o : toRender) {
// if player collides with/collects an object
if (Player.getInstance(null).hasCollected(o)) {
// if its the first coin that he collides with, dispose it
if (o.equals((Coin) toRender.get(3))) {
((Coin) toRender.get(3)).dispose();
}
// if its the second coin that he collides with, dispose it
if (o.equals((Coin) toRender.get(4))) {
((Coin) toRender.get(4)).dispose();
}
}
}
}
public void beginRendering() {
delta = Timer.getInstance().getTime();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.begin();
batch.draw(background, 0, 0, Gdx.graphics.getWidth(),
Gdx.graphics.getHeight());
timer.drawTime(batch);
for (GameObject object : toRender) {
object.update();
boolean objectIsntCoin = !(object.equals(toRender.get(3)) ||
object.equals(toRender.get(4))); //the 2 coins are in the 3rd and 4th position in the array list
// draw every object's sprite apart from coin, since coin should render the animation rather than the sprite
if (objectIsntCoin) {
object.draw(batch);
}
}
collect();
((Flag) toRender.get(toRender.size() - 1)).drawLevelComplete(batch);
// if the coin exists (i.e. hasn't been disposed), render the animation
if (((Coin) toRender.get(3)).checkExists()) {
((Coin) toRender.get(3)).render(delta);
}
// if the coin exists (i.e. hasn't been disposed), render the animation
if (((Coin) toRender.get(4)).checkExists()) {
((Coin) toRender.get(4)).render(delta);
}
batch.end();
}
}
public class Coin extends GameObject implements Screen {
private SpriteBatch batch;
private Animation animation;
private float time;
private float xPos;
private float yPos;
private Rectangle objectRect;
private boolean exists;
public Coin(Sprite spr, float xPos, float yPos, float radius) {
super(spr, xPos, yPos, radius);
this.xPos = xPos;
this.yPos = yPos;
batch = new SpriteBatch();
objectRect = new Rectangle(getxPos(), getyPos(), getSprite().getWidth(), getSprite().getHeight());
exists = true;
time = 0;
show();
}
public Rectangle getRect() {
return objectRect;
}
public void render(float delta) {
// TODO Auto-generated method stub
batch.begin();
batch.draw(animation.getKeyFrame(time += delta), xPos, yPos);
batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void show() {
animation = new Animation(1 / 8f,
new TextureRegion(new Texture(Gdx.files.internal("coin1.png"))),
new TextureRegion(new Texture(Gdx.files.internal("coin2.png"))),
new TextureRegion(new Texture(Gdx.files.internal("coin3.png"))),
new TextureRegion(new Texture(Gdx.files.internal("coin4.png"))),
new TextureRegion(new Texture(Gdx.files.internal("coin5.png"))),
new TextureRegion(new Texture(Gdx.files.internal("coin6.png"))),
new TextureRegion(new Texture(Gdx.files.internal("coin7.png"))),
new TextureRegion(new Texture(Gdx.files.internal("coin8.png"))));
animation.setPlayMode(Animation.PlayMode.LOOP);
}
#Override
public void hide() {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void dispose() {
batch.dispose();
exists = false;
}
public boolean checkExists() {
return exists;
}
}
LogCat:1
So the errors that the LogCat point to:
1)dispose() method in Coin:
batch.dispose();
2)collect() method in Renderer:
if(o.equals((Coin) toRender.get(3))) {
3)beginRendering() method in Renderer:
for (GameObject object : toRender) {
Does anyone know why my program is crashing? I just want the animated coin to disappear when the Player touches it. Currently the coin DOES disappear, the application just shuts down immediately after though. Have been stuck on this for a while so any insight is highly appreciated.
Thank you in advance.
First, I want to mention that downcasting the objects in toRender like you are is both dangerous and indicates there is a flaw in your design. Additionally, you'll notice that equals(Object) accepts an Object as an argument; you don't need to cast it to Coin.
Anyway, the reason your program is crashing is explained in the IllegalArgumentException message,
buffer not allocated with newUnsafeByteBuffer or already disposed.
You're trying to dispose your Coin's batch when it has already been disposed.
In your collect() method, you loop through the objects, and you dispose of their batches, but the Coin objects themselves are never removed from your toRender list. So, the next time collect() is called, it will loop through those same Coin objects and try to dispose of them again, and an exception is thrown.
The solution is to remove the Coin objects from your toRender list when they no longer belong in your game's scene. However, you can't remove an element from a list while you're iterating over it, as this would disrupt the loop. Instead, remove them like so:
public void collect() {
// Holds the Coins we want to remove from toRender
final Collection<GameObject> toRemove = new LinkedList<>();
for (GameObject o : toRender) {
if (Player.getInstance(null).hasCollected(o)) {
if (o.equals(toRender.get(3))) {
final Coin coin = (Coin) toRender.get(3);
coin.dispose();
toRemove.add(coin);
}
if (o.equals(toRender.get(4))) {
final Coin coin = (Coin) toRender.get(4);
coin.dispose();
toRemove.add(coin);
}
}
}
// Remove the collected Coins
toRender.removeAll(toRemove);
}

Categories