Loop Not performing as expected when using detachChild() and addChild() - java

This question refers to andengine GL-ES1.
I am having trouble making a wallpaper activity that refreshes when your return to it, or when the user performs actions in the game.
My game has two activities. In one, you can edit and arrange the background elements in a room. In the other you play the game, and it uses the same background with the elements you arranged in the first activity.
There is also a live wallpaper in which your room is the background and characters move around in front of it.
I am making updtaes in onResume() in the wallpaper.
first I detach all the backgroudn sprites i used before.
Then I attach new sprites in the updated positions.
What happens is: some of the sprites don't show up.
Here is the method: Can you see anything I'm doing wrong?
private void loadBackgroundDecorations() {
//Add new decorations
Log.d(TAG, "loadBackgoundDecorations");
mEngine.runOnUpdateThread(new Runnable() {
#Override
public void run() {
// Remove Old Decorations
Log.d(TAG, "loadBackgoundDecorations: decorationList.size() =" + decorationList.size());
while(decorationList.size() > 0){
Sprite d = decorationList.remove(0);
scene.detachChild(d);
Log.d(TAG, "loadBackgoundDecorations: detachChild");
}
decorationList.clear();
//Add new decorations
ArrayList<Integer> decorations = app.getBackgroundManager().getDecorations();
Log.d(TAG, "loadBackgoundDecorations: decorations.size()" +decorations.size());
for (int i = 0; i < decorations.size(); i+=3) {
Log.d(TAG, "Decoration Values: texture-"+decorations.get(i)+", x-"+decorations.get(1+i)+", y-"+decorations.get(2+i));
Sprite draggable = new Sprite(decorations.get(1+i),decorations.get(2+i),mGameTextureRegionLibrary.get(decorations.get(i)));
draggable.setIgnoreUpdate(true);
scene.attachChild(draggable,0);
decorationList.add(draggable);
Log.d(TAG, "loadBackgoundDecorations: attachChild"+ i);
}
}
});
}
#Override protected void onResume() {
super.onResume();
Log.d(TAG, "onResume");
BitmapTextureAtlasTextureRegionFactory.createFromAsset(mTexture, this, app.getAquariumBackground(), 0, 0);
addBubbles();
loadBackgroundDecorations();
addCharacters()
}
============ UPDATE =================
As some people have suggested below, I tried adding all the scene setup functions into the runnable. This has no effect. What has worked for me is to set the "wrong" decorations visible property to "false". But I am worried that this will eventually cause a memory leak as more and more duplicates of the sprites are hidden on the wallpaper.
The problem only exists when I call "detachChild". For some reason that seems to prevent "attachChild" from firing correcly. Anybody have ideas for what could be causing this?
Can anyone else create an activity that adds and removes sprites in the onResume function?

I am fairly certain that the error has to do with your onResume method. The order you have your methods in is
addBubbles();
loadBackgroundDecorations();
addCharacters()
but your loadBackgroundDecorations uses a runnable so there is no guarantee that the method will run in between.
My Explanation:
From what I understand both addCharacter and addBubbles will be running on the UIthread whereas the loadBackgroundDecorations method will run on the update thread. The two threads will go through the methods at different times and that is where you are seeing some inconsistencies.
To Fix:
Put addBubbles and addCharacters in the same runnable in the order that you want and it should work as expected.

Related

ObjectAnimator strange behaviour while trying to pause

I have a few animated objects.
I use a custom class to store their ImageViews and ObjectAnimators
And I have a method for pausing them.
It looks pretty simple:
public void pause_animations(View view) {
for (int i = 0; i < num_of_objects; i++) {
objects[i].animator.pause();
}
}
This method being called in 2 cases:
As a button onClick.
At some random time.
When I press a button and this code runs - everything works perfectly. All objects stop their moving.
But in the second case, objects just freeze and teleport.
UPDATE. I have a touch listener. Every time user touches screen, a method try_to_pause(); runs.
private void try_to_pause() {
if (number_of_touches % touches_to_pause == 0) {
pause_animations(null);
}
}
From the documentation of the Animator#pause() method, another reason may be that you started the animation from a different thread than main (emphasis is mine).
Pauses a running animation. This method should only be called on the same thread on which the animation was started.

Breaking recursion from listeners

