When I switch screens it lags and takes a really long time to load it on android, but on desktop launcher it does it instantly.
An example of a screen that takes a long time load is the level screen, it goes there from the main menu.
This is the code in the LevelScreen it takes a really long time load this, Is there any reason for this?
public class LevelScreen extends MenuBase {
private GameMain mGameMain;
public LevelScreen(GameMain main) {
super(main, GameInfo.LEVEL_SCREEN_NAME);
this.mGameMain = main;
main.ply.showAds(false);
}
#Override
protected Actor createActors() {
Table container = new Table();
container.setDebug(GameInfo.TABLE_DEBUG);
container.setFillParent(true);
container.setBackground(new TextureRegionDrawable(new TextureRegion(new Texture(AssetPaths.BLUE_BACKGROUND))));
Table table = new Table();
table.setBackground(new TextureRegionDrawable(new TextureRegion(new Texture(AssetPaths.BLUE_BACKGROUND))));
table.setDebug(GameInfo.TABLE_DEBUG);
final ScrollPane scroll = new ScrollPane(table, uiSkin);
table.pad(GameInfo.HUD_HEIGHT).defaults().space(10);
for (int i = 1; i < 8; i++) {
table.row();
final TextButton button = new TextButton("Level " + i, uiSkin, SkinStylePath.LIGHT_BUTTON_LONG);
table.add(button).padRight(50f);
button.addListener(new ClickListener() {
public void clicked(InputEvent event, float x, float y) {
System.out.println("click " + x + ", " + y);
}
});
System.out.println(GameManager.getInstance().scoreUnlockList(i));
System.out.println("GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() = " + GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() +
"\n GameManager.getInstance().mGameData.isLevel7Unlocked() " + GameManager.getInstance().mGameData.isLevel7Unlocked());
if (GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() < i) {
// for the levels we haven't unlocked write this next to it.
table.add(new Label("get over " + GameManager.getInstance().scoreUnlockList(i) + " points to unlock this level", uiSkin, SkinStylePath.ARVO_WHITE_WITH_BLACK_OUTLINE_22));
//disable all the buttons that we haven't unlocked that level for
button.setDisabled(true);
}
final int finalI = i;
button.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
clickSound(randomNumberGenerator()).play(GameManager.getInstance().mGameData.getSoundFxVolume());
playLevel(finalI, button);
}
});
}
scroll.setFlickScroll(true);
scroll.setFadeScrollBars(true);
scroll.setSmoothScrolling(true);
container.add(scroll).expand().fill();
container.row();
return container;
}
#Override
protected void createAnotherActor(Stage mStage) {
Texture handTexture;
handTexture = mAssetManager.get(AssetDescriptors.HAND);
Image handImage = new Image(handTexture);
handImage.setPosition(560, 100);
SequenceAction sequenceAction = new SequenceAction(GameManager.getInstance().handMoveSequence(0.3f, false), Actions.moveTo(560f, 560f, 0.8f));
handImage.addAction(sequenceAction);
if (GameManager.getInstance().mGameData.getUpToWhichLevelIsUnlocked() >= 3) {
mStage.addActor(handImage);
}
}
void playLevel(int levelNumber, TextButton levelTextButton) {
GameManager.getInstance().selectLevel(levelNumber);
mGameMain.setScreen(new NutritionQuiz(mGameMain, levelTextButton.getText().toString()));
}
#Override
public void show() {
}
}
All I can do is guess to what's slowing your game down.
The first thing I see is container.setBackground(new TextureRegionDrawable(new TextureRegion(new Texture(AssetPaths.BLUE_BACKGROUND)))); Every time you switch screens, this method is called. The thing that takes the longest in that line is probably new Texture(AssetPaths.BLUE_BACKGROUND). Doing that is much better than having static resources but it takes a long time.
One thing you could do is use a Skin. This is libgdx's way of organizing sprites, fonts, and almost anything else. It can be hard to refactor the code to make it use a skin, but in the end, it is worth it. If used correctly, instead of having multiple files with sprites, all the sprites would be compiled into a master like file so only one file would have to be loaded.
Here's an example of how I use it. As you can see, I have a skin.atlas, skin.json, skin.png. Luckily for you, you don't have to create these manually. How to use TexturePacker Is also useful as well.
If you really don't want to refactor your game into using skins, you can always store Drawables in a single object and pass that object around to each Screen so it's not loading sprites whenever the screen is changed.
Please provide code of MenuBase, because it is impossible to see something from your inherited class.
Possible solutions to find performance lack:
1) Try to profile your code step by step. Create any time counter class and check each method you call after calling next screen.
2) Try to remove all extra code from your affected classes. If you have actors create method - don't call it. You have main.ply.showAds(false); - try to remove it at first, I guess this code calls something from external library. It is easily able to slow down your app.
As for #retodaredevil answer - methods like new Texture, TextureRegion, etc do not make something bad. I have interface with hundreds of such method calls and I don't see any impact on loading time by that.
Related
I'm trying to implement a MiniMax algorithm in a Reversi/Othello game, and I'm pretty stuck, since the function I wrote looks perfectly normal, and yet I get some strange moves, and a crash after a few. Here's the function finding an optimum move:
public Field findBestMove(GameBoard gb, int depth, int player)
{
if(depth >= max_depth) return null;
ArrayList <Field> moves = findAllPossibleMoves(gb, player);
Field best_move = null;
/** iterating over all possible moves, to find the best one */
for (int i=0; i<moves.size(); i++)
{
/* board to simulate moves */
GameBoard temp_board = new GameBoard(gb);
Field move = moves.get(i);
game.move(move, temp_board, player);
int opposite_player = player == GameBoard.WHITE ? GameBoard.BLACK : GameBoard.WHITE;
Field best_deep_move = findBestMove (temp_board, depth + 1, opposite_player);
/** if the maximum depth is reached, we have a null, so we evaluate */
if (best_deep_move == null)
{
/** we rate it according to the evaluation table */
move.setRating(evaluate (temp_board, player));
}
else
{
move.setRating(best_deep_move.getRating());
}
if(best_move == null)
{
best_move = move;
}
else
{
if (depth%2==0)
{
/** for us, we look for the maximum */
if (best_move.getRating() < move.getRating()) best_move = move;
}
else
{
/** for the opponent, we look for the minimum */
if (best_move.getRating() > move.getRating()) best_move = move;
}
}
}
return best_move;
}
After each move, the active player is changed. In the onTouchEvent method of the GameView, first the player makes his move, and then the player is changed to the WHITE one, which is the AI, and it makes a move. It should search for the best move in his tree, and then perform ONE move, instead he does several weird moves. I've no idea why, for each branch I create a new copy of a board, so I have no idea why the main game board gets modified.
Any ideas?
If changing a copy of an object affects the original. Then it is a "shallow copy". That means that somewhere in data structure objects are shared. You want a "deep copy".
Show us the code for new GameBoard(gb)
Some optinos: you can implement clone for your Gameboard and all of the objects it contains (and that they contain). Or, implement an undo() function in your game board. As long as you undo every move in your gameboard you can perform moves on it. That would save memory and object creation overhead when doing test moves during evaluation..
I am creating a game using Andengine and in this I want an object flying in the sky to drop bombs below. Currently I am using a timehandler to create both the flying object and the bombs. But its not working properly. The problems I am facing are:
1) Sometimes instead of a single bomb 2 or 3 bombs are dropped.
2) And the bomb objects are also not getting recycled. The code for recycling the object is getting called, but it doesn't seem to work.
I have noticed one thing i.e. suppose, initially I have one flying object that drops a bomb. When the bomb leaves the screen, the recycling code for bomb object gets called once. And after sometime as the flying object leaves the screen it also gets recycled. Now when another flying object is created and it drops the bomb, the code for recycling the bomb is getting called twice. Then for third flying object, the code for recycling the single bomb is getting called thrice and so on.
The code to add flying object is as follows
private void createDragonHandler() {
TimerHandler spriteTimerHandler;
float mEffectSpawnDelay = 10f;
spriteTimerHandler = new TimerHandler(mEffectSpawnDelay, true,
new ITimerCallback() {
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
addDragon();
}
});
getEngine().registerUpdateHandler(spriteTimerHandler);
}
public void addDragon() {
Dragon dragon = (Dragon) dragonSpritePool.obtainPoolItem();
if (dragon.getParent() != mainScene)
mainScene.attachChild(dragon);
}
public synchronized Dragon obtainPoolItem() {
dragon = super.obtainPoolItem();
Random rand = new Random();
final int x = (int) (CAMERA_WIDTH + resourceManager.dragonTextureRegion
.getWidth());
int minY = (int) resourceManager.dragonTextureRegion.getHeight();
int maxY = (int) (CAMERA_HEIGHT / 2 - resourceManager.dragonTextureRegion
.getHeight());
int rangeY = maxY - minY;
final int y = rand.nextInt(rangeY) + minY;
dragon.reset();
dragon.setVisible(true);
dragon.setIgnoreUpdate(false);
dragon.animate(150);
dragon.setPosition(x, y);
MoveXModifier mod = new MoveXModifier(15, dragon.getX(),
-dragon.getWidth());
float mEffectSpawnDelay = 5f;
TimerHandler spriteTimerHandler = new TimerHandler(mEffectSpawnDelay,
true, new ITimerCallback() {
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
DragonFire dragonFire = BirdShoot.dragonFireSpritePool
.obtainPoolItem(dragon.getX(), dragon.getY());
BirdShoot.mainScene.attachChild(dragonFire);
}
});
dragon.registerEntityModifier(mod.deepCopy());
dragon.setNoHit(0);
PhysicsHandler mPhysicsHandler;
mPhysicsHandler = new PhysicsHandler(dragon);
dragon.setPhysicsHandler(mPhysicsHandler);
dragon.registerUpdateHandler(dragon.getmPhysicsHandler());
BirdShoot.engine.registerUpdateHandler(spriteTimerHandler);
return dragon;
}
`
Where are you writing the code for recycling the sprite objects? According to your problem, I see something fishy there. It might be possible that the code is not getting executed. The code to recycle the sprites must be something like this:-
public void onHandleRecycleItem(Sprite sprite){
super.onHandleRecycleItem(sprite);
// Your code to recycle the object
}
Also it should be called using the following line :
yourPool.recyclePoolItem(spriteObject);
Without seeing your code, it will be hard to help with this. But, this has the smell of things not being done on the updateThread.
Any time you do something that affects AndEngine, be sure you call it via
runOnUpdateThread(new Runnable() {
#Override
public void run() {
/* Do your AndEngine changes in here*/
}
});`
I was trying to make the enemies in my game go up and down; since I'm using a physic body with a Sprite on it I can't use entity modifiers, so I decided give the body a little push using the .setLinearVelocity(float x, float y) method every time its sprite reach a certain point in the screen.
With just one body works great, but I need to have other enemeis (same sprite, different body) spawning every 5 seconds and doing the same thing, but I don't know how to track them... I mean, I don't know how to control if each body reaches the Y location independently from one another...
For example, right now the code is like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
final Sprite rectangle_face = new Sprite(random_x, this.y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face, BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
//I give the body a initial push
rectangle_face_body.setLinearVelocity(0, -5);
//I register an update handler to the sprite to control if it reaches a certain Y value
rectangle_face.registerUpdateHandler(new IUpdateHandler()
{
#Override
public void onUpdate(float pSecondsElapsed)
{
if (rectangle_face.getY() >= y-50)
{
//Here I just use a flag so that later on below I can do the push
MyApp.this.setLinearVelocity = true;
}
}
#Override
public void reset()
{
// TODO Auto-generated method stub
}
});
//Here I register the physic connector and if the flag permits it, I push the body up
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face, rectangle_face_body, true, false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
if(MyApp.this.setLinearVelocity)
{
rectangle_face_body.setLinearVelocity(0, -3);
MyApp.this.setLinearVelocity = false;
}
}
});
this.mscene.attachChild(rectangle_face);
}
With the code like this the first body do what is planned, it moves up and down but as soon as another body pops up, it falls down and the other body goes up because the boolean setLinearVelocity is always set to true, so there is a costant push upwards; when a third body comes in, the second body falls down as well and this last one takes its place going up
With this code I didn't expect much else... but I don't know what else I can try... how can I control this?
Thanks in advance :)
EDIT: Added working code in an anwser below
I suggest you separate the code for the enemy from the code for the update handler. Create a class Enemy that will contain the Sprite and Body, hold your Enemies in an array and override the onUpdate method of your PhysicsWorld so that it goes through the array of Enemies and does what you want to all of them.
Here's a code snippet showing a very simple way of doing this:
mEngine.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() {}
#Override
public void onUpdate(float pSecondsElapsed) {
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
});
Please note that this may not a very good idea as this code will probably run on a thread different to the one of the physics engine, which could cause all sorts of problems. A better way would be overriding the onUpdate method of PhysicsWorld:
#Override
public void onUpdate(final float pSecondsElapsed) {
super.onUpdate();
for (Enemy e : enemies) {
e.checkPositionAndBounce();
}
}
If you are unsure of what the first snippet means, look up "anonymous inner class".
Ok, here's the final working code (I didn't create a method to check the position or a class for the enemies just because right now I'm just messing around with the mechanics; I'll create a new project when I'm ready to really start):
this.m_PhysicsWorld = new PhysicsWorld(new Vector2(0, SensorManager.GRAVITY_EARTH), false)
{
#Override
public void onUpdate(float pSecondsElapsed)
{
super.onUpdate(pSecondsElapsed);
for(int i = 0; i <= MyApp.this.mSpriteCounter; i++)
{
if (rectangle_face[i].getY() >= y-50)
{
final PhysicsConnector spritePhysicsConnector = m_PhysicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(rectangle_face[i]);
spritePhysicsConnector.getBody().setLinearVelocity(0, -3);
}
}
};
In this code rectangle_face[] is an array of Sprites; each sprite is created like this:
private void add_Box_Face()
{
float random_x = (float) (28 + (int)(Math.random() * ((this.CAMERA_WIDTH - 28*2) + 1)));
final Body rectangle_face_body;
rectangle_face[this.mSpriteCounter] = new Sprite(random_x, y, this.mRectangleFaceTextureRegion, this.getVertexBufferObjectManager());
rectangle_face_body = PhysicsFactory.createBoxBody(this.m_PhysicsWorld, rectangle_face[this.mSpriteCounter], BodyType.DynamicBody, this.BOX_FIXTURE_DEF);
rectangle_face_body.setUserData("target");
rectangle_face_body.setLinearVelocity(0, -5);
this.m_PhysicsWorld.registerPhysicsConnector(new PhysicsConnector(rectangle_face[this.mSpriteCounter], rectangle_face_body, true, false));
this.mscene.attachChild(rectangle_face[this.mSpriteCounter]);
}
That's it, thanks again for the help :)
I have an application using a GlSurfaceView and renderer. I have it set so that when the user exits the application via the back button I call myActivity.finish();
This is fine and I can see the activity getting calls to onStop() and onDestroy();
The app works fine the first time run however when I subsequently run I have had a problem with my motionEvents.
I handle motion events by queuing them into a pool and having the renderer access the pool at the right time like so:
try
{
//Get the history first
int hist = event.getHistorySize();
if (hist > 0)
{
//Oldest is first in the list. (I think).
for (int i=0;i <hist; i++)
{
InputObject input = inputObjectPool.take();
input.useEventHistory(event, i);
defRenderer.feedInput(input);
}
}
//The current one still needs to be added
InputObject input = inputObjectPool.take();
input.useMotionEvent(event);
defRenderer.feedInput(input);
}
And in the renderer:
synchronized (inputQueueMutex)
{
ArrayBlockingQueue<InputObject> inputQueue = this.inputQueue;
while (!inputQueue.isEmpty()){try
{
InputObject input = inputQueue.take();
if (input.eventType == InputObject.EVENT_TYPE_TOUCH)
{
screenManager.processMotionEvent(input);
}
else if (input.eventType == InputObject.EVENT_TYPE_KEY)
{
screenManager.processKeyPress(input);
}
input.returnToPool();
}
catch (InterruptedException ie)
{
DLog.defError("Interrupted blocking on input queue.", ie);
}
}
}
As you can see in the above code I hand these motion events to the ScreenManager which basically is my way of having several "scenes" which I render out. This works fine the first time I run the application and the screen interprets my motion touches into movement of a simple square at the moment.
However the second time I run the application the square is drawn to the screen fine however the motion events do nothing.
I have followed the motion events and although they are given to the "new" renderer it seems to be giving the motion events to an old screen. Or rather to an old object on the screen. This is confusing as in my code in the onCreate() method I do this:
//Set up the renderer and give it to the SurfaceView
defRenderer = new DefRenderer();
defView = new DefView(this);
defView.setRenderer(defRenderer);
//Set out content to the surface view.
setContentView(defView);
//Set up the input queue
createInputObjectPool();
OnCreate is called both the first time and the second time my app is run (and the app was destroyed!) the screens are made new in defRenderer and are given to a new defView.
I am very confused how data could remain in the defRenderer to receive the motionEvents as the app is completely remade.
Is there something obvious going on that I am missing here? I would have thought that when onDestroy is called the app would be completely dereferenced and so no trace of it would remain. Is this not true? Does somehow when I call new Renderer(); is it referencing an old one?
I am at a loss as to what is going on really. Especially as this app is a basic copy of another I have written which works completely fine!
EDIT:
After a small amount of experimentation I have discovered that the motion events are actually going to an old ScrollPanel (an object I made..) which is registered as a listener (and by listener I mean my own implementation ..) for MotionEvents. I have made my own event system for these like so:
public interface TouchSource
public static final int TYPE_TOUCHDOWN = 0;
public static final int TYPE_TOUCHDRAG = 1;
public static final int TYPE_TOUCHCLICK = 2;
public Vector<TouchListener> listeners = new Vector<TouchListener>();
public void addTouchListener(TouchListener listener);
public void removeTouchListener(TouchListener listener);
public void touchOccured(int type, int xPos, int yPos);
}
And the listener interface:
public interface TouchListener
public boolean touchDownOccured(int xPos, int yPos);
public boolean touchDragOccured(int xPos, int yPos);
public boolean touchClickOccured(int xPos, int yPos);
So the Screen implements touchSource and so has a list of the listeners. Now despite being REMADE by Screen currentScreen = new Screen(); called in the OnCreate(); of the manager this list of listeners is still populated with the old ScrollPanel?
How is this? I'm clearly missing something obvious. Like somehow the list of listeners is static for some reason and not getting dereferenced despite the app being completely remade?
I suspect the issue you're facing might have something to do with the fact that the original motionevents are recycled (returned to their pool) by the framework after the onMotionEvent() returns.
From the way you're using your InputObjects, I think you might be keeping a reference to the original motionevents in there, and not copying the event data.
Quickly try using MotionEvent.obtain(event) whereever you use event now (this makes a copy) and see if this makes the weird behaviour go away. Naturally, if this works you will eventually have to recycle() those copies after you're done with them. Do not call recycle() on the original motionevents though.
Cheers, Aert.
I started using Rokon to create the graphical portion of my game but when it was finished I had a lot of trouble creating a menu system and doing alerts with it. Discouraged, I started over without the game engine and made a nice looking UI. When the user clicks start game I want to run Rokon to load the graphics I made, but Ive tried everything I can think of and can't get it to not force close. I just did a basic call to make a new GameEngine since the GameEngine does everything else with the new view and the rest. Heres the code in my MainActivity(ignore the difficulty stuff, I just want to load the one difficulty for now):
protected void startGame(int difficulty) {
// TODO Auto-generated method stub
Context context = getApplicationContext();
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, "Game Started!" + "\n" + "Difficulty set to: " + difficulty, duration);
toast.show();
switch(difficulty){
case 1:
{
//Code to start Game on Easy
GameEngine easyGame = new GameEngine();
easyGame.onCreate();
Here is the Rokon GameEngine code I am trying to use, I made sure to add the library and other directories it was previously using...
import com.stickycoding.rokon.DrawPriority;
import com.stickycoding.rokon.RokonActivity;
public class GameEngine extends RokonActivity {
public static final float GAME_WIDTH = 320f;
public static final float GAME_HEIGHT = 480f;
private GameScene scene;
public void onCreate() {
debugMode();
forceFullscreen();
forcePortrait();
setGameSize(GAME_WIDTH, GAME_HEIGHT);
setDrawPriority(DrawPriority.PRIORITY_VBO);
setGraphicsPath("textures/");
createEngine();
}
public void onLoadComplete() {
Textures.load();
setScene(scene = new GameScene());
}
}
Maybe they just aren't compatible with each other and I have to stick with using Rokon from the start, but there's gotta be a way to make this work.
I've been playing around with the code and the debugger alot trying to figure out which part of the code wont work, and the error lies when I call createEngine(); if that helps at all... Some of the other code could be commented out to make it work, so Ive narrowed it down to that line.
You are using forcePortrait(). Did you set orientation to portrait for this activity in the manifest?