This site uses cookies to ensure you get the best experience. More info
Got it!

Tilling Soil



Growing crops

Today I’m going to show you how I tackled the implementation of growing crops in Praedium.

It’s very rough for now as I have been struggling a little bit with the engine’s internals.

So, how does the process of growing crops will look like in Praedium?

My idea for that is basically a direct copy of the flow from Harvest Moon games.
The flow can be explained by these steps:

  1. Till the soil.
  2. Sow seeds.
  3. Water the soil.
  4. Repeat step #3 every day until plants are ready for harvest.
  5. ???
  6. PROFIT

The last two steps are a joke of course, but I couldn’t resist.

From what we can gather, a single tillable tile on our farm can therefore be tilled, watered and contain a seed within it, which will later turn into a crop.

We cannot sow seeds or water soil that is not tilled. Though, we can water a tilled soil that does not have a seed or plant a seed if the soil is not watered.

While this is definitely a very simple flow there are more details that we need to cover.

Tools

Every single task through this flow (except maybe harvesting the crops) requires a proper tool to be used.

We need a hoe to till the soil.
We need a watering can to water it.
We need some kind of seed bag to carry, and sow seeds.

This of course means we would need to have some kind of inventory for our character, and that’s what I’ll be definitely implementing in the future, but for now in order to achieve the result with minimal effort I decided to ignore it.

Instead, our character has some kind of currently used tool which we can switch between and use them on a tile next to him using arrow keys (movement is made with WASD keys).

The representation of current tool in code is made via simple enumeration.

The tool is changed whenever we press E, although there is no UI at this moment to actually see it.
The enumeration will be definitely removed and refactored in to actual classes, which instances are kept in some sort of Inventory class so for now the code is kept in a single component - ToolHandler.

public enum Tool
{
    Hoe = 0,
    WateringCan,
    Seeds
}

public class ToolHandler : Component
{
    public Tool CurrentTool = Tool.Hoe;

    protected override void OnStart()
    {
        Game.KeyDown += Game_KeyDown;
    }

    void Game_KeyDown(object sender, KeyInfoEventArgs e)
    {
        if(e.KeyInfo.Key == Key.E)
        {
            CurrentTool = (Tool)((((int)CurrentTool) + 1) % 3);
        }
    }

    public override void Update()
    {
        Vector2D offset = Vector2D.Zero;

        if(Game.UI.IsKeyDown(Key.Up))
        {
            offset = new Vector2D(0, -1);
        }
        else if(Game.UI.IsKeyDown(Key.Right))
        {
            offset = new Vector2D(1, 0);
        }
        else if(Game.UI.IsKeyDown(Key.Down))
        {
            offset = new Vector2D(0, 1);
        }
        else if(Game.UI.IsKeyDown(Key.Left))
        {
            offset = new Vector2D(-1, 0);
        }

        if(offset != Vector2D.Zero)
        {
            var targetTile = Game.GetObjectAt(GameObject.Position + offset) as FieldTile;

            if(targetTile != null)
            {
                switch(CurrentTool)
                {
                    case Tool.Hoe:
                        targetTile.Till();
                        break;
                    case Tool.WateringCan:
                        targetTile.Water();
                        break;
                    case Tool.Seeds:
                        targetTile.Seed();
                        break;
                }
            }
        }
    }
}

The ToolHandler checks for user input and processes it by finding a field tile under given position and then, depending on current tool it interacts with it.

Field tiles

The field tile is a new abstraction that represents a special kind of tiles that are present on our farm and are the only place where we can grow the crops, till the soil and so on.

That is why I decided to, at least for now, keep the information about where and how many of such tiles exist, within the tile map.

Data representation in tilemaps

Areas representing actual fields Areas representing actual fields. Notice lack of other objects on them, those will be generated randomly when initial farm is created for a new game.

After doing so, we had to parse the file and look for the field blocks in the tile map, in order to create the field tiles.