I'm trying to break a special case that makes this code recursive.
I have a Javafx game where there are human and computer players each play when it's his turn and there can be many rounds.
A computer is supposed to play automatically and move to the next player immediately and show no direct indication to the UI (but it's possible to review what it did afterwards).
The problem is in the case where there are only computer players, we will come here the moment the currentBoardPane was loaded, enter the condition since all players are computers, set the board of the next player, and then without finishing the call, call this same function again:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
gameManager.setNextPlayer(); // it does current player property = next player
//update board on scene
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
}
});
Instead of this, if I subscribe a listener to the currentPlayer property in GameManager then I still need to call setNextPlayer() from that listener which is again recursive.
I can make a special case if all players are a computer, then run the game from a while(true){} instead of listeners and binds but there has to be a better way to break this recursion.
Is there a way to not get into recursion while still having listeners and binds?
Notes:
currentBoardPane signifies the current game board on the screen and it's an ObjectProperty.
Making the following assumptions about your code:
Everything is currently running on the FX Application Thread
The currentBoardPane.setValue(...) causes the UI to update (so you update the UI each move)
then a "quick and dirty" way to do this is:
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
gameManager.playAutoMovesForCurrentPlayer();
//update board on scene
Platform.runLater(() -> {
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
}
});
This delegates the updates to a new Runnable, schedules that runnable to execute on the FX Application Thread, and exits the handler immediately. Thus the call to currentBoardPane.setValue(...) is executed later and is no longer recursive.
In fact, if you do just a little more work:
private final Executor aiExecutor = Executors.newSingleThreadExecutor();
// ...
currentBoardPane.addListener((e) -> {
if(gameManager.checkIfCurrentPlayerIsComputer()){
Task<Void> makeMoveTask = new Task<Void>() {
#Override
protected Void call() {
gameManager.playAutoMovesForCurrentPlayer();
return null ;
}
};
makeMoveTask.setOnSucceeded(e -> {
//update board on scene
gameManager.setNextPlayer(); // it does current player property = next player
currentBoardPaneIndex = ((currentBoardPaneIndex + 1) % gameManager.getPlayers().size());
currentBoardPane.setValue(boardPanes.get((currentBoardPaneIndex))); //this is a recursive call
});
aiExecutor.execute(makeMoveTask);
}
});
then this is exactly the code you would use if computing the move took enough time that it would not be acceptable to block the UI while it was happening. (And if computing the move takes very little time, this will still work just fine.) This assumes that playAutoMovesForCurrentPlayer() doesn't update the UI.

how to pause the game to handle user input

I'm facing a problem since many days without finding an anwser.
In the code i will not put all my code because it will just complicate the question.
I have a game class which is rendering each frame.
public class MyGame implements ApplicationListener {
#Override
public void render() {
//handling event
handleEvent();
//update player position
updatePlayerPosition();
//rendering the player using a batch
renderPlayer();
}
public void handleEvent(){
//when the player prees on C i'm calling a method in another class
// when i do some processing
if (Gdx.input.isKeyPressed(Keys.C)) {
OtherClassForProcessing() ocp = new OtherClassForProcessing();
ocp.process();
}
}
//in this method i have to ask the user to choose an option
//i have to think to stop running this method until the
// user choose an option
//this method has to return a value
public static int displayChoice(List<Integer> ListOfInteger){
return 0;
}
}
public Class OtherClassForProcessing(){
public void process(){
int value= MyGame.displayChoice() ;
}
}
The question is how can i ask the user to choose an option in the displayChoice method.
What kind of widget will do this work.
I tried to use another screen for that , but the methode don't stop running .
How can i ask the program to stop until the user choose an option.
Thank you
what i tried is :
#Override
public static int displayChoice(List<Integer> ListOfInteger){
//i change the screen when i ask the user to choose from many options
setScreen(new PauseScreen());
a wile loop hwo run until the user choose an option from the other screen
while(PauseScreen.notYetChoosen){
Gdx.app.log("display message ", "the user not yet choose an ption");
}
return PauseScreenValue;
}
When i put the while loop:
the screen don't change from the game to the PauseScreen.
the loop run without stoping
the screen block
But when i remove the while loop the screen change to the PauseScreen but the method finish without waiting the user to choose an option.
EDIT
i tried to avoid using another screen unfortunantly even when i used a window the screen block
You can use a separate screen for this, I do not know your code structure exactly but here is how you can do it conceptually if you were trying to get input from a "pop up" or "pause screen" or something of that nature.
Inside of your Game Screen have a boolean which will be set when your "pop up" is displayed, for example isPaused, then you can use this boolean to skip over game logic while waiting for the screen to receive input.
For a more elegant approach you can use Game States which can represent which state your game is in. You can have a PLAYING state, GETTING_INPUT state, etc. Then you can run game logic depending on which state you are in.
EXAMPLE:
public void update (float deltaTime) {
if (deltaTime > 0.1f) deltaTime = 0.1f;
switch (state) {
case GAME_READY:
updateReady();
break;
case GAME_RUNNING:
updateRunning(deltaTime);
break;
case GAME_PAUSED:
updatePaused();
break;
case GAME_LEVEL_END:
updateLevelEnd();
break;
case GAME_OVER:
updateGameOver();
break;
}
}
EXAMPLE SOURCE AND MORE INFO:
LIBGDX SuperJumper Demo
https://github.com/libgdx/libgdx-demo-superjumper/blob/master/core/src/com/badlogicgames/superjumper/GameScreen.java
Response to your edit
The reason your code is not changing is because you have a while loop printing out to the Gdx Log until input is taken so your code is stuck in that while loop.
If you want to go this route, you can set a 'pause' variable inside your Game Screen to true and then set your screen to the pause screen. Inside of your Game Screens update logic, tell it not to update if paused.
public void update()
{
if(!paused)
{
//game logic
}
}

