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

Making things move



In my previous post I have introduced the component pattern and followed with an example of implementation. Today, in this short post I’m going to show you how have I used this pattern to implement a simple component that handles our Player’s movement.

The Player

Let’s start with the game object that will represent the Player.
Our Player class inherits from the basic GameObject class and on top of that defines how it will be rendered.
GameObject class in my project also defines an abstract method Render where the object is given an access to an Malison.Core.Iterminal instance in order to render itself on screen.
In my case, I’m going to use the simple @ sign for now, rendered in the current player’s Position.

[RequireComponent(typeof(PlayerMovementHandler))]
public class Player : GameObject
{
    public TermColor ForeColor;

    public override void Render(Malison.Core.ITerminal terminal)
    {
        terminal[Position][TermColor.White, TermColor.Black].Write(Glyph.At);
    }

    protected override void OnStart()
    {
        Position = Vector2D.Zero;
    }
}

You can also see the usage of RequireComponent attribute in order to attach the PlayerMovementHandler instance to the game object.

PlayerMovementHandler

The Handler itself is quite simple. We define the LAG constant which defines the time amount between every tile movement so our Player doesn’t move too fast.

The OnStart callback is empty for now, because no setup was required for such trivial example.

In our Update method we define the actual logic for movement. We check for all of the WASD keys and if one of them is pressed we modify the movement vector.
If the vector is not zero valued, we change our player’s position by the value of the movement vector.

This way we can apply multiple key-pressed at once in order to also move diagonally.

public class PlayerMovementHandler : Component
{
    // Limit movement speed to 10 tiles per second
    private const double LAG = 0.1f;

    private double elaspedTime;

    protected override void OnStart()
    { }

    public override void Update()
    {
        if(elapsedTime < LAG)
            elaspedTime += Game.DeltaTime;

        if(elaspedTime > LAG)
        {
            elaspedTime = 0;
            Vector2D movement = Vector2D.Zero;

            if(Game.UI.IsKeyDown(Key.A))
                movement += new Vector2D(-1, 0);

            if(Game.UI.IsKeyDown(Key.D))
                movement += new Vector2D(1, 0);

            if(Game.UI.IsKeyDown(Key.W))
                movement += new Vector2D(0, -1);

            if(Game.UI.IsKeyDown(Key.S))
                movement += new Vector2D(0, 1);

            if(movement != Vector2D.Zero)
            {
                GameObject.Position += movement;
            }
        }
    }
}

It moves! It moves! Don’t mind the random symbols - these are just a test of the terminal emulation library.

The devil is in the details

There is a ton of things I haven’t covered though that are more or less hidden in these code samples - for example the fact that the Key enumerator is actually part of the game engine.

If, for example I would want to switch the framework from Windows Forms to MonoGame to go for the glorious multi-platform support (which I’ll probably do in the future) I’ll just write a tiny bit of code as a facade to handle and map that framework’s key codes instead of refactoring the whole project to decouple it from Windows Forms’ KeyCode.

Another things are the Game and Game.UI objects whose implementation I have not shown yet.
I’m still laying down the basics and changing the project structure to - for example - maybe separate the engine itself from the game in the future.

Speaking of refactoring, meanwhile I’m working hard on the Malison library which - if you remember the project introduction post - I’m maintaining now.
In short, I want to decouple it from the Glyph abstraction that puts a heavy constraint on the available text characters in the library. It also limits the users to use the given font or customize their fonts to fit the constraints of the Glyph enumerator.

To clarify - that Glyph enumerator defines available characters in specific order that represents how the character in spritesheet for that font looks like.
Another troubling thing is the fact that the font’s encoding could not be changed because of that.

It’s a tightly coupled problem which I’ll have to deal with. If I want to allow usage of a custom font which in case of my game is - CP437 - and allow the support for it’s characters and encoding, which differ from font to font - there is no other way.

This change will also allow to switch the font sprite to actual non-text sprites quite easily if such need would arise.

Such is the result of me actually working on Malison and Bramble libraries from time to time, while implementing Praedium.

The good news is that I’ll end up with 2 more projects than I expected before entering the Daj się poznać competition.

That’s it for today. Next time I’ll maybe show you the results of my - hopefully - successful refactoring and explain the decisions I made there and how did they improve the library itself.

For those who missed it, here are the repositories for the projects:

  • Bramble - a set of utility classes such as Vector2D
  • Malison - terminal emulation library
  • Praedium - my actual project

For more information refer to the project introduction post.

Please don’t bite me for the lack of reasonable README.md files in the repositories - I’ll try to get around them soon.