0
\$\begingroup\$

The fields: (example)

public static final FileHandle ASSETS_DIR = Gdx.files.internal("");
public static final String TEXTURES_DIR = "textures/";
public static final String TEXTURES_ATLAS_DIR = TEXTURES_DIR + "packed/";
public static final String TEXTURES_WHEELS_DIR = TEXTURES_DIR + "wheels/";
public static final String TEXTURES_TIRES_DIR = TEXTURES_DIR + "tires/";
public static final String TEXTURES_VEHICLES_DIR = TEXTURES_DIR + "vehicles/";
public static final String TEXTURES_COMPUTER_DIR = TEXTURES_DIR + "computer/";
public static final String TEXTURES_GARAGE_DIR = TEXTURES_DIR + "garage/";
public static final String TEXTURES_UI_DIR = TEXTURES_DIR + "ui/";
public static final String TEXTURES_CURSOR_DIR = TEXTURES_DIR + "cursors/";

public static final String DATA_DIR = "data/";
public static final String VEHICLE_DATA_DIR = DATA_DIR + "vehicles/";
public static final String COMPUTER_DATA_DIR = DATA_DIR + "computer/";
public static final String BROWSER_PATH = COMPUTER_DATA_DIR + "browser/";

public static final String ATLAS_WHEELS = "atlas_wheels.atlas";
public static final String ATLAS_GARAGE = "atlas_garage.atlas";
public static final String ATLAS_COMPUTER = "atlas_computer.atlas";
public static final String ATLAS_UI = "atlas_ui.atlas";

public static final String FONTS_DIR = "fonts/";
public static final String FONT_STYLE_A = "fstl_stcrd";

*Example:**

You can see here I use some literals from time to time. I can create a constant for that, but I don't think that's the best solution. I'm still having strings all around the code and maybe wasting memory (not the concern here, just saying though).

public static LinkedHashMap<String, Texture> loadTextures(Car car) {
    final FileHandle root = car.getData().getAssetsDirectory();
    final JsonValue specs = new Json().fromJson(null, root.child(CHASSIS_DATA_FILENAME));

    final LinkedHashMap<String, Texture> textures = new LinkedHashMap();

    // Order is important for proper packing. Big parts first or it will create more pages than needed.
    textures.put("body", new Texture(root.child(Model.Layer.BODY.getName() + ".png")));
    textures.put("mask", new Texture(root.child(Model.Layer.MASK.getName() + ".png")));
    textures.put("tire", new Texture(GameAssetManager.TEXTURES_TIRES_DIR + specs.get("wheels").get("tire").asString() + ".png"));
    textures.put("wheel", new Texture(GameAssetManager.TEXTURES_WHEELS_DIR + specs.get("wheels").get("wheel").asString() + ".png"));

    for(BodyPart.SubLayer lp : BodyPart.SubLayer.values()) {
        BodyPart p = car.getBody().getBodyPart(lp);

        if(p == null)
            continue;

        FileHandle bf = root.child(lp.getName() + "/" + String.valueOf(p.getPartID()) + ".png");

        if(!bf.exists())
            continue;

        Texture t = new Texture(bf);
        textures.put(lp.getName(), t);
    }

    return textures;
}

The problem:

I have string literals (only for internal usage) separeted in relevant classes for each one (GameAssetManager has fields that indicate where to locate resources and CarAssets has fields to find specific resources, etc...).

Sometimes non of those fields meet my requeriments and I have to revert to hardcoding a string for a particular piece of code and I don't want to have strings scattered throughout my code because as it grows, i know it will become a pain int the butt.

I'm thinking of implementing some kind of 'config.json' file and use inside the program just pointers to strings inside that file like:

0x0000AB0F: "textures/vehicles/wheel.png"
0x0000AB1F: "textures/vehicles/tire.png"
0x0000FC03: "enemy/body.png"

And in code just do:

String s = Utils.getString(0x0000AB0F);

The only (annoying) problem i see is that i still have to go back and forth between the 'config.json' file and the code im writing to locate the proper code for the string that I'm looking for.

By the way, I didn't came up with this hex to string thing. I saw it in the source code of another game I used to script years ago and I thought it was neat.

I'm want to get some information before beggining to make this big code changes. I searched around and didn't find the right answer.

What do you think will be the best approach?

Thanks for your time.

\$\endgroup\$
3
\$\begingroup\$

Your architecture seems to be an example of Stringly Typed: You are using strings where more specialized data types would make more sense.

In this case, most strings seem to refer to directories, which in Java are usually represented best by objects of class File. So TEXTURES_TIRES_DIR should be a File, not a String.

Similarily, your JsonValue specs should be converted to a more strongly typed class as soon as you load it (By the way: this would also be a good place to validate the file and throw a useful error message if something is missing). So instead of calling specs.get("wheels").get("tire").asString() + ".png" you should be able to call something like specs.getTireTexture() or specs.getTexture(CarParts.TIRE) (with CarParts being an enum).

I'm thinking of implementing some kind of 'config.json' file and use inside the program just pointers to strings inside that file like:

0x0000AB0F: "textures/vehicles/wheel.png"
0x0000AB1F: "textures/vehicles/tire.png"
0x0000FC03: "enemy/body.png"

And in code just do:

String s = Utils.getString(0x0000AB0F);

You might notice that this code is completely unreadable. When you later look at the above line, you have no way to tell which texture is actually loaded here without looking at your config file. You can not even tell whether that hex-code is correct or not. This is not just a small annoyance, it is a huge annoyance which will drive you crazy in the long-run.

If you want some lightweight lookup mechanism for string locations, at least use properly named int-constants so the code stays human-readable. But using constants is still a bad idea, because adding a single character to any of the strings in the file will invalidate any indexes which come after it. So if you want to have such a lookup table, then you should build it at runtime after parsing the file.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks. I will take all this into consideration for refactoring my code. Regarding the fie "specs.json" i dont load it (there are dozens of them in different folders), but read it in real time, because it contains specific information depending on the object im loading. I construct my entities in real time reading that file and looking up the resources through the assets directory. \$\endgroup\$ – Jh62 Sep 21 '18 at 5:54
1
\$\begingroup\$

Use a little bit of both:

In your JSON file, instead of using these hex codes as keys, use named strings, the ones equivalent to your string constant names.

The idea here is that you can change the data without the need to recompile, it will also be easier to localise your game (change language? change the JSON file).

Also, I advise strognly against using these hex code without you knowing why you'd use them: this will make your code very hard to read.

Sorry for the brevity, I'm on my phone.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.