foreach(var field in map.ObjectGroups[0].Objects.Where(x => x.Name == "Field Block"))
{
    int width = (int)field.Width / map.TileWidth;
    int height = (int)field.Height / map.TileHeight;
    int x = (int)field.X / map.TileWidth;
    int y = (int)field.Y / map.TileHeight;

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            FieldTile tile = new FieldTile();
            tile.Position = new Vector2D(x + i, y + j);
            AddGameObject(tile);
        }
    }
}

The objects in .tmx format have their parameters represented in pixels, therefore we need to scale them into a single unit width/height based format.

Having parsed the sizing parameters, we loop through the points covered by each rectangle and initialize new FieldTile instances on those positions.

FieldTile class

The FieldTile is a new kind of GameObject that also utilises the CellRenderer.
The status of the tile - whether it is tilled, watered or contains a seed - is temporarily represented by a simple enumeration FieldTileStatus with Flags attribute.

This enumeration may perhaps actually not be removed in the future as it is not a bad way to represent the tile’s status. Only the Seeded flag would probably be removed as the tiles can also be occupied by other kinds of objects.

[Flags]
public enum FieldTileStatus
{
    Default = 0,
    Tilled = 1,
    Seeded = 2,
    Watered = 4
}

[RequireComponent(typeof(CellRenderer))]
public class FieldTile : GameObject
{
    private CellRenderer renderer;

    public FieldTileStatus Status
    {
        get;
        set;
    }

    public bool Tilled
    {
        get
        {
            return Status.HasFlag(FieldTileStatus.Tilled);
        }
    }
    public bool Watered
    {
        get
        {
            return Status.HasFlag(FieldTileStatus.Watered);
        }
    }

    protected override void OnStart()
    {
        Name = "FieldTile";

        renderer = (CellRenderer)GetComponentOfType(typeof(CellRenderer));

        renderer.Character = new Character((int)Glyph.Space, Colors.Soil, Colors.Soil);
    }

    public void Till()
    {
        if(!Status.HasFlag(FieldTileStatus.Tilled))
        {
            Status |= FieldTileStatus.Tilled;
            renderer.Character = new Character(renderer.Character.Code, renderer.Character.ForeColor, Colors.TilledSoil);
        }
    }

    public void Seed()
    {
        if(Status.HasFlag(FieldTileStatus.Tilled))
        {
            Status |= FieldTileStatus.Seeded;
            renderer.Character = new Character((int)Glyph.Bullet, TermColor.Parse("#1a140d"), renderer.Character.BackColor);
        }
    }

    public void Water()
    {
        if (Status.HasFlag(FieldTileStatus.Tilled))
        {
            Status |= FieldTileStatus.Watered;
            renderer.Character = new Character(renderer.Character.Code, renderer.Character.ForeColor, Colors.WateredSoil);
        }
    }
}

The logic behind Till, Seed and Water methods is really straightforward and basically consists of adding another flag and changing the renderer’s character.

When we till the soil, the background changes to be a bit darker.
When we place a seed in it, the character code changes to a little dot.
When we water it, the soil becomes even darker.

The fieldwork flow in action. The fieldwork flow in action.

Wrapping up

And that’s it for today’s post!

I have shown how the basic flow looks like, and how it presents itself in game.

Speaking about it, I had a very interesting idea today. And that is, to completely change the way the game would be played.

I found the typical rougelike keyboard controls to be a little bit odd and clunky for this type of activity. I wonder if I should change that to not actually control the character but give him commands as in point and click or maybe Dwarf Fortress’ keyboard style of controls for some general management.

This way I could even go as far as to change the game from a single character based to some kind of family-on-a-farm management game with a real time strategy feeling.

I’m actually very curious about going this route, especially because I’m not that deep into one way or the other.

Maybe you can help me out? If you have an opinion, suggestion or some expectations from Praedium - feel free to drop a comment below.

Meanwhile I’ll have to decide which way to go, as both are going to be different.