Last
epside in Dragon Ball Z, Goku programmed a GxImage class, but now Vegeta
wonders who is managing all those image instances. Of course, yet another
GxImageLibrary class will do just that. It is used to add images (typically
during the boot-up, or when loading a new level (section)), and future
Materials (see next chapter) should be able to quickly find their image needs
here. As the word says: a library.
Now I’m
not really familiar with Java, so forgive me if I’m doing it all wrong. But I
went looking into (alphabetic) sorted arrays. Since we may have quite a bunch
of images (actually, we don’t, but anyway), we don’t want to loop through the whole
shitpile every time some other object needs image “xyz”. Sorted lists,
collections, hashes, or whatever they are called in Java, can reduce such
searches. Turns out Java calls this a “Map”. I think.
My point is, searching sucks kids. Avoid it when possible. And if you really have to, ask your wife. Or your mom. Because most likely, she has a better memory than you. And that kids, is because she organizes things, instead of just throwing it in a random corner.
public class GxImageLibrary {
HashMap<String,GxImage> images;
public GxImageLibrary()
{
this.images = new HashMap();
} // create
public void releaseAll()
{
Iterator it = this.images.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
GxImage img = (GxImage)pair.getValue();
img.releaseFromGPU();
it.remove(); // avoids a ConcurrentModificationException
} // while iterating
this.images.clear();
} // releaseAll
public void addImage( String imageFilePath )
{
// Check if there is an Atlas file as well - assuming PNG and Atlas are named the same!
String atlasFilePath = imageFilePath.replace( ".png", ".atlas" );
// Use fileName as idName
int start = imageFilePath.lastIndexOf( '/' )+1;
int end = imageFilePath.lastIndexOf( '.' );
String idName = imageFilePath.substring( start, end );
// Make image and add to the list
GxImage img = new GxImage( idName, imageFilePath, atlasFilePath );
this.images.put( idName, img );
} // addImage
public GxImage get( String idName )
{
return this.images.get( idName );
} // idName
} // GxImageLibrary
Just
like how we added a global camera instance in the Engine, we also add the ImageLibrary as a part of our engine code. The engine will create it, destroys it, and makes it available so your "game-code" can use it.
<engine.java>
public class Engine {
float deltaSecs;
GxCamera camera;
GxImageLibrary imageLibrary;
public Engine()
{
this.camera = new GxCamera();
this.imageLibrary = new GxImageLibrary();
} // create
public void shutdown()
{
this.imageLibrary.releaseAll();
} // shutdown
...
public GxImage getImage(String idName )
{
return this.imageLibrary.get( idName );
} // getImage
public GxImageLibrary getImageLibrary()
{
return this.imageLibrary;
} // getImageLibrary
} // Engine
In
general, there are 3 ways here. First is to have your “game-code” doing that,
using hard-coded lines. The second approach is to load a database or “package”
file of some sort, which enlists all available images. Method 3 is on-demand. If
the “mainMenu” class needs Image X, then it shall be loaded. The neat part
about that, is that you can also unload it (making room for others) once the “MainMenu”
is inactive for a while. However, this management is a bit more complicated,
and still those other instances need to know material paths and such.
I hate
hard-coded stuff, but since this is a small game, with relative few resources,
I’m gonna do it anyway. Just adding a simple (game) file that is called in the
initial phase, which then loads all the images. The same file will also load
all Materials, Sounds and other resource files. But since we don’t have
anything yet for that, those are just empty placeholders for now.
public class Resources {
Engine engine;
public void loadInitial( Engine engine )
{
// Load all the initial stuff, during boot-up
// These resources are always available, thus consuming memory permanently
this.engine = engine;
this.loadInitial_Sounds();
this.loadInitial_Images();
this.loadInitial_Animations();
this.loadInitial_LevelPack();
} // loadInitial
private void loadInitial_Images( )
{
engine.getImageLibrary().addImage( "Images/Orb/Orb01.png" );
engine.getImageLibrary().sort();
} // loadInitial_Images
private void loadInitial_Animations()
{
} // loadInitial_Animations
private void loadInitial_Sounds()
{
} // loadInitial_Sounds
private void loadInitial_LevelPack()
{
} // loadInitial_LevelPack
} // Resources
<yourGame.java>
public class JunkThrowerGame extends ApplicationAdapter {
Engine engine;
Resources resources;
SpriteBatch batch;
...
@Override
public void create () {
this.engine = new Engine();
this.resources = new Resources();
this.resources.loadInitial( this.engine );
...
} // create
You can
see, as we slowly start deleting our initial test junk code, the game code gets
more tidy, robust, readable and moreover: extendable. Chunks of test-code in
the Game file are slowly transformed into engine classes. Next chapter, we’ll
proceed sprite animations.
No comments:
Post a Comment