0
\$\begingroup\$

Hello I am trying to delay a part of the processes in my game, but it happend that I use one of my variables in an inner class so I have to make it final, but by making it final I can't assign new value when I find it. All I am asking for is to explain me how to do the delay without making my variable final. Here is my code:

public class TomatoScript implements IActorScript { private CompositeActor tomato; private static final int speed = 100; private BitmapFont bFont; private Batch bch; ArrayList<FruitScript> fruits; private final int dmg = 10; private int hp = 50; private Rectangle bounds; private int state = 0; private FruitScript collidetFruit; private boolean dead() { return hp <= 0; } private void setHp(int dmg) { hp = hp - dmg; } public TomatoScript(Batch b, BitmapFont bf, ArrayList<FruitScript> fruits) { this.bch = b; this.bFont = bf; this.fruits = fruits; } @Override public void init(CompositeActor entity) { this.tomato = entity; tomato.setPosition(200, 129); bounds = new Rectangle(tomato.getX(), tomato.getY(), tomato.getWidth(), tomato.getHeight()); bch.begin(); bFont.draw(bch, Integer.toString(hp), tomato.getX() + 20, tomato.getY() + 95); bch.end(); } @Override public void act(float delta) { switch (state) { case 0: tomato.setX(tomato.getX() + speed * delta); bounds.setX(tomato.getX()); bch.begin(); bFont.draw(bch, Integer.toString(hp), tomato.getX() + 20, tomato.getY() + 95); bch.end(); if (tomato.getX() >= 1090) { tomato.remove(); } if (collisionFound()) { state++; } break; case 1: if (collisionAct(collidetFruit)) { state = 0; } break; } } private boolean collisionFound() { for (FruitScript f : fruits) { if (f.getBounds().overlaps(bounds)) { collidetFruit = f; return true; } } return false; } private boolean collisionAct(FruitScript f) { com.badlogic.gdx.utils.Timer.schedule(new com.badlogic.gdx.utils.Timer.Task() { @Override public void run() { f.setCol(true);//here it says I should make the "f" final. f.setHp(dmg);//here also. setHp(f.getDmg()); } },2); if (f.dead()) { fruits.remove(f); return true; } if (dead()) { if (!f.dead()) { f.setCol(false); tomato.getScripts().remove(this); tomato.remove(); } return false; } return false; } @Override public void dispose() { }} 

I've tried to make it final, but it ruins everything it's supposed to stop the actors do the damage taking and then the one alive to continue, but it was doing it too fast in a blink of an eye. When you make the f final, it can't get the new item it should collide with. I hope someone can help :)

\$\endgroup\$
4
  • \$\begingroup\$ Did you tried to change your method signature to "private boolean collisionAct(final FruitScript f)" ? \$\endgroup\$ Commented Dec 19, 2015 at 14:53
  • \$\begingroup\$ @elenfoiro78 yes I tried \$\endgroup\$ Commented Dec 20, 2015 at 10:41
  • \$\begingroup\$ but as I explained it does not work right and and disposing my actor from the scene goes wrong \$\endgroup\$ Commented Dec 20, 2015 at 15:22
  • \$\begingroup\$ In fact, if the Timer wants to have f as final is because it needs to be sure that it will still be alive or point to the same thing the time it does its operations. \$\endgroup\$ Commented Dec 20, 2015 at 15:31

2 Answers 2

1
\$\begingroup\$

As wrote in my comment, f should be final because the timer created with an enclosure need to be sure that f will remain the same during the run() execution.

I would try to make a class deriving com.badlogic.gdx.utils.Timer.Task (lets say you call it myTimerTask) with a creator that takes the FruitScript as parameter and override run().

When in collisionAct(), you instanciate a new MyTimerTask(f) and pass it to com.badlogic.gdx.utils.Timer.Schedule().

This way you should avoid enclosure restriction.

Hope it helps.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks mate guess the whole thing was to make it separate :) \$\endgroup\$ Commented Dec 20, 2015 at 16:53
  • \$\begingroup\$ but it seems that it also delays my actor removals any ideas on this? \$\endgroup\$ Commented Dec 20, 2015 at 17:02
0
\$\begingroup\$

Solution 1

Well, let's look at the LibGDX application lifecycle:

  • new LwgjlApplication(parametershere)
  • create()
  • while(true && time since last frame >= 1000000000 / fps) render()
  • dispose()

Now if we look at this logically then most LibGDX applications run at 60 FPS but they also run on a sort of timer. The timer system that LibGDX uses is the Display.sync() method from LWJGL but we can't use that as we don't want to drop FPS

If we go deeper, what does Display.sync() use? It uses the base System.nanoTime() timing system which allows for precise nanosecond reactions in your program and it's built-in to Java!

How do we use this to do our delay then? We can use a few variables and an if statement to do the work for us easily. An example of this is posted below:

public class Timer { public static void main(String[] args) { long timeOfIncident = 0, timeTillReaction = 1000000000; boolean condition = true, timeOfIncidentSet = false, reactionOccurred = false; while(!reactionOccurred) { if(condition && !timeOfIncidentSet) { timeOfIncident = System.nanoTime(); timeOfIncidentSet = true; } if(System.nanoTime() >= timeOfIncident + timeTillReaction) { System.out.println("Reaction in 1 second / 1 billion nanoseconds!"); reactionOccurred = true; } } } } 

Solution 2

We can use the default LibGDX Timer class:

float delayInSeconds = 4; SpriteBatch exampleBatch = new SpriteBatch(); BitmapFont font = new BitmapFont(); Timer.schedule(new Task() { @Override public void run() { exampleBatch.begin(); font.draw(exampleBatch, "Draws after 4 seconds!", Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2); exampleBatch.end(); } }, delayInSeconds); 

Hope this helps!

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.