I'm making a similar game to the talking tom game where a character is animated on the screen and talks back.
I have about 100 transparent PNGs for each animation. There are 10 Animations. Each PNG has been compressed to the max, max file size is 30KB.
I've been having issues with memory management before ( fixed it ), but this is what I've tried before :
- Loading all PNGs into the assets manager on splashscreen : Takes too long to load, crashes at the end of the loading, no errors, no log.
- Packing all the PNGs into atlas files : Each PNG is 480*800, so I get about 5 pages of 2048*2048 atlas files for each. Takes too much time to load in the Assets manager, and same as before, crashes with no errors.
- I can't make the PNGs smaller in dimensions, please don't suggest that.
- I don't want to use GIFs or Videos for the animations.
What has worked for me is using a timer, no assets manager, and just loading whatever frame I need. It's working great on the 3 Android phones I have at my house + Friends, but they're all modern Samsung & Nexus devices. I've also tested on a few emulators, and it's working just fine.
I published the game a few days ago, and I'm getting some reviews about the game crashing right away, and since there is no errors or log to be reported, I'm not sure how to reproduce the issue or debug it.
Here's the code of my Actor that takes care of the animation :
public class AnimActor extends Actor {
private SpriteBatch batch;
private TextureAtlas textureAtlas;
private Sprite sprite;
private int currentFrame = 1;
private int TotalFrames ;
FileHandle[] filesxx;
String currentFolder;
Boolean currentLoop;
float stateTime;
TalkerGame Game;
AssetManager assets_manager;
String[] fileList;
TextureRegion tex1;
Texture tex = null;
Timer Timerx = null;
Timer.Task TheTask = null;
public AnimActor(TalkerGame talkerGame, AssetManager manager)
{
Game = talkerGame;
assets_manager = manager;
batch = new SpriteBatch();
sprite = new Sprite();
float scale = (float)( (float)Gdx.graphics.getWidth() / (float) (480));
sprite.setPosition(0, 0);
sprite.setBounds(0,0,(float)Gdx.graphics.getWidth() ,(float)Gdx.graphics.getHeight() );
// sprite.setScale(scale);
}
public void PlayAnimation(String FolderName,Boolean loop)
{
currentLoop = loop;
currentFolder = FolderName;
currentFrame = 1;
//String[] fileList = new String[0];
ArrayList<String> FileListArray = new ArrayList<String>();
final String Path = FolderName + "/";
filesxx = Gdx.files.internal(Path).list();
for (FileHandle file : filesxx) {
// do something interesting here
if( !file.name().contentEquals("icon.png") && file.name().contains(".png") )
{
FileListArray.add(file.name());
}
}
Collections.sort
(FileListArray, String.CASE_INSENSITIVE_ORDER);
fileList = FileListArray.toArray(new String[0]);
// Get all files in Folder
TotalFrames = fileList.length-1;
if(TheTask != null)
{
TheTask.cancel();
}
TheTask = new Timer.Task() {
@Override
public void run() {
currentFrame++;
if ((currentFrame > TotalFrames) && (currentLoop == false))
{
// Play Idle
PlayAnimation("idle", true);
currentLoop = true;
currentFolder = "idle";
// Stop Music if was playing
Game.StopMusic();
// Start/Restart Recording
Game.StartInterfaceRecord();
}
if ((currentFrame > TotalFrames) && (currentLoop == true))
{
currentFrame = 1;
}
/* if ((currentFrame > TotalFrames))
{
currentFrame = 1;
}*/
sprite.setRegion(getNextRegion(currentFrame));
}
};
if(Timerx != null)
{
Timerx.stop();
Timerx.clear();
}
Timerx = new Timer();
Timerx.schedule(TheTask, 0, 1 / 30.0f );
}
public TextureRegion getNextRegion(int CurrentFramex)
{
// System.gc();
String file_name = fileList[CurrentFramex]; // String.valueOf(CurrentFramex)+".png";
if(tex!=null)
{
// Game.aInterface.Log("Disposing Texture");
tex.dispose();
}
String num = "0";
if(CurrentFramex <10)
{
num = "00";
}
// System.gc();
FileHandle file = Gdx.files.internal(currentFolder+"/"+file_name);
tex = new Texture(file);
TextureRegion tex1= new TextureRegion(tex);
return tex1;
}
@Override
public void draw(Batch batch, float parentAlpha) {
// TODO Auto-generated method stub
sprite.draw(batch);
}
@Override
public void act(float delta) {
// TODO Auto-generated method stub
super.act(delta);
}
public String getCurrentFrameFile()
{
return currentFolder+"/"+fileList[currentFrame];
}
public void dispose(){
batch.dispose();
sprite.getTexture().dispose();
}
}
Thanks