Article Image
Article Image
read

One of the interesting concepts I read about was the use of “prototypes”. I’m not talking about prototypes in terms of unfinished game projects, although coincidentally that’s what I was doing to test this concept. The “prototype” idea is related to entities or objects in a game, let’s say you have a building that turns stone into brick and you assign a number of properties.

class Factory {
    var title = "Stone Factory"
    var craftingTime = 3.0
    var inputItems = ["stone": 1]
    var outputItems = ["brick": 1]
    var currentProgress = 0.0
    var isCrafting = false
}

You’ll probably notice some properties won’t ever change, or would be strange to duplicate for every StoneFactory in the game. That’s where a prototype comes into play, by moving those properties out into another class that can be referenced by all stone factories your game will use less memory. At 1 object this doesn’t have a big impact but maybe 1000 or 100,000 objects it certainly will. Here’s an example:

class FactoryPrototype {
    var id: String // I use this in the next example
    var title = "Stone Factory"
    var craftingTime = 3.0
    var inputItems = ["stone": 1]
    var outputItems = ["brick": 1]
}

class Factory {
    var prototype: FactoryPrototype
    var currentProgress = 0.0
    var isCrafting = false
}

Another benefit of this pattern is that we can remove all the prototype data from save files and dynamically load it at runtime when needed. Since it’s not in the saved game we can also tweak the values to balance the game between updates and not break the save file or need complex migration code. Let’s have a look at a more complete implementation that would do that.

// Before the game loads all prototypes are registered with unique IDs.
class PrototypeRegistry {
    private static var prototypes: [String: FactoryPrototype] = [:]

    static func register(_ prototype: FactoryPrototype) {
        prototypes[prototype.id] = prototype
    }

    static func load(_ id: String) -> FactoryPrototype {
        return prototypes[id]!
    }
}

struct FactoryPrototype {
    var id: String
    var title: String
    var craftingTime: TimeInterval
    var inputItems: [String: Int]
    var outputItems: [String: Int]
}

class Factory {
    var prototype: FactoryPrototype
    // Only need to serialize these values into a save file
    var prototypeId: String
    var currentProgress = 0.0
    var isCrafting = false

    init(prototype: FactoryPrototype) {
        self.prototypeId = prototype.id
        self.prototype = prototype
    }

    init(prototypeId: String) {
        self.prototypeId = prototypeId
        self.prototype = PrototypeRegistry.load(prototypeId)
    }
}

Now it’s trivial to add more types of factories and change them without touching a line of gameplay code. All the prototypes can live in a text file if you want to write a parser for that, I’m lazy and coding them into a set of data files that initialize and register them when the app launches. I also have a few more properties for the 3D model and scale factory so trying out different models it’s super easy.

Hopefully you found this helpful and enjoy the small glimpse into development of Builderment. I had a fun time implementing this and learning about structuring the code this way for more optimal performance.

Follow and Subscribe 👍

This journey is just beginning. If you like what you read I’ll be posting more of it, hopefully weekly. Currently on twitter and instagram sharing images and videos from development. Reach out via email or come join discord!

Twitter @builderment
Instagram @builderment
Discord https://discord.gg/VkH4Nq3
Email contact@builderment.com

Blog Logo

Builderment


Published