Project Polis (Dev Journal #4): Resource acquisition and production — Polis – Dev Blog

Having laid the foundations for our gameplay systems, we can now focus on implementing the mechanics behind the resource acquisition and production. After all we need resources to sustain our population and expand our city. By resource acquisition we mean the process by which we remove a resource from the environment (natural resource) and place it in some inventory (eg. wood from trees) and by resource production, that process by which we create new resources by combining others (eg. wood stick from wood).

The production system

In Polis, buildings are responsible for these two processes, which from now on we will be referring to as “production buildings”. A production building can be constructed on any tile as long as that tile can provide the resources required as inputs. All production buildings need a number of workers to be assigned to them from the population and will continuously produce resources over time. Finally, most of these buildings will have some local storage where the produced resources will be temporarily stored, awaiting transportation. A building will not produce if there are no workers assigned, the local storage is full or the required input resources have been depleted.

Image 1: Production system overview

For each building we define a production function which is responsible for applying a specific action or sequence of actions on some inputs while producing some outputs. Each building, once it has enough workers assigned, will start a production task which every game day will add the worker’s effort towards the production task. Once enough effort has been accumulated, the task is finished and the production function gets executed. The required inputs are removed from the tile and the produced outputs are placed in the building’s local inventory.

In order to manage our production tasks and make sure that enough workers from the population are assigned to resource production, we create the production system. We use the coroutine task system we’ve previously created in order to implement and manage our production tasks, allowing us to run multiple tasks simultaneously while suspending or removing others that cannot be executed.

Modeling the production function: inputs and outputs

As we’ve previously mentioned a production building specifies a production function which defines the actions applied on the inputs to acquire the outputs. In image 1 we can see that our production function uses a “production function definition”. The idea here is to implement the logic of a few discrete production functions (eg. acquisition, transformation, combination) and create some “definitions” in the editor that will allow us to produce various resources by specifying different inputs.

An example will make things much clearer. We want to have a foraging camp which will acquire any edible resources from the tile it has been constructed on. We also want to have a logging camp that will chop down trees and acquire wood. These two production buildings have one thing in common: They take resources from a tile as inputs, apply some action on them (foraging, chop wood) and produce some outputs storing them in the building’s local storage.

Image 2: examples of production function

So we can see that even though both the foraging and the logging camp use the same type of production function (acquire), they produce different outputs since they take different inputs. Also the production of two buildings might differ depending on the tile they are placed. For example a foraging camp on a tile that has apple trees and blackberry bushes will produce apples and blackberries while a foraging camp placed on a tile with mushrooms and oak trees will produce acorns and mushrooms.

The attribute commodity

All the above make it evident that we need to rethink our commodity system, especially the resource commodities and extend it in a way where we can group our resources by common characteristics, allowing us to easily define our various production functions.

We create the attribute commodity, which like all the other commodities, has a unique id. Then we add two lists in the resource commodity an “attributes” and a “has” list. The “attributes” list specifies the attributes that characterize this resource (edible, wood, mineral, animal, etc) while the “has” refers to other resources this resource might contain (the blackberry bush has blackberries for example). When we build our commodity database, we go through each resource and construct a dictionary that allows us to execute quick queries about what attributes each resource has. This way we can easily decide where to place buildings and what production inputs and outputs each building will have.

Each attribute can specify some data if needed. For example, the edible attribute specifies an “energy” value which defines how much energy the edible will provide once consumed. Mushrooms, acorns, blackberries and apples need to define different energy values, therefore we need a way of exposing those variables in the editor and storing their values in the resource that defines them.

One problem here is that Unity’s serializer doesn’t support polymorphic types, at least not in the way we want to use them. To deal with this, we created an editor script for our resource commodities that allows us to add and remove any attribute to our resource commodities. We also created a custom property drawer for our attributes that allows us to expose and edit their variables in the editor. To handle serialization of classes that inherit from AttributeCommodity, we simply serialize them to a JSON string and store them in the resource commodity.

Our current implementation of the attribute commodities is still at an early stage but for now it is good enough as a proof of concept. We feel that such a system is really important for Polis, as this will allow us to describe the items in our world through a “language” of attributes, enabling us to create a big number of resources making every island unique.

Future work

  • Better serialization using FullSerializer.
  • Simplify the attribute commodity workflow by providing simpler interfaces.
  • Implement editor scripts to allow more complex data to be exposed (enum, asset reference, etc)
Be Sociable, Share!
  • Reddit

Leave a Reply

Your email address will not be published. Required fields are marked *