Android AndEngine score += 1 error increases a lot

I am creating sprites that get saved into a list called listSprites each sprite that touches a line (line3) that I made gets detached from the screen. What I want is when It gets detached (collides with line3) the score increases only 1, but now it increases a lot like it reacher 10,218 in 1 minute, once a sprite collides with the line it detaches and the score starts increasing without stopping even though no sprite is coliiding with it.
/* The actual collision-checking. */
mScene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() { }
#Override
public void onUpdate(final float pSecondsElapsed) {
} for(Sprite s: listSprites){
if (s.collidesWith(line3)){
mScore += 1;
mScene.detachChild(s);
mText.setText(" "+mScore+"");
}
}
}
});
}
It looks like collidesWith() doesn't care whether the child is attached or not. If that's the case, and you don't want to remove the sprite from listSprites, you need to check each sprite in the list to see if it's attached in addition to the collision check.
I haven't used andengine much, but from looking at the source and examples, it looks like you could just do something as simple as changing:
if (s.collidesWith(line3)){
to:
if (s.hasParent() && s.collidesWith(line3)){
hasParent() should return false if the sprite is not attached to anything, so check for that.
This assumes that you're not attaching the sprites to a different scene in the meantime.

Making images drop in android

I am making an android game which needs to display some different images.
I need to make a method that keeps on generating images from a resource in the drawable directory and then drop the images from the top of the screen to the bottom. I also need that each image should have an id "image-1" "image-2" in which the index number goes higher once more images are created as an integer. I also need them to be generated at different locations at the top of the screen and drop with a specified speed. Once they hit the bottom, I want a method to be executed like:
public void touchedGround() {
//My code
}
I am using this code so far:
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
public class GameScreenActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gamescreen);
generateParachuters(savedInstanceState);
}
private void generateParachuters(Bundle icicle) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "generating images", 10).show();
}
}
I know one way to do it, but it requires a lot more code then what you're probably looking for. But hey, here goes.
Create a class for your falling object, which I'm guessing is a Parachuter. This class will have an X and Y variable to keep track of where it is on the screen. You can then have a tick method, which will increase the Y variable by however fast you want it to fall. You can also have them keep track of a integer ID if you want.
Create a list that will hold the Parachuter objects. I use an ArrayList. This way you create a Parachuter when needed and add it to the list. Cycle through the list to draw each one.
You need something to draw the Parachuters with. Personally, I use Canvas from SurfaceView.
You'll need a looping animation. Loop through, each time drawing the Parachuters and calling tick on each one.
During the loop, you can check the position of each Parachuter. If its position goes beyond Canvas.getHeight(), remove the image from the list.
Well, that's quite a bit there. Ask me if you need further clarification.
UPDATE: Here's a fully-working example.
UPDATE 2:
//Check right edge of screen
for (int i = 0; i < parachuters.size(); i++)
{
if (parachuters.get(i).getX() > canvas.getWidth())
//Do whatever it is you want
}

Categories