javatext-filesconfiggame-development

Java text files: How do I assign values per line to the corresponding variable?


I'm trying to make config files for a Java game I'm making, and I wanna make sure that upon loading a new level, I can get data from a text file that serves as the config file.

For example, the Level1.txt file would look like this:

PlayerSpawn = -1000, 500
Block1Data = -500,400,30,30
...

For these 2, the first 2 variables are their initial coordinates, and the block has its size in there too.

I now want to look for a name in the file (like PlayerSpawn) so I can pass it to the corresponding variable.

How would I do that?


Solution

  • You have a ton of options at your disposal (e.g. Properties,JSON,XML,YAML,TOML,etc). I'll cover 2 common formats you can use for this purpose:

    Properties File

    The JDK comes with the idea of property files built-into it. These are very similar to window's INI files. You use them through the Java class java.util.Properties and it implements the Map<String,String> interface. Here is how you might use it:

    import java.util.Properties;
    ...
    Properties levelProps = new Properties();
    try( InputStream is = new FileInputStream( "level_1.properties" ) ) {
       levelProps.load( is );
    }
    
    String playerSpawn = levelProps.get("playerSpawn");
    String block1Data = levelProps.get("block1Data");
    
    List<Integer> block1DataList = Arrays.stream(blockData.split(","))
                                         .map(Integer::parseInt)
                                         .collect(Collectors.toList());
    

    One thing you'll notice is that you have to parse the resulting strings into relevant data before you can use it. This often means lots of data processing and object binding before it becomes usable. And in most programs this is overly tedious. Another con is properties are flat structures as evidenced by your array notation you used. You can map complex structures to a flat representation, but you'll have to spend effort to transform it back. People do given clues as to how to structure and think about the data by using dot notation to signify and collect like valued properties, but it's still just property=value format. Dot notation looks like this:

    player.spawnPoint=100,100
    player.hitPoints = 200
    player.allergies=dairy,wheat
    

    So you can begin to see how these properties might be mapped to properties inside an object called player as opposed to local variables.

    JSON Files

    Unlike Properties in Java, JSON is a language neutral format that came from Javascript literal notation. The JDK does not come with support for reading/writing JSON files within the JDK so you'll need an external library to give you that ability. There are many JSON libs out there for Java: Jackson being on of the most commonly used one. Here is example of JSON file:

    {
       player: {
          spawn: [ 100, 150 ],
          hitPoints: 100,
          allergies = [
             "dairy",
             "wheat"
          ]
       },
       blocks: [
          [ -500, 400, 30, 30 ],
          [ -240, 50, 80, 120 ]
       ]
    }
    

    One of the key differences between these two formats is JSON is not a flat structure. It support a hierarchy of Objects, Arrays, and primitive types: numbers, strings, booleans, nulls.

    This means you have far less transformations to perform when reading JSON data because the libraries can bind the data directly into native Java types. Numbers become Integers or Doubles for example. Booleans in JSON are read out as Boolean in Java. JSON arrays are Java List, and JSON Objects are Maps. However, JSON libraries also support binding directly to Java classes.

     String jsonString = """
    {
      spawn: [ 100, 150 ],
      hitPoints: 100,
      allergies = [
         "dairy",
         "wheat"
      ]
    }
     """;
        
     ObjectMapper objectMapper = new ObjectMapper();
     try {
         Person person = objectMapper.readValue(jsonString, Player.class);
         System.out.println("Spawn Point: " + player.getSpawn());
         System.out.println("Hit Points: " + person.getHitPoints());
         System.out.println("Allergies: " + person.getAllergies());
     } catch (IOException e) {
         e.printStackTrace();
     }
    

    Jackson coordinates (Gradle):

    implementation "com.fasterxml.jackson.core:jackson-databind:2.17.2"
    

    The last thing I'll say is you may want to familiarize yourself with loading resources from the classpath. Most IDEs and build tools like Gradle or Maven have a ready made folder called resources that are available on the classpath. This is an appropriate place to put your configuration files like levels, images, etc. Nearly all build tools will package resources with your code in a jar file for use outside of your development environment which makes it very easy to install and use your code for end users. This is great for things YOU as the developer would configure NOT your end users.

    Update:

    I will mention XML files because they are a common format, support object hierarchies with data binding similar to JSON (although there is no data type conversion from using raw parser APIs like JSON), and the JDK supports them without needing a dependency to read them.