From: oskar.wiksten Date: Sun, 16 Oct 2011 07:08:52 +0000 (+0000) Subject: Major refactoring of resourceloader. This version loads graphical resources when... X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=ebc9c9998bf6847b1fbe3d6910de3c1c5fda5e62;p=users%2Fmchehab%2Fandors-trail.git Major refactoring of resourceloader. This version loads graphical resources when they are first required, instead of loading them all when the game starts. Resources are cached using SoftReference<> and reclaimed by the Android OS whenever needed. Refactored resourceloader of conversationcollection. Now the game only loads conversations when they are used in the ConversationActivity, instead of loading them all when the game starts. These two changes drastically reduces the memory footprint of the game, thus allowing devices with lower maximum heap size to run the game. Changed link to forums (http://andorstrail.com/) git-svn-id: https://andors-trail.googlecode.com/svn/trunk@181 08aca716-68be-ccc6-4d58-36f5abd142ac --- diff --git a/AndorsTrail/AndroidManifest.xml b/AndorsTrail/AndroidManifest.xml index 15040ff..a839185 100644 --- a/AndorsTrail/AndroidManifest.xml +++ b/AndorsTrail/AndroidManifest.xml @@ -4,7 +4,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" package="com.gpl.rpg.AndorsTrail" android:versionCode="25" - android:versionName="0.6.10a4" + android:versionName="0.6.10b1" android:installLocation="auto" > Willkommen bei Andor\'s Trail, einem roguelike Open-Source Rollenspiel für Android<br /> <br /> - <a href="http://andors.techby2guys.com/">Forum auf andors.techby2guys.com für Fragen und Diskussionen.</a><br /> + <a href="http://andorstrail.com/">Forum auf andorstrail.com für Fragen und Diskussionen.</a><br /> <br /> <a href="http://code.google.com/p/andors-trail/">Projekt Homepage auf code.google.com für Entwickler.</a><br /> <br /> diff --git a/AndorsTrail/res/values-fr/strings.xml b/AndorsTrail/res/values-fr/strings.xml index 31e28a1..ecff8be 100644 --- a/AndorsTrail/res/values-fr/strings.xml +++ b/AndorsTrail/res/values-fr/strings.xml @@ -192,7 +192,7 @@ Bienvenue à la Piste d\'Andor, un jeu de rôle libre sur Android.<br /> <br /> - <a href="http://andors.techby2guys.com/">Forum du jeu andors.techby2guys.com pour les questions et les discussions sur la façon de jouer.</a><br /> + <a href="http://andorstrail.com/">Forum du jeu andorstrail.com pour les questions et les discussions sur la façon de jouer.</a><br /> <br /> <a href="http://code.google.com/p/andors-trail/">Site internet du projet sur code.google.com pour les développeurs.</a><br /> <br /> diff --git a/AndorsTrail/res/values-it/strings.xml b/AndorsTrail/res/values-it/strings.xml index f09b67c..df88d10 100644 --- a/AndorsTrail/res/values-it/strings.xml +++ b/AndorsTrail/res/values-it/strings.xml @@ -190,7 +190,7 @@ Benvenuto in Andor\'s Trail, un gioco RPG per Android.<br /> <br /> - <a href="http://andors.techby2guys.com/">Forum del gioco su andors.techby2guys.com per domande e discussioni riguardo il gameplay.</a><br /> + <a href="http://andorstrail.com/">Forum del gioco su andorstrail.com per domande e discussioni riguardo il gameplay.</a><br /> <br /> <a href="http://code.google.com/p/andors-trail/">Homepage del progetto su code.google.com</a><br /> <br /> diff --git a/AndorsTrail/res/values-ru/strings.xml b/AndorsTrail/res/values-ru/strings.xml index 705d3a6..09e1951 100644 --- a/AndorsTrail/res/values-ru/strings.xml +++ b/AndorsTrail/res/values-ru/strings.xml @@ -166,7 +166,7 @@ Добро пожаловать в игру След Эндора, рогалик РПГ на Android.<br /> <br /> - <a href="http://andors.techby2guys.com/">Game forums on andors.techby2guys.com for questions and gameplay discussions.</a><br /> + <a href="http://andorstrail.com/">Game forums on andorstrail.com for questions and gameplay discussions.</a><br /> <br /> <a href="http://code.google.com/p/andors-trail/">Project homepage on code.google.com for developers.</a><br /> <br /> diff --git a/AndorsTrail/res/values/strings.xml b/AndorsTrail/res/values/strings.xml index d64d83d..5100a1c 100644 --- a/AndorsTrail/res/values/strings.xml +++ b/AndorsTrail/res/values/strings.xml @@ -194,7 +194,7 @@ Welcome to Andor\'s Trail, an open-source roguelike RPG on Android.<br /> <br /> - <a href="http://andors.techby2guys.com/">Game forums on andors.techby2guys.com for questions and gameplay discussions.</a><br /> + <a href="http://andorstrail.com/">Game forums on andorstrail.com for questions and gameplay discussions.</a><br /> <br /> <a href="http://code.google.com/p/andors-trail/">Project homepage on code.google.com for developers.</a><br /> <br /> diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java index 41e8dc9..ceaedeb 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/AndorsTrailApplication.java @@ -20,7 +20,7 @@ public final class AndorsTrailApplication extends Application { public static final boolean DEVELOPMENT_VALIDATEDATA = false; public static final boolean DEVELOPMENT_DEBUGMESSAGES = false; public static final int CURRENT_VERSION = 25; - public static final String CURRENT_VERSION_DISPLAY = "0.6.10a4"; + public static final String CURRENT_VERSION_DISPLAY = "0.6.10b1"; public final WorldContext world = new WorldContext(); public final WorldSetup setup = new WorldSetup(world, this); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/Dialogs.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/Dialogs.java index 3fa70d8..0b7d355 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/Dialogs.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/Dialogs.java @@ -46,7 +46,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.Monster; import com.gpl.rpg.AndorsTrail.model.item.ItemType; import com.gpl.rpg.AndorsTrail.model.item.Loot; import com.gpl.rpg.AndorsTrail.model.map.MapObject; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; import com.gpl.rpg.AndorsTrail.view.ItemContainerAdapter; public final class Dialogs { @@ -184,12 +184,12 @@ public final class Dialogs { ((ItemContainerAdapter) itemList.getAdapter()).notifyDataSetChanged(); } }); - itemList.setAdapter(new ItemContainerAdapter(mainActivity, context.tileStore, combinedLoot.items)); + itemList.setAdapter(new ItemContainerAdapter(mainActivity, context.tileManager, combinedLoot.items)); AlertDialog.Builder db = new AlertDialog.Builder(mainActivity) .setTitle(title) .setMessage(msg) - .setIcon(new BitmapDrawable(context.tileStore.getBitmap(TileStore.iconID_groundbag))) + .setIcon(new BitmapDrawable(context.tileManager.preloadedTiles.getBitmap(TileManager.iconID_groundbag))) .setNegativeButton(R.string.dialog_close, null) .setView(itemList); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/WorldSetup.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/WorldSetup.java index 8374a34..b4fa7ad 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/WorldSetup.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/WorldSetup.java @@ -107,7 +107,7 @@ public final class WorldSetup { Context ctx = androidContext.get(); int result = Savegames.loadWorld(world, ctx, loadFromSlot); if (result == Savegames.LOAD_RESULT_SUCCESS) { - MovementController.loadCurrentTileMap(ctx.getResources(), world); + MovementController.cacheCurrentMapData(ctx.getResources(), world, world.model.currentMap); } return result; } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java index f8523f6..63a75ed 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ActorConditionInfoActivity.java @@ -33,7 +33,8 @@ public class ActorConditionInfoActivity extends Activity { setContentView(R.layout.actorconditioninfo); ImageView img = (ImageView) findViewById(R.id.actorconditioninfo_image); - img.setImageBitmap(world.tileStore.getBitmap(conditionType.iconID)); + world.tileManager.setImageViewTile(img, conditionType); + TextView tv = (TextView) findViewById(R.id.actorconditioninfo_title); tv.setText(conditionType.name); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java index 58faf3e..f2b10c3 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java @@ -37,7 +37,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.Actor; import com.gpl.rpg.AndorsTrail.model.actor.Monster; import com.gpl.rpg.AndorsTrail.model.actor.Player; import com.gpl.rpg.AndorsTrail.model.item.Loot; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; public final class ConversationActivity extends Activity { public static final int ACTIVITYRESULT_ATTACK = Activity.RESULT_FIRST_USER + 1; @@ -59,6 +59,8 @@ public final class ConversationActivity extends Activity { private OnClickListener radioButtonListener; private boolean displayActors = true; + private final ConversationCollection conversationCollection = new ConversationCollection(); + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -92,7 +94,7 @@ public final class ConversationActivity extends Activity { statementList = (ListView) findViewById(R.id.conversation_statements); statementList.addFooterView(replyGroup); - listAdapter = new StatementContainerAdapter(this, conversationHistory, world.tileStore); + listAdapter = new StatementContainerAdapter(this, conversationHistory, world.tileManager); statementList.setAdapter(listAdapter); nextButton = (Button) findViewById(R.id.conversation_next); @@ -119,7 +121,6 @@ public final class ConversationActivity extends Activity { setPhrase(phraseID); } - public void setPhrase(String phraseID) { this.phraseID = phraseID; @@ -144,7 +145,7 @@ public final class ConversationActivity extends Activity { return; } - phrase = world.conversations.getPhrase(phraseID); + phrase = world.conversationLoader.loadPhrase(phraseID, conversationCollection, getResources()); if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) { if (phrase == null) phrase = new Phrase("(phrase \"" + phraseID + "\" not implemented yet)", null, null, null); } @@ -249,6 +250,7 @@ public final class ConversationActivity extends Activity { } s.text = text; s.color = color; + s.isPlayerActor = actor != null ? actor.isPlayer : false; conversationHistory.add(s); listAdapter.notifyDataSetChanged(); statementList.requestLayout(); @@ -277,6 +279,7 @@ public final class ConversationActivity extends Activity { public String text; public int iconID; public int color; + public boolean isPlayerActor; public boolean hasActor() { return iconID != NO_ICON; @@ -291,6 +294,7 @@ public final class ConversationActivity extends Activity { dest.writeString(text); dest.writeInt(iconID); dest.writeInt(color); + dest.writeByte((byte) (isPlayerActor ? 1 : 0)); } @SuppressWarnings("unused") @@ -301,6 +305,7 @@ public final class ConversationActivity extends Activity { result.text = in.readString(); result.iconID = in.readInt(); result.color = in.readInt(); + result.isPlayerActor = in.readByte() == 1; return result; } @@ -312,11 +317,11 @@ public final class ConversationActivity extends Activity { private static final class StatementContainerAdapter extends ArrayAdapter { - private final TileStore tileStore; + private final TileManager tileManager; - public StatementContainerAdapter(Context context, ArrayList items, TileStore tileStore) { + public StatementContainerAdapter(Context context, ArrayList items, TileManager tileManager) { super(context, 0, items); - this.tileStore = tileStore; + this.tileManager = tileManager; } @Override @@ -331,7 +336,8 @@ public final class ConversationActivity extends Activity { final ImageView iv = (ImageView) result.findViewById(R.id.conversation_image); final TextView tv = (TextView) result.findViewById(R.id.conversation_text); if (statement.hasActor()) { - iv.setImageBitmap(tileStore.getBitmap(statement.iconID)); + if (statement.isPlayerActor) tileManager.setImageViewTileForPlayer(iv, statement.iconID); + else tileManager.setImageViewTileForMonster(iv, statement.iconID); iv.setVisibility(View.VISIBLE); tv.setText(statement.actorName + ": " + statement.text, BufferType.SPANNABLE); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Inventory.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Inventory.java index 56f114c..6c6ec09 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Inventory.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Inventory.java @@ -9,6 +9,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.Player; import com.gpl.rpg.AndorsTrail.model.item.Inventory; import com.gpl.rpg.AndorsTrail.model.item.ItemContainer; import com.gpl.rpg.AndorsTrail.model.item.ItemType; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection; import com.gpl.rpg.AndorsTrail.view.ItemContainerAdapter; import android.app.Activity; @@ -30,6 +31,7 @@ import android.widget.AdapterView.OnItemClickListener; public final class HeroinfoActivity_Inventory extends Activity { private WorldContext world; private ViewContext view; + private TileCollection wornTiles; private Player player; private ItemContainer container; @@ -65,7 +67,8 @@ public final class HeroinfoActivity_Inventory extends Activity { } }); container = player.inventory; - inventoryListAdapter = new ItemContainerAdapter(this, world.tileStore, container); + wornTiles = world.tileManager.loadTilesFor(player.inventory, getResources()); + inventoryListAdapter = new ItemContainerAdapter(this, world.tileManager, container, wornTiles); inventoryList.setAdapter(inventoryListAdapter); heroinfo_stats_gold = (TextView) findViewById(R.id.heroinfo_stats_gold); @@ -155,7 +158,7 @@ public final class HeroinfoActivity_Inventory extends Activity { private void updateWornImage(ImageView view, int resourceIDEmptyImage, ItemType type) { if (type != null) { - world.tileStore.setImageViewTile(view, type); + world.tileManager.setImageViewTile(view, type, wornTiles); } else { view.setImageResource(resourceIDEmptyImage); } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Stats.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Stats.java index 0ed6112..9519a36 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Stats.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Stats.java @@ -53,7 +53,7 @@ public final class HeroinfoActivity_Stats extends Activity { setContentView(R.layout.heroinfo_stats); ImageView iv = (ImageView) findViewById(R.id.heroinfo_image); - iv.setImageBitmap(world.tileStore.getBitmap(player.actorTraits.iconID)); + world.tileManager.setImageViewTile(iv, player); ((TextView) findViewById(R.id.heroinfo_title)).setText(player.actorTraits.name); heroinfo_ap = (TextView) findViewById(R.id.heroinfo_ap); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java index 8eb4f11..7f6b715 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ItemInfoActivity.java @@ -48,7 +48,7 @@ public final class ItemInfoActivity extends Activity { setContentView(R.layout.iteminfo); ImageView img = (ImageView) findViewById(R.id.iteminfo_image); - world.tileStore.setImageViewTile(img, itemType); + world.tileManager.setImageViewTileForSingleItemType(img, itemType, getResources()); TextView tv = (TextView) findViewById(R.id.iteminfo_title); tv.setText(itemType.name); tv = (TextView) findViewById(R.id.iteminfo_category); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java index bc3c508..f5d0cd3 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/LevelUpActivity.java @@ -36,7 +36,8 @@ public final class LevelUpActivity extends Activity { final Resources res = getResources(); ImageView img = (ImageView) findViewById(R.id.levelup_image); - img.setImageBitmap(world.tileStore.getBitmap(player.actorTraits.iconID)); + world.tileManager.setImageViewTile(img, player); + TextView tv = (TextView) findViewById(R.id.levelup_description); tv.setText(res.getString(R.string.levelup_description, player.level+1)); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java index 41c7ec9..44ad7bb 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MainActivity.java @@ -138,7 +138,7 @@ public final class MainActivity extends Activity { case INTENTREQUEST_PREFERENCES: AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this); AndorsTrailPreferences.read(this, app.preferences); - world.tileStore.updatePreferences(app.preferences); + world.tileManager.updatePreferences(app.preferences); dpad.updateVisibility(app.preferences); break; case INTENTREQUEST_SAVEGAME: diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java index 3dce23d..5a0da2e 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterEncounterActivity.java @@ -43,7 +43,7 @@ public final class MonsterEncounterActivity extends Activity { tv.setText(getString(R.string.dialog_monsterencounter_message, difficulty)); ImageView iw = (ImageView) findViewById(R.id.monsterencounter_image); - iw.setImageBitmap(world.tileStore.getBitmap(monster.actorTraits.iconID)); + world.tileManager.setImageViewTile(iw, monster); Button b = (Button) findViewById(R.id.monsterencounter_attack); b.setOnClickListener(new OnClickListener() { diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java index 1d3a2d9..16cbf36 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/MonsterInfoActivity.java @@ -79,7 +79,7 @@ public final class MonsterInfoActivity extends Activity { } private void updateTitle(Monster monster) { - monsterinfo_image.setImageBitmap(world.tileStore.getBitmap(monster.actorTraits.iconID)); + world.tileManager.setImageViewTile(monsterinfo_image, monster); monsterinfo_title.setText(monster.actorTraits.name); monsterinfo_difficulty.setText(getMonsterDifficultyResource(world, monster)); } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java index 9cfc2af..b796d3b 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ShopActivity.java @@ -70,8 +70,8 @@ public final class ShopActivity extends TabActivity implements OnContainerItemCl npc.dropList.createRandomLoot(merchantLoot, player); container_buy = merchantLoot.items; - buyListAdapter = new ShopItemContainerAdapter(this, world.tileStore, player, container_buy, this, false); - sellListAdapter = new ShopItemContainerAdapter(this, world.tileStore, player, player.inventory, this, true); + buyListAdapter = new ShopItemContainerAdapter(this, world.tileManager, player, container_buy, this, false); + sellListAdapter = new ShopItemContainerAdapter(this, world.tileManager, player, player.inventory, this, true); shoplist_buy.setAdapter(buyListAdapter); shoplist_sell.setAdapter(sellListAdapter); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java index 4259b9d..47c5c1c 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/StartScreenActivity.java @@ -103,8 +103,8 @@ public final class StartScreenActivity extends Activity { } final Resources res = getResources(); - app.world.tileStore.setDensity(res); - app.world.tileStore.updatePreferences(app.preferences); + app.world.tileManager.setDensity(res); + app.world.tileManager.updatePreferences(app.preferences); app.setup.startResourceLoader(res, app.preferences); if (AndorsTrailApplication.DEVELOPMENT_FORCE_STARTNEWGAME) { diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/WorldContext.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/WorldContext.java index 3854e6e..3d12840 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/WorldContext.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/context/WorldContext.java @@ -3,6 +3,7 @@ package com.gpl.rpg.AndorsTrail.context; import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; import com.gpl.rpg.AndorsTrail.VisualEffectCollection; import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection; +import com.gpl.rpg.AndorsTrail.conversation.ConversationLoader; import com.gpl.rpg.AndorsTrail.model.ModelContainer; import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionTypeCollection; import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection; @@ -11,11 +12,12 @@ import com.gpl.rpg.AndorsTrail.model.item.DropListCollection; import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection; import com.gpl.rpg.AndorsTrail.model.map.MapCollection; import com.gpl.rpg.AndorsTrail.model.quest.QuestCollection; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; public class WorldContext { //Objectcollections - public final ConversationCollection conversations; + //public final ConversationCollection conversations; + public final ConversationLoader conversationLoader; public final ItemTypeCollection itemTypes; public final MonsterTypeCollection monsterTypes; public final VisualEffectCollection visualEffectTypes; @@ -25,31 +27,31 @@ public class WorldContext { public final SkillCollection skills; //Objectcollections - public final TileStore tileStore; + public final TileManager tileManager; //Model public final MapCollection maps; public ModelContainer model; public WorldContext() { - this.conversations = new ConversationCollection(); + this.conversationLoader = new ConversationLoader(); this.itemTypes = new ItemTypeCollection(); this.monsterTypes = new MonsterTypeCollection(); this.visualEffectTypes = new VisualEffectCollection(); this.dropLists = new DropListCollection(); - this.tileStore = new TileStore(); + this.tileManager = new TileManager(); this.maps = new MapCollection(); this.quests = new QuestCollection(); this.actorConditionsTypes = new ActorConditionTypeCollection(); this.skills = new SkillCollection(); } public WorldContext(WorldContext copy) { - this.conversations = copy.conversations; + this.conversationLoader = copy.conversationLoader; this.itemTypes = copy.itemTypes; this.monsterTypes = copy.monsterTypes; this.visualEffectTypes = copy.visualEffectTypes; this.dropLists = copy.dropLists; - this.tileStore = copy.tileStore; + this.tileManager = copy.tileManager; this.maps = copy.maps; this.quests = copy.quests; this.model = copy.model; @@ -61,7 +63,7 @@ public class WorldContext { } // Selftest method. Not part of the game logic. - public void verifyData() { + public void verifyData(ConversationCollection conversations) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { assert(itemTypes.getItemType("gold") != null); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java index 8ac65ea..6cd59d4 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/MovementController.java @@ -1,6 +1,7 @@ package com.gpl.rpg.AndorsTrail.controller; import android.content.res.Resources; +import android.os.AsyncTask; import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences; import com.gpl.rpg.AndorsTrail.context.ViewContext; @@ -9,10 +10,12 @@ import com.gpl.rpg.AndorsTrail.model.ModelContainer; import com.gpl.rpg.AndorsTrail.model.actor.Monster; import com.gpl.rpg.AndorsTrail.model.actor.Player; import com.gpl.rpg.AndorsTrail.model.item.Loot; +import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap; import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap; import com.gpl.rpg.AndorsTrail.model.map.MapObject; import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea; import com.gpl.rpg.AndorsTrail.model.map.TMXMapTranslator; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection; import com.gpl.rpg.AndorsTrail.util.Coord; import com.gpl.rpg.AndorsTrail.util.L; import com.gpl.rpg.AndorsTrail.util.TimedMessageTask; @@ -30,10 +33,30 @@ public final class MovementController implements TimedMessageTask.Callback { this.movementHandler = new TimedMessageTask(this, Constants.MINIMUM_INPUT_INTERVAL, false); } - public void placePlayerAt(int objectType, String mapName, String placeName, int offset_x, int offset_y) { - placePlayerAt(view.mainActivity.getResources(), world, objectType, mapName, placeName, offset_x, offset_y); - view.mainActivity.clearMessages(); - view.mainActivity.mainview.notifyMapChanged(); + public void placePlayerAt(final int objectType, final String mapName, final String placeName, final int offset_x, final int offset_y) { + + AsyncTask task = new AsyncTask() { + @Override + protected Void doInBackground(Void... arg0) { + stopMovement(); + + placePlayerAt(view.mainActivity.getResources(), world, objectType, mapName, placeName, offset_x, offset_y); + view.mainActivity.clearMessages(); + view.mainActivity.mainview.notifyMapChanged(); + + return null; + } + + @Override + protected void onPostExecute(Void result) { + super.onPostExecute(result); + stopMovement(); + view.gameRoundController.resume(); + } + + }; + view.gameRoundController.pause(); + task.execute(); } public static void placePlayerAt(final Resources res, final WorldContext world, int objectType, String mapName, String placeName, int offset_x, int offset_y) { @@ -51,8 +74,8 @@ public final class MovementController implements TimedMessageTask.Callback { final ModelContainer model = world.model; if (model.currentMap != null) model.currentMap.updateLastVisitTime(); + cacheCurrentMapData(res, world, newMap); model.currentMap = newMap; - loadCurrentTileMap(res, world); model.player.position.set(place.position.topLeft); model.player.position.x += Math.min(offset_x, place.position.size.width-1); model.player.position.y += Math.min(offset_y, place.position.size.height-1); @@ -241,8 +264,11 @@ public final class MovementController implements TimedMessageTask.Callback { } } - public static void loadCurrentTileMap(Resources res, WorldContext world) { - world.model.currentTileMap = TMXMapTranslator.readLayeredTileMap(res, world.tileStore, world.model.currentMap); + public static void cacheCurrentMapData(final Resources res, final WorldContext world, final PredefinedMap nextMap) { + LayeredTileMap mapTiles = TMXMapTranslator.readLayeredTileMap(res, world.tileManager.tileCache, nextMap); + TileCollection cachedTiles = world.tileManager.loadTilesFor(nextMap, mapTiles, world, res); + world.model.currentTileMap = mapTiles; + world.tileManager.currentMapTiles = cachedTiles; } private int movementDx; diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java index 5ff29bf..f290862 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java @@ -1,5 +1,6 @@ package com.gpl.rpg.AndorsTrail.conversation; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map.Entry; @@ -44,8 +45,8 @@ public final class ConversationCollection { return phrases.get(id); } - public void initialize(ConversationListParser parser, String input) { - parser.parseRows(input, phrases); + public Collection initialize(ConversationListParser parser, String input) { + return parser.parseRows(input, phrases); } // Selftest method. Not part of the game logic. diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationLoader.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationLoader.java new file mode 100644 index 0000000..6804116 --- /dev/null +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationLoader.java @@ -0,0 +1,27 @@ +package com.gpl.rpg.AndorsTrail.conversation; + +import java.util.Collection; +import java.util.HashMap; + +import android.content.res.Resources; + +import com.gpl.rpg.AndorsTrail.resource.parsers.ConversationListParser; + +public final class ConversationLoader { + private final HashMap resourceIDsPerPhraseID = new HashMap(); + + public void addIDs(int resourceId, Collection ids) { + for(String s : ids) resourceIDsPerPhraseID.put(s, resourceId); + } + + public Phrase loadPhrase(String phraseID, ConversationCollection conversationCollection, Resources r) { + Phrase phrase = conversationCollection.getPhrase(phraseID); + if (phrase != null) return phrase; + + ConversationListParser conversationListParser = new ConversationListParser(); + int resourceID = resourceIDsPerPhraseID.get(phraseID); + conversationCollection.initialize(conversationListParser, r.getString(resourceID)); + + return conversationCollection.getPhrase(phraseID); + } +} diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.java index f359966..b3befd6 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/MonsterTypeCollection.java @@ -47,11 +47,11 @@ public final class MonsterTypeCollection { } // Selftest method. Not part of the game logic. - public void verifyData(WorldContext world) { + public void verifyData(WorldContext world, ConversationCollection conversations) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { for (MonsterType t : monsterTypesById.values()) { if (t.phraseID != null) { - if (!world.conversations.isValidPhraseID(t.phraseID)) { + if (!conversations.isValidPhraseID(t.phraseID)) { L.log("WARNING: Cannot find phrase \"" + t.phraseID + "\" for MonsterType \"" + t.id + "\"."); } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java index f52967f..d8f0cb7 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java @@ -17,7 +17,7 @@ import com.gpl.rpg.AndorsTrail.model.item.Inventory; import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection; import com.gpl.rpg.AndorsTrail.model.item.Loot; import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; import com.gpl.rpg.AndorsTrail.util.Coord; import com.gpl.rpg.AndorsTrail.util.Range; import com.gpl.rpg.AndorsTrail.util.Size; @@ -39,7 +39,7 @@ public final class Player extends Actor { public int availableSkillIncreases = 0; public Player() { - super(new ActorTraits(TileStore.CHAR_HERO, new Size(1, 1), new CombatTraits(), DEFAULT_PLAYER_MOVECOST, null), true); + super(new ActorTraits(TileManager.CHAR_HERO, new Size(1, 1), new CombatTraits(), DEFAULT_PLAYER_MOVECOST, null), true); this.lastPosition = new Coord(); this.nextPosition = new Coord(); this.levelExperience = new Range(); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.java index 924f8f0..95f44a4 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemContainer.java @@ -30,7 +30,6 @@ public class ItemContainer { this.quantity = initialQuantity; } - // ====== PARCELABLE =================================================================== public ItemEntry(DataInputStream src, WorldContext world, int fileversion) throws IOException { diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemType.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemType.java index cdfa7e0..f723cd3 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemType.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/ItemType.java @@ -1,7 +1,7 @@ package com.gpl.rpg.AndorsTrail.model.item; import com.gpl.rpg.AndorsTrail.model.CombatTraits; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; public final class ItemType { public static final int CATEGORY_WEAPON = 0; @@ -146,13 +146,13 @@ public final class ItemType { public int getOverlayTileID() { switch (displayType) { case ItemType.DISPLAYTYPE_QUEST: - return TileStore.iconID_selection_yellow; + return TileManager.iconID_selection_yellow; case ItemType.DISPLAYTYPE_LEGENDARY: - return TileStore.iconID_selection_green; + return TileManager.iconID_selection_green; case ItemType.DISPLAYTYPE_EXTRAORDINARY: - return TileStore.iconID_selection_blue; + return TileManager.iconID_selection_blue; case ItemType.DISPLAYTYPE_RARE: - return TileStore.iconID_selection_purple; + return TileManager.iconID_selection_purple; } return -1; } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java index a96b75e..7d253aa 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/LayeredTileMap.java @@ -1,5 +1,7 @@ package com.gpl.rpg.AndorsTrail.model.map; +import java.util.Collection; + import com.gpl.rpg.AndorsTrail.util.Size; public final class LayeredTileMap { @@ -9,12 +11,14 @@ public final class LayeredTileMap { public final Size size; public final MapLayer[] layers; + public final Collection usedTileIDs; - public LayeredTileMap(Size size, MapLayer[] layers) { + public LayeredTileMap(Size size, MapLayer[] layers, Collection usedTileIDs) { this.size = size; assert(size.width > 0); assert(size.height > 0); assert(layers.length == 3); this.layers = layers; + this.usedTileIDs = usedTileIDs; } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java index 820a227..e906ce5 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/MapCollection.java @@ -9,6 +9,7 @@ import java.util.HashSet; import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; import com.gpl.rpg.AndorsTrail.context.WorldContext; +import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection; import com.gpl.rpg.AndorsTrail.model.item.DropList; import com.gpl.rpg.AndorsTrail.util.L; @@ -34,7 +35,7 @@ public final class MapCollection { } // Selftest method. Not part of the game logic. - public void verifyData(WorldContext world) { + public void verifyData(WorldContext world, ConversationCollection conversations) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { for (PredefinedMap m : predefinedMaps) { for (MapObject o : m.eventObjects) { @@ -83,13 +84,13 @@ public final class MapCollection { L.log("WARNING: Map \"" + m.name + "\" contains keyarea without phraseid."); continue; } - world.conversations.getPhrase(o.id); // Will warn inside if not available. + conversations.getPhrase(o.id); // Will warn inside if not available. } else if (o.type == MapObject.MAPEVENT_SIGN) { if (o.id == null || o.id.length() <= 0) { L.log("WARNING: Map \"" + m.name + "\" contains sign without phraseid."); continue; } - world.conversations.getPhrase(o.id); // Will warn inside if not available. + conversations.getPhrase(o.id); // Will warn inside if not available. } else if (o.type == MapObject.MAPEVENT_REST) { if (o.id == null || o.id.length() <= 0) { L.log("WARNING: Map \"" + m.name + "\" contains rest area without id."); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java index 8f27d9e..bb192bb 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/map/TMXMapTranslator.java @@ -2,6 +2,7 @@ package com.gpl.rpg.AndorsTrail.model.map; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; import com.gpl.rpg.AndorsTrail.model.actor.MonsterType; @@ -17,7 +18,7 @@ import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXProperty; import com.gpl.rpg.AndorsTrail.model.map.TMXMapFileParser.TMXTileSet; import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress; import com.gpl.rpg.AndorsTrail.resource.DynamicTileLoader; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileCache; import com.gpl.rpg.AndorsTrail.util.Coord; import com.gpl.rpg.AndorsTrail.util.CoordRect; import com.gpl.rpg.AndorsTrail.util.L; @@ -33,9 +34,9 @@ public final class TMXMapTranslator { maps.add(TMXMapFileParser.read(r, xmlResourceId, name)); } - public static LayeredTileMap readLayeredTileMap(Resources res, TileStore tileStore, PredefinedMap map) { + public static LayeredTileMap readLayeredTileMap(Resources res, TileCache tileCache, PredefinedMap map) { TMXLayerMap resultMap = TMXMapFileParser.readLayeredTileMap(res, map.xmlResourceId, map.name); - return transformMap(resultMap, tileStore); + return transformMap(resultMap, tileCache); } public ArrayList transformMaps(DynamicTileLoader tileLoader, MonsterTypeCollection monsterTypes, DropListCollection dropLists) { @@ -192,7 +193,7 @@ public final class TMXMapTranslator { } - private static LayeredTileMap transformMap(TMXLayerMap map, TileStore tileStore) { + private static LayeredTileMap transformMap(TMXLayerMap map, TileCache tileCache) { final Size mapSize = new Size(map.width, map.height); final MapLayer[] layers = new MapLayer[] { new MapLayer(mapSize) @@ -200,6 +201,7 @@ public final class TMXMapTranslator { ,new MapLayer(mapSize) }; Tile tile = new Tile(); + HashSet usedTileIDs = new HashSet(); for (TMXLayer layer : map.layers) { int ixMapLayer = -2; String layerName = layer.name; @@ -223,11 +225,13 @@ public final class TMXMapTranslator { if (!getTile(map, gid, tile)) continue; - layers[ixMapLayer].tiles[x][y] = tileStore.getTileID(tile.tilesetName, tile.localId); + int tileID = tileCache.getTileID(tile.tilesetName, tile.localId); + layers[ixMapLayer].tiles[x][y] = tileID; + usedTileIDs.add(tileID); } } } - return new LayeredTileMap(mapSize, layers); + return new LayeredTileMap(mapSize, layers, usedTileIDs); } private static boolean getTile(final TMXLayerMap map, final int gid, final Tile dest) { diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.java index d3dce67..f360cf5 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/DynamicTileLoader.java @@ -1,45 +1,47 @@ package com.gpl.rpg.AndorsTrail.resource; import java.util.HashMap; +import java.util.Map.Entry; import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; +import com.gpl.rpg.AndorsTrail.resource.tiles.ResourceFileTileset; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileCache; import com.gpl.rpg.AndorsTrail.util.L; import com.gpl.rpg.AndorsTrail.util.Size; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import android.graphics.BitmapFactory.Options; - public final class DynamicTileLoader { - private final TileStore store; - private final Resources r; + private final TileCache tileCache; - private final HashMap preparedTilesetsByResourceId = new HashMap(); - private final HashMap preparedTilesetsByResourceName = new HashMap(); - private int allocatedTiles = 0; + private final HashMap preparedTilesetsByResourceId = new HashMap(); + private final HashMap preparedTilesetsByResourceName = new HashMap(); private int currentTileStoreIndex; - public DynamicTileLoader(TileStore store, Resources r) { - this.store = store; - this.r = r; + private static final class ResourceFileTilesetLoadList { + public final ResourceFileTileset tileset; + public final HashMap tileIDsToLoadPerLocalID = new HashMap(); + public ResourceFileTilesetLoadList(ResourceFileTileset tileset) { + this.tileset = tileset; + } + } + + public DynamicTileLoader(TileCache tileCache) { + this.tileCache = tileCache; initialize(); } private void initialize() { - allocatedTiles = 0; preparedTilesetsByResourceId.clear(); preparedTilesetsByResourceName.clear(); - currentTileStoreIndex = store.bitmaps.length; + currentTileStoreIndex = tileCache.getMaxTileID(); } public void prepareTileset(int resourceId, String tilesetName, Size numTiles, Size destinationTileSize) { - TilesetBitmap b = new TilesetBitmap(resourceId, tilesetName, numTiles, destinationTileSize); - preparedTilesetsByResourceId.put(resourceId, b); - preparedTilesetsByResourceName.put(tilesetName, b); + ResourceFileTileset b = new ResourceFileTileset(resourceId, tilesetName, numTiles, destinationTileSize); + ResourceFileTilesetLoadList loadList = new ResourceFileTilesetLoadList(b); + preparedTilesetsByResourceId.put(resourceId, loadList); + preparedTilesetsByResourceName.put(tilesetName, loadList); } - private TilesetBitmap getTilesetBitmap(int tilesetImageResourceID) { + private ResourceFileTilesetLoadList getTilesetBitmap(int tilesetImageResourceID) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { if (!preparedTilesetsByResourceId.containsKey(tilesetImageResourceID)) { L.log("WARNING: Cannot load tileset " + tilesetImageResourceID); @@ -48,7 +50,7 @@ public final class DynamicTileLoader { } return preparedTilesetsByResourceId.get(tilesetImageResourceID); } - private TilesetBitmap getTilesetBitmap(String tilesetName) { + private ResourceFileTilesetLoadList getTilesetBitmap(String tilesetName) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { if (!preparedTilesetsByResourceName.containsKey(tilesetName)) { L.log("WARNING: Cannot load tileset " + tilesetName); @@ -58,123 +60,39 @@ public final class DynamicTileLoader { return preparedTilesetsByResourceName.get(tilesetName); } - public int prepareTileID(int tilesetImageResourceID, int localId) { - TilesetBitmap b = getTilesetBitmap(tilesetImageResourceID); - return prepareTileID(b, localId); + public int prepareTileID(int tilesetImageResourceID, int localID) { + ResourceFileTilesetLoadList b = getTilesetBitmap(tilesetImageResourceID); + return prepareTileID(b, localID); } - public int prepareTileID(String tilesetName, int localId) { - TilesetBitmap b = getTilesetBitmap(tilesetName); - return prepareTileID(b, localId); + public int prepareTileID(String tilesetName, int localID) { + ResourceFileTilesetLoadList b = getTilesetBitmap(tilesetName); + return prepareTileID(b, localID); } public Size getTilesetSize(String tilesetName) { - TilesetBitmap b = getTilesetBitmap(tilesetName); - return b.destinationTileSize; + ResourceFileTilesetLoadList b = getTilesetBitmap(tilesetName); + return b.tileset.destinationTileSize; } - private int prepareTileID(TilesetBitmap tileset, int localId) { - int tileStoreIndex = 0; - if (tileset.tilesToLoad.containsKey(localId)) { - tileStoreIndex = tileset.tilesToLoad.get(localId); + private int prepareTileID(ResourceFileTilesetLoadList tileset, int localID) { + int tileID = 0; + if (tileset.tileIDsToLoadPerLocalID.containsKey(localID)) { + tileID = tileset.tileIDsToLoadPerLocalID.get(localID); } else { - tileStoreIndex = currentTileStoreIndex; ++currentTileStoreIndex; - ++allocatedTiles; - tileset.tilesToLoad.put(localId, tileStoreIndex); - } - return tileStoreIndex; - } - - public void flush() { - store.allocateTiles(allocatedTiles); - - for (TilesetBitmap b : preparedTilesetsByResourceId.values()) { - if (b.tilesToLoad.isEmpty()) { - if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { - L.log("OPTIMIZE: Tileset " + b.tilesetName + " does not contain any loaded tiles. The file could be removed from the project."); - } - continue; - } - - boolean recycle = true; - Bitmap tilesetImage = createTilesetImage(b); - for (int localId : b.tilesToLoad.keySet()) { - int tileStoreIndex = b.tilesToLoad.get(localId); - Bitmap tile = createTileFromTileset(tilesetImage, b, localId); - if (tile == tilesetImage) recycle = false; - - store.setBitmap(tileStoreIndex, tile, b.tilesetName, localId); - } - if (recycle) tilesetImage.recycle(); + tileID = currentTileStoreIndex; + tileset.tileIDsToLoadPerLocalID.put(localID, tileID); } - - initialize(); + return tileID; } - private Bitmap createTilesetImage(TilesetBitmap b) { - //return BitmapFactory.decodeResource(r, b.resourceId); - Options o = new Options(); - o.inScaled = false; - Bitmap sourceImage = BitmapFactory.decodeResource(r, b.resourceId, o); - sourceImage.setDensity(Bitmap.DENSITY_NONE); - b.calculateFromSourceImageSize(sourceImage.getWidth(), sourceImage.getHeight()); - return sourceImage; - } - - private Bitmap createTileFromTileset(Bitmap tilesetImage, TilesetBitmap tileset, int localId) { - final int x = localId % tileset.numTiles.width; - final int y = (localId - x) / tileset.numTiles.width; - final int left = x * tileset.sourceTileSize.width; - final int top = y * tileset.sourceTileSize.height; - if (tileset.scale != null) { - return Bitmap.createBitmap(tilesetImage, left, top, tileset.sourceTileSize.width, tileset.sourceTileSize.height, tileset.scale, true); - } else { - return Bitmap.createBitmap(tilesetImage, left, top, tileset.sourceTileSize.width, tileset.sourceTileSize.height); - } - } - public static int measureBitmapWidth(Resources r, int resourceId) { - Bitmap b = BitmapFactory.decodeResource(r, resourceId); - int width = b.getWidth(); - b.recycle(); - return width; - } - - private static class TilesetBitmap { - public final int resourceId; - public final String tilesetName; - public final Size destinationTileSize; - public final Size numTiles; - public Size sourceTileSize; - public Matrix scale; - - public HashMap tilesToLoad = new HashMap(); - - public TilesetBitmap(int resourceId, String tilesetName, Size numTiles, Size destinationTileSize) { - this.resourceId = resourceId; - this.tilesetName = tilesetName; - this.destinationTileSize = destinationTileSize; - this.numTiles = numTiles; - } - - public void calculateFromSourceImageSize(final int sourceWidth, final int sourceHeight) { - sourceTileSize = new Size( - sourceWidth / numTiles.width - ,sourceHeight / numTiles.height - ); - - if (destinationTileSize.width == sourceTileSize.width && destinationTileSize.height == sourceTileSize.height) { - scale = null; - } else { - scale = new Matrix(); - scale.postScale( - ((float) destinationTileSize.width) / sourceTileSize.width - ,((float) destinationTileSize.height) / sourceTileSize.height - ); - - if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { - L.log("OPTIMIZE: Tileset " + tilesetName + " will be resized from " + sourceTileSize.toString() + " to " + destinationTileSize.toString()); - } + public void flush() { + tileCache.allocateMaxTileID(currentTileStoreIndex); + for(Entry e : preparedTilesetsByResourceId.entrySet()) { + ResourceFileTileset tileset = e.getValue().tileset; + for(Entry tile : e.getValue().tileIDsToLoadPerLocalID.entrySet()) { + tileCache.setTile(tile.getValue(), tileset, tile.getKey()); } } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceFileTokenizer.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceFileTokenizer.java index d9b3b76..e26f9c1 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceFileTokenizer.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceFileTokenizer.java @@ -1,7 +1,9 @@ package com.gpl.rpg.AndorsTrail.resource; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -38,7 +40,8 @@ public class ResourceFileTokenizer { } } - public void tokenizeRows(String input, HashMap dest, ResourceObjectParser> parser) { + public Collection tokenizeRows(String input, HashMap dest, ResourceObjectParser> parser) { + HashSet ids = new HashSet(); ArrayList> objects = new ArrayList>(); tokenizeRows(input, objects, parser); @@ -52,7 +55,9 @@ public class ResourceFileTokenizer { } } dest.put(id, o.second); + ids.add(id); } + return ids; } private void tokenizeRow(String input, ArrayList dest, ResourceObjectParser parser) { @@ -89,8 +94,8 @@ public class ResourceFileTokenizer { super(columns); } - public void parseRows(String input, HashMap dest) { - tokenizeRows(input, dest, this); + public Collection parseRows(String input, HashMap dest) { + return tokenizeRows(input, dest, this); } } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.java index b58a6d6..69f73e3 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/ResourceLoader.java @@ -1,8 +1,11 @@ package com.gpl.rpg.AndorsTrail.resource; +import java.util.Collection; + import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; import com.gpl.rpg.AndorsTrail.R; import com.gpl.rpg.AndorsTrail.context.WorldContext; +import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection; import com.gpl.rpg.AndorsTrail.model.map.TMXMapTranslator; import com.gpl.rpg.AndorsTrail.resource.parsers.ActorConditionsTypeParser; import com.gpl.rpg.AndorsTrail.resource.parsers.ConversationListParser; @@ -38,10 +41,9 @@ public final class ResourceLoader { long start = System.currentTimeMillis(); taskStart = start; - final TileStore tiles = world.tileStore; - final int mTileSize = tiles.tileSize; + final int mTileSize = world.tileManager.tileSize; - DynamicTileLoader loader = new DynamicTileLoader(tiles, r); + DynamicTileLoader loader = new DynamicTileLoader(world.tileManager.tileCache); prepareTilesets(loader, mTileSize); if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("prepareTilesets"); @@ -58,6 +60,11 @@ public final class ResourceLoader { /*tiles.iconID_selection_green = */loader.prepareTileID(R.drawable.ui_selections, 4); + // ======================================================================== + // Load effects + world.visualEffectTypes.initialize(loader); + if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("VisualEffectLoader"); + // ======================================================================== // Load skills world.skills.initialize(); @@ -72,6 +79,11 @@ public final class ResourceLoader { } if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("ActorConditionsTypeParser"); + // ======================================================================== + // Load preloaded tiles + loader.flush(); + world.tileManager.loadPreloadedTiles(r); + // ======================================================================== // Load items @@ -110,11 +122,13 @@ public final class ResourceLoader { // Load conversations final ConversationListParser conversationListParser = new ConversationListParser(); final TypedArray conversationsListsToLoad = r.obtainTypedArray(conversationsListsResourceId); + ConversationCollection conversations = new ConversationCollection(); for (int i = 0; i < conversationsListsToLoad.length(); ++i) { - world.conversations.initialize(conversationListParser, conversationsListsToLoad.getString(i)); + Collection ids = conversations.initialize(conversationListParser, conversationsListsToLoad.getString(i)); + world.conversationLoader.addIDs(conversationsListsToLoad.getResourceId(i, -1), ids); } if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { - world.conversations.verifyData(); + conversations.verifyData(); } if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("ConversationListParser"); @@ -128,7 +142,7 @@ public final class ResourceLoader { } if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { - world.monsterTypes.verifyData(world); + world.monsterTypes.verifyData(world, conversations); } if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("MonsterTypeParser"); @@ -148,15 +162,10 @@ public final class ResourceLoader { if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("mapReader.transformMaps"); if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { - world.maps.verifyData(world); + world.maps.verifyData(world, conversations); } - // ======================================================================== - // Load effects - world.visualEffectTypes.initialize(loader); - if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("VisualEffectLoader"); - // ======================================================================== // Load graphics resources (icons and tiles) loader.flush(); @@ -166,7 +175,7 @@ public final class ResourceLoader { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { - world.verifyData(); + world.verifyData(conversations); } if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("world.verifyData()"); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/TileStore.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/TileStore.java deleted file mode 100644 index 78a538b..0000000 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/TileStore.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.gpl.rpg.AndorsTrail.resource; - -import java.util.HashMap; - -import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences; -import com.gpl.rpg.AndorsTrail.model.item.ItemType; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.widget.ImageView; - -public final class TileStore { - public static final int CHAR_HERO = 1; - public static final int iconID_selection_red = 2; - public static final int iconID_selection_yellow = 3; - public static final int iconID_attackselect = iconID_selection_red; - public static final int iconID_moveselect = iconID_selection_yellow; - public static final int iconID_groundbag = 4; - public static final int iconID_boxopened = 5; - public static final int iconID_boxclosed = 6; - public static final int iconID_shop = iconID_groundbag; - public static final int iconID_selection_blue = 7; - public static final int iconID_selection_purple = 8; - public static final int iconID_selection_green = 9; - - - private float density; - public int tileSize; - - public int viewTileSize; - public float scale; - - public void setDensity(Resources r) { - density = r.getDisplayMetrics().density; - tileSize = (int) (32 * density); - } - - public void updatePreferences(AndorsTrailPreferences prefs) { - scale = prefs.scalingFactor; - viewTileSize = (int) (tileSize * prefs.scalingFactor); - } - - //TODO: should be final. - public Bitmap[] bitmaps = new Bitmap[1]; - private HashMap> tilesetLocalIDsToTileID = new HashMap>(); - - public void allocateTiles(int tilecount) { - if (tilecount <= 0) return; - - Bitmap[] oldArray = bitmaps; - bitmaps = new Bitmap[bitmaps.length + tilecount]; - System.arraycopy(oldArray, 0, bitmaps, 0, oldArray.length); - } - - public Bitmap getBitmap(int tileID) { - return bitmaps[tileID]; - } - public int getTileID(String tilesetName, int localId) { - return tilesetLocalIDsToTileID.get(tilesetName).get(localId); - } - - public void setBitmap(int tileID, Bitmap bitmap, String tilesetName, int localId) { - bitmaps[tileID] = bitmap; - if (!tilesetLocalIDsToTileID.containsKey(tilesetName)) tilesetLocalIDsToTileID.put(tilesetName, new HashMap()); - tilesetLocalIDsToTileID.get(tilesetName).put(localId, tileID); - } - - public void setImageViewTile(ImageView imageView, ItemType itemType) { - final Bitmap icon = getBitmap(itemType.iconID); - final int overlayIconID = itemType.getOverlayTileID(); - if (overlayIconID != -1) { - imageView.setImageDrawable( - new LayerDrawable(new Drawable[] { - new BitmapDrawable(getBitmap(overlayIconID)) - ,new BitmapDrawable(icon) - }) - ); - } else { - imageView.setImageBitmap(icon); - } - } -} diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/ResourceFileTileset.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/ResourceFileTileset.java new file mode 100644 index 0000000..f60c50c --- /dev/null +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/ResourceFileTileset.java @@ -0,0 +1,47 @@ +package com.gpl.rpg.AndorsTrail.resource.tiles; + +import android.graphics.Matrix; + +import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; +import com.gpl.rpg.AndorsTrail.util.L; +import com.gpl.rpg.AndorsTrail.util.Size; + +public final class ResourceFileTileset { + public final int resourceID; + public final String tilesetName; + public final Size destinationTileSize; + public final Size numTiles; + public Size sourceTileSize; + public Matrix scale; + + public ResourceFileTileset(int resourceID, String tilesetName, Size numTiles, Size destinationTileSize) { + this.resourceID = resourceID; + this.tilesetName = tilesetName; + this.destinationTileSize = destinationTileSize; + this.numTiles = numTiles; + } + + @Override public int hashCode() { return resourceID; } + + public void calculateFromSourceImageSize(final int sourceWidth, final int sourceHeight) { + sourceTileSize = new Size( + sourceWidth / numTiles.width + ,sourceHeight / numTiles.height + ); + + if (destinationTileSize.width == sourceTileSize.width && destinationTileSize.height == sourceTileSize.height) { + scale = null; + } else { + scale = new Matrix(); + scale.postScale( + ((float) destinationTileSize.width) / sourceTileSize.width + ,((float) destinationTileSize.height) / sourceTileSize.height + ); + + if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { + L.log("OPTIMIZE: Tileset " + tilesetName + " will be resized from " + sourceTileSize.toString() + " to " + destinationTileSize.toString()); + } + } + } + +} diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCache.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCache.java new file mode 100644 index 0000000..5948179 --- /dev/null +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCache.java @@ -0,0 +1,126 @@ +package com.gpl.rpg.AndorsTrail.resource.tiles; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map.Entry; + +import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; +import com.gpl.rpg.AndorsTrail.util.L; + +import android.content.res.Resources; +import android.graphics.Bitmap; + +public final class TileCache { + + private final ReferenceQueue gcQueue = new ReferenceQueue(); + private ResourceFileTile[] resourceTiles = new ResourceFileTile[1]; + private HashMap> tileIDsPerTilesetAndLocalID = new HashMap>(); + + public int getMaxTileID() { return resourceTiles.length-1; } + public void allocateMaxTileID(int maxTileID) { + if (maxTileID <= 0) return; + + ResourceFileTile[] oldArray = resourceTiles; + resourceTiles = new ResourceFileTile[maxTileID+1]; + System.arraycopy(oldArray, 0, resourceTiles, 0, oldArray.length); + } + public void setTile(int tileID, ResourceFileTileset tileset, int localID) { + if (resourceTiles[tileID] == null) resourceTiles[tileID] = new ResourceFileTile(tileset, localID); + HashMap tileIDsPerLocalID = tileIDsPerTilesetAndLocalID.get(tileset.tilesetName); + if (tileIDsPerLocalID == null) { + tileIDsPerLocalID = new HashMap(); + tileIDsPerTilesetAndLocalID.put(tileset.tilesetName, tileIDsPerLocalID); + } + tileIDsPerLocalID.put(localID, tileID); + } + public int getTileID(String tileSetName, int localID) { + return tileIDsPerTilesetAndLocalID.get(tileSetName).get(localID); + } + + private static final class ResourceFileTile { + public final ResourceFileTileset tileset; + public final int localID; + public SoftReference bitmap; + public ResourceFileTile(ResourceFileTileset tileset, int localID) { + this.tileset = tileset; + this.localID = localID; + } + } + + private void cleanQueue() { + System.gc(); + Reference ref; + while ((ref = gcQueue.poll()) != null) { + Bitmap b = ref.get(); + if (b != null) b.recycle(); + } + } + + public TileCollection loadTilesFor(Collection iconIDs, Resources r) { return loadTilesFor(iconIDs, r, null); } + public TileCollection loadTilesFor(Collection iconIDs, Resources r, TileCollection result) { + cleanQueue(); + int maxTileID = 0; + HashMap> tilesToLoadPerSourceFile = new HashMap>(); + for(int tileID : iconIDs) { + ResourceFileTile tile = resourceTiles[tileID]; + HashMap tiles = tilesToLoadPerSourceFile.get(tile.tileset); + if (tiles == null) { + tiles = new HashMap(); + tilesToLoadPerSourceFile.put(tile.tileset, tiles); + } + tiles.put(tileID, tile); + maxTileID = Math.max(maxTileID, tileID); + } + + if (result == null) result = new TileCollection(maxTileID); + for(Entry> e : tilesToLoadPerSourceFile.entrySet()) { + TileCutter cutter = null; + + for(Entry j : e.getValue().entrySet()) { + int tileID = j.getKey(); + ResourceFileTile tile = j.getValue(); + + Bitmap bitmap = null; + if (tile.bitmap != null) bitmap = tile.bitmap.get(); + + if (bitmap == null) { + if (cutter == null) { + if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) { + L.log("Loading tiles from tileset " + e.getKey().tilesetName); + } + cutter = new TileCutter(e.getKey(), r); + } + + bitmap = cutter.createTile(tile.localID); + tile.bitmap = new SoftReference(bitmap, gcQueue); + } + result.setBitmap(tileID, bitmap); + } + + if (cutter != null) cutter.recycle(); + } + cleanQueue(); + return result; + } + + public Bitmap loadSingleTile(int tileID, Resources r) { + cleanQueue(); + ResourceFileTile tile = resourceTiles[tileID]; + if (tile.bitmap != null) { + Bitmap bitmap = tile.bitmap.get(); + if (bitmap != null) return bitmap; + } + + if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) { + L.log("Loading single tile from tileset " + tile.tileset.tilesetName); + } + TileCutter cutter = new TileCutter(tile.tileset, r); + Bitmap result = cutter.createTile(tile.localID); + cutter.recycle(); + tile.bitmap = new SoftReference(result, gcQueue); + return result; + } +} diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCollection.java new file mode 100644 index 0000000..de3563e --- /dev/null +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCollection.java @@ -0,0 +1,19 @@ +package com.gpl.rpg.AndorsTrail.resource.tiles; + +import android.graphics.Bitmap; + +public class TileCollection { + public final Bitmap[] bitmaps; + + public TileCollection(int maxTileID) { + bitmaps = new Bitmap[maxTileID+1]; + } + + public Bitmap getBitmap(int tileID) { + return bitmaps[tileID]; + } + + public void setBitmap(int tileID, Bitmap bitmap) { + bitmaps[tileID] = bitmap; + } +} diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCutter.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCutter.java new file mode 100644 index 0000000..e4d4685 --- /dev/null +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileCutter.java @@ -0,0 +1,53 @@ +package com.gpl.rpg.AndorsTrail.resource.tiles; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapFactory.Options; + +public class TileCutter { + private final ResourceFileTileset sourceFile; + private final Bitmap tilesetImage; + private boolean recycle = true; + + public TileCutter(ResourceFileTileset sourceFile, Resources r) { + this.sourceFile = sourceFile; + this.tilesetImage = createTilesetImage(r); + } + + private Bitmap createTilesetImage(Resources r) { + //return BitmapFactory.decodeResource(r, b.resourceId); + Options o = new Options(); + o.inScaled = false; + Bitmap sourceImage = BitmapFactory.decodeResource(r, sourceFile.resourceID, o); + sourceImage.setDensity(Bitmap.DENSITY_NONE); + sourceFile.calculateFromSourceImageSize(sourceImage.getWidth(), sourceImage.getHeight()); + return sourceImage; + } + + public Bitmap createTile(int localID) { + final int x = localID % sourceFile.numTiles.width; + final int y = (localID - x) / sourceFile.numTiles.width; + final int left = x * sourceFile.sourceTileSize.width; + final int top = y * sourceFile.sourceTileSize.height; + Bitmap result; + if (sourceFile.scale != null) { + result = Bitmap.createBitmap(tilesetImage, left, top, sourceFile.sourceTileSize.width, sourceFile.sourceTileSize.height, sourceFile.scale, true); + } else { + result = Bitmap.createBitmap(tilesetImage, left, top, sourceFile.sourceTileSize.width, sourceFile.sourceTileSize.height); + } + if (result == tilesetImage) recycle = false; + return result; + } + + public void recycle() { + if (recycle) tilesetImage.recycle(); + } + + public static int measureBitmapWidth(Resources r, int resourceID) { + Bitmap b = BitmapFactory.decodeResource(r, resourceID); + int width = b.getWidth(); + b.recycle(); + return width; + } +} diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileManager.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileManager.java new file mode 100644 index 0000000..7b7a1af --- /dev/null +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/tiles/TileManager.java @@ -0,0 +1,136 @@ +package com.gpl.rpg.AndorsTrail.resource.tiles; + +import java.util.HashSet; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.widget.ImageView; + +import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences; +import com.gpl.rpg.AndorsTrail.context.WorldContext; +import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionType; +import com.gpl.rpg.AndorsTrail.model.actor.Monster; +import com.gpl.rpg.AndorsTrail.model.actor.Player; +import com.gpl.rpg.AndorsTrail.model.item.Inventory; +import com.gpl.rpg.AndorsTrail.model.item.ItemContainer; +import com.gpl.rpg.AndorsTrail.model.item.ItemType; +import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry; +import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap; +import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea; +import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap; + +public final class TileManager { + public static final int CHAR_HERO = 1; + public static final int iconID_selection_red = 2; + public static final int iconID_selection_yellow = 3; + public static final int iconID_attackselect = iconID_selection_red; + public static final int iconID_moveselect = iconID_selection_yellow; + public static final int iconID_groundbag = 4; + public static final int iconID_boxopened = 5; + public static final int iconID_boxclosed = 6; + public static final int iconID_shop = iconID_groundbag; + public static final int iconID_selection_blue = 7; + public static final int iconID_selection_purple = 8; + public static final int iconID_selection_green = 9; + + private float density; + public int tileSize; + + public int viewTileSize; + public float scale; + + + public final TileCache tileCache = new TileCache(); + public final TileCollection preloadedTiles = new TileCollection(72); + public TileCollection currentMapTiles; + private final HashSet preloadedTileIDs = new HashSet(); + + + public TileCollection loadTilesFor(ItemContainer container, Resources r) { + HashSet iconIDs = new HashSet(); + for(ItemEntry i : container.items) { + iconIDs.add(i.itemType.iconID); + } + return tileCache.loadTilesFor(iconIDs, r); + } + + public TileCollection loadTilesFor(Inventory inventory, Resources r) { + HashSet iconIDs = new HashSet(); + for(ItemEntry i : inventory.items) { + iconIDs.add(i.itemType.iconID); + } + for(ItemType t : inventory.wear) { + if (t != null) iconIDs.add(t.iconID); + } + return tileCache.loadTilesFor(iconIDs, r); + } + + public TileCollection loadTilesFor(PredefinedMap map, LayeredTileMap tileMap, WorldContext world, Resources r) { + HashSet iconIDs = new HashSet(); + for(MonsterSpawnArea a : map.spawnAreas) { + for(String monsterTypeID : a.monsterTypeIDs) { + iconIDs.add(world.monsterTypes.getMonsterType(monsterTypeID).iconID); + } + } + iconIDs.addAll(tileMap.usedTileIDs); + + TileCollection result = tileCache.loadTilesFor(iconIDs, r); + for(int i : preloadedTileIDs) { + result.setBitmap(i, preloadedTiles.getBitmap(i)); + } + return result; + } + + public void setDensity(Resources r) { + density = r.getDisplayMetrics().density; + tileSize = (int) (32 * density); + } + + public void updatePreferences(AndorsTrailPreferences prefs) { + scale = prefs.scalingFactor; + viewTileSize = (int) (tileSize * prefs.scalingFactor); + } + + + + public void setImageViewTile(ImageView imageView, Monster monster) { setImageViewTileForMonster(imageView, monster.actorTraits.iconID); } + public void setImageViewTile(ImageView imageView, Player player) { setImageViewTileForPlayer(imageView, player.actorTraits.iconID); } + public void setImageViewTileForMonster(ImageView imageView, int iconID) { imageView.setImageBitmap(currentMapTiles.getBitmap(iconID)); } + public void setImageViewTileForPlayer(ImageView imageView, int iconID) { imageView.setImageBitmap(preloadedTiles.getBitmap(iconID)); } + public void setImageViewTile(ImageView imageView, ActorConditionType conditionType) { imageView.setImageBitmap(preloadedTiles.getBitmap(conditionType.iconID)); } + public void setImageViewTileForUIIcon(ImageView imageView, int iconID) { imageView.setImageBitmap(preloadedTiles.getBitmap(iconID)); } + + public void setImageViewTileForSingleItemType(ImageView imageView, ItemType itemType, Resources r) { + final Bitmap icon = tileCache.loadSingleTile(itemType.iconID, r); + setImageViewTile(imageView, itemType, icon); + } + public void setImageViewTile(ImageView imageView, ItemType itemType, TileCollection itemTileCollection) { + final Bitmap icon = itemTileCollection.getBitmap(itemType.iconID); + setImageViewTile(imageView, itemType, icon); + } + private void setImageViewTile(ImageView imageView, ItemType itemType, Bitmap icon) { + final int overlayIconID = itemType.getOverlayTileID(); + if (overlayIconID != -1) { + imageView.setImageDrawable( + new LayerDrawable(new Drawable[] { + new BitmapDrawable(preloadedTiles.getBitmap(overlayIconID)) + ,new BitmapDrawable(icon) + }) + ); + } else { + imageView.setImageBitmap(icon); + } + } + + + public void loadPreloadedTiles(Resources r) { + int maxTileID = tileCache.getMaxTileID(); + for(int i = TileManager.CHAR_HERO; i <= maxTileID; ++i) { + preloadedTileIDs.add(i); + } + tileCache.loadTilesFor(preloadedTileIDs, r, preloadedTiles); + } +} diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ActorConditionList.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ActorConditionList.java index affc575..ddc9fa6 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ActorConditionList.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ActorConditionList.java @@ -41,7 +41,8 @@ public final class ActorConditionList extends LinearLayout { for (ActorCondition c : conditions) { View v = View.inflate(context, R.layout.inventoryitemview, null); - ((ImageView) v.findViewById(R.id.inv_image)).setImageBitmap(world.tileStore.getBitmap(c.conditionType.iconID)); + ImageView iw = (ImageView) v.findViewById(R.id.inv_image); + world.tileManager.setImageViewTile(iw, c.conditionType); SpannableString content = new SpannableString(describeEffect(res, c)); content.setSpan(new UnderlineSpan(), 0, content.length(), 0); ((TextView) v.findViewById(R.id.inv_text)).setText(content); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java index 6c6e111..0e0c9f1 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/CombatView.java @@ -116,8 +116,8 @@ public final class CombatView extends RelativeLayout { if (selectedMonster != null) { attackMoveButton.setText(res.getString(R.string.combat_attack, player.combatTraits.attackCost)); monsterBar.setVisibility(View.VISIBLE); - monsterInfo.setImageBitmap(world.tileStore.getBitmap(selectedMonster.actorTraits.iconID)); - updateMonsterHealth(selectedMonster.health); + world.tileManager.setImageViewTile(monsterInfo, selectedMonster); + updateMonsterHealth(selectedMonster.health); currentMonster = selectedMonster; } else if (selectedMovePosition != null) { attackMoveButton.setText(res.getString(R.string.combat_move, player.actorTraits.moveCost)); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.java index ab774ec..2e3eba4 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ItemContainerAdapter.java @@ -10,14 +10,20 @@ import android.widget.TextView; import com.gpl.rpg.AndorsTrail.R; import com.gpl.rpg.AndorsTrail.model.item.ItemContainer; import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; public final class ItemContainerAdapter extends ArrayAdapter { - private final TileStore tileStore; + private final TileManager tileManager; + private final TileCollection tileCollection; - public ItemContainerAdapter(Context context, TileStore tileStore, ItemContainer items) { + public ItemContainerAdapter(Context context, TileManager tileManager, ItemContainer items) { + this(context, tileManager, items, tileManager.loadTilesFor(items, context.getResources())); + } + public ItemContainerAdapter(Context context, TileManager tileManager, ItemContainer items, TileCollection tileCollection) { super(context, 0, items.items); - this.tileStore = tileStore; + this.tileManager = tileManager; + this.tileCollection = tileCollection; } @Override @@ -29,7 +35,7 @@ public final class ItemContainerAdapter extends ArrayAdapter { result = View.inflate(getContext(), R.layout.inventoryitemview, null); } - tileStore.setImageViewTile((ImageView) result.findViewById(R.id.inv_image), item.itemType); + tileManager.setImageViewTile((ImageView) result.findViewById(R.id.inv_image), item.itemType, tileCollection); ((TextView) result.findViewById(R.id.inv_text)).setText(item.itemType.describeWearEffect(item.quantity)); return result; } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java index a906b6e..e85b26c 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/MainView.java @@ -3,6 +3,7 @@ package com.gpl.rpg.AndorsTrail.view; import com.gpl.rpg.AndorsTrail.AndorsTrailApplication; import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences; import com.gpl.rpg.AndorsTrail.context.ViewContext; +import com.gpl.rpg.AndorsTrail.context.WorldContext; import com.gpl.rpg.AndorsTrail.controller.InputController; import com.gpl.rpg.AndorsTrail.controller.VisualEffectController.VisualEffectAnimation; import com.gpl.rpg.AndorsTrail.model.ModelContainer; @@ -12,7 +13,8 @@ import com.gpl.rpg.AndorsTrail.model.map.LayeredTileMap; import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap; import com.gpl.rpg.AndorsTrail.model.map.MapLayer; import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; import com.gpl.rpg.AndorsTrail.util.Coord; import com.gpl.rpg.AndorsTrail.util.CoordRect; import com.gpl.rpg.AndorsTrail.util.L; @@ -41,7 +43,7 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac private CoordRect mapViewArea; // Area in mapcoordinates containing the visible map. topleft == this.topleft private final ModelContainer model; - private final TileStore tiles; + private final WorldContext world; private final ViewContext view; private final InputController inputController; private final AndorsTrailPreferences preferences; @@ -50,6 +52,8 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac private final Paint mPaint = new Paint(); private final CoordRect p1x1 = new CoordRect(new Coord(), new Size(1,1)); private boolean hasSurface = false; + + private TileCollection tiles; public MainView(Context context, AttributeSet attr) { super(context, attr); @@ -58,8 +62,8 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivityContext(context); this.view = app.currentView.get(); this.model = app.world.model; - this.tiles = app.world.tileStore; - this.tileSize = tiles.tileSize; + this.world = app.world; + this.tileSize = world.tileManager.tileSize; this.inputController = view.inputController; this.preferences = app.preferences; @@ -93,8 +97,8 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac L.log("surfaceChanged " + w + ", " + h); - this.scale = tiles.scale; - this.scaledTileSize = tiles.viewTileSize; + this.scale = world.tileManager.scale; + this.scaledTileSize = world.tileManager.viewTileSize; L.log("scale=" + scale); L.log("scaledTileSize=" + scaledTileSize); @@ -262,7 +266,7 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac for (Loot l : currentMap.groundBags) { if (l.isVisible) { - drawFromMapPosition(canvas, area, l.position, TileStore.iconID_groundbag); + drawFromMapPosition(canvas, area, l.position, TileManager.iconID_groundbag); } } @@ -277,9 +281,9 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac if (model.uiSelections.selectedPosition != null) { if (model.uiSelections.selectedMonster != null) { - drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileStore.iconID_attackselect); + drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_attackselect); } else { - drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileStore.iconID_moveselect); + drawFromMapPosition(canvas, area, model.uiSelections.selectedPosition, TileManager.iconID_moveselect); } } } @@ -337,6 +341,8 @@ public final class MainView extends SurfaceView implements SurfaceHolder.Callbac ); mapViewArea = new CoordRect(mapTopLeft, mapViewSize); + tiles = world.tileManager.currentMapTiles; + clearCanvas(); recalculateMapTopLeft(); diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/QuickitemView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/QuickitemView.java index 05ce7f2..9f21baa 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/QuickitemView.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/QuickitemView.java @@ -15,9 +15,9 @@ import com.gpl.rpg.AndorsTrail.activity.MainActivity; import com.gpl.rpg.AndorsTrail.context.ViewContext; import com.gpl.rpg.AndorsTrail.context.WorldContext; import com.gpl.rpg.AndorsTrail.model.item.ItemType; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; -public class QuickitemView extends LinearLayout implements OnClickListener{ +public class QuickitemView extends LinearLayout implements OnClickListener { public static final int NUM_QUICK_SLOTS = 3; private final WorldContext world; @@ -41,7 +41,7 @@ public class QuickitemView extends LinearLayout implements OnClickListener{ items[i] = (QuickButton)findViewById(quickButtons.getResourceId(i, -1)); QuickButton item = items[i]; item.setIndex(i); - item.setImageBitmap(world.tileStore.getBitmap(TileStore.iconID_shop)); + world.tileManager.setImageViewTileForUIIcon(item, TileManager.iconID_shop); item.setOnClickListener(this); item.setEmpty(true); } @@ -74,11 +74,11 @@ public class QuickitemView extends LinearLayout implements OnClickListener{ for (int i = 0; i < NUM_QUICK_SLOTS; ++i){ QuickButton item = items[i]; ItemType type = world.model.player.inventory.quickitem[i]; - if(type==null){ - item.setImageBitmap(world.tileStore.getBitmap(TileStore.iconID_shop)); + if(type==null) { + world.tileManager.setImageViewTileForUIIcon(item, TileManager.iconID_shop); item.setEmpty(true); } else { - world.tileStore.setImageViewTile(item, type); + world.tileManager.setImageViewTileForSingleItemType(item, type, getResources()); item.setEmpty(!world.model.player.inventory.hasItem(type.id)); } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.java index 17cc092..8a073c2 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/ShopItemContainerAdapter.java @@ -16,18 +16,21 @@ import com.gpl.rpg.AndorsTrail.model.actor.Player; import com.gpl.rpg.AndorsTrail.model.item.ItemContainer; import com.gpl.rpg.AndorsTrail.model.item.ItemType; import com.gpl.rpg.AndorsTrail.model.item.ItemContainer.ItemEntry; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileCollection; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; public final class ShopItemContainerAdapter extends ArrayAdapter { - private final TileStore tileStore; + private final TileManager tileManager; + private final TileCollection tileCollection; private final OnContainerItemClickedListener clickListener; private final boolean isSelling; private final Resources r; private final Player player; - public ShopItemContainerAdapter(Context context, TileStore tileStore, Player player, ItemContainer items, OnContainerItemClickedListener clickListener, boolean isSelling) { + public ShopItemContainerAdapter(Context context, TileManager tileManager, Player player, ItemContainer items, OnContainerItemClickedListener clickListener, boolean isSelling) { super(context, 0, items.items); - this.tileStore = tileStore; + this.tileManager = tileManager; + this.tileCollection = tileManager.loadTilesFor(items, context.getResources()); this.player = player; this.clickListener = clickListener; this.isSelling = isSelling; @@ -45,7 +48,7 @@ public final class ShopItemContainerAdapter extends ArrayAdapter { result = View.inflate(getContext(), R.layout.shopitemview, null); } - tileStore.setImageViewTile((ImageView) result.findViewById(R.id.shopitem_image), itemType); + tileManager.setImageViewTile((ImageView) result.findViewById(R.id.shopitem_image), itemType, tileCollection); ((TextView) result.findViewById(R.id.shopitem_text)).setText(itemType.describeWearEffect(item.quantity)); Button b = (Button) result.findViewById(R.id.shopitem_shopbutton); if (isSelling) { diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java index 7b8be72..c6d0a36 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/view/StatusView.java @@ -8,11 +8,10 @@ import com.gpl.rpg.AndorsTrail.context.ViewContext; import com.gpl.rpg.AndorsTrail.context.WorldContext; import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition; import com.gpl.rpg.AndorsTrail.model.actor.Player; -import com.gpl.rpg.AndorsTrail.resource.TileStore; +import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; @@ -64,12 +63,12 @@ public final class StatusView extends RelativeLayout { expBar.init(R.drawable.ui_progress_exp, R.string.status_exp); levelupDrawable = new LayerDrawable(new Drawable[] { - new BitmapDrawable(world.tileStore.getBitmap(player.actorTraits.iconID)) - ,new BitmapDrawable(world.tileStore.getBitmap(TileStore.iconID_moveselect)) + new BitmapDrawable(world.tileManager.preloadedTiles.getBitmap(player.actorTraits.iconID)) + ,new BitmapDrawable(world.tileManager.preloadedTiles.getBitmap(TileManager.iconID_moveselect)) }); quickToggle = (ImageButton) findViewById(R.id.quickitem_toggle); - quickToggle.setImageBitmap(world.tileStore.getBitmap(TileStore.iconID_boxclosed)); + world.tileManager.setImageViewTileForUIIcon(quickToggle, TileManager.iconID_boxclosed); quickToggle.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -95,23 +94,24 @@ public final class StatusView extends RelativeLayout { if (canLevelUp) { heroImage.setImageDrawable(levelupDrawable); } else { - heroImage.setImageBitmap(world.tileStore.getBitmap(player.actorTraits.iconID)); + world.tileManager.setImageViewTile(heroImage, player); } } public void updateActiveConditions(Context androidContext, LinearLayout activeConditions) { GreedyImageViewAppender t = new GreedyImageViewAppender(androidContext, activeConditions); for (ActorCondition condition : player.conditions) { - t.setCurrentImage(world.tileStore.getBitmap(condition.conditionType.iconID)); + ImageView iv = t.getNextImage(); + world.tileManager.setImageViewTile(iv, condition.conditionType); } t.removeOtherImages(); } public void updateQuickItemImage(boolean visible){ if(visible){ - quickToggle.setImageBitmap(world.tileStore.getBitmap(TileStore.iconID_boxopened)); + world.tileManager.setImageViewTileForUIIcon(quickToggle, TileManager.iconID_boxopened); } else { - quickToggle.setImageBitmap(world.tileStore.getBitmap(TileStore.iconID_boxclosed)); + world.tileManager.setImageViewTileForUIIcon(quickToggle, TileManager.iconID_boxclosed); } } @@ -127,21 +127,21 @@ public final class StatusView extends RelativeLayout { this.context = context; this.previousChildCount = container.getChildCount(); } - public void setCurrentImage(Bitmap b) { + public ImageView getNextImage() { // Since this is called a lot, we do not want to recreate the view objects every time. // Therefore, we reuse existing ImageView:s if they are present, but just change the image on them. + ImageView iv; if (currentChildIndex < previousChildCount) { // There already is a create dimage on this position, reuse it. - ImageView iv = (ImageView) container.getChildAt(currentChildIndex); - iv.setImageBitmap(b); + iv = (ImageView) container.getChildAt(currentChildIndex); iv.setVisibility(View.VISIBLE); } else { // The player has never had this many conditions, create a new ImageView to hold the condition image. - ImageView iv = new ImageView(context); - iv.setImageBitmap(b); + iv = new ImageView(context); container.addView(iv, layoutParams); } ++currentChildIndex; + return iv; } public void removeOtherImages() { for(int i = previousChildCount - 1; i >= currentChildIndex; --i) {