Skip to content

[Holtzman Engine] Customizing your game

Morgan L edited this page Nov 1, 2024 · 1 revision
logo

Creating a prefab

A pefab is a json file that represents a template for an entity.

{
    "tag": "redShip",
    "staticObject": true,
    "components": {
        "Transform": { "position": [0, 0, 0] },
        "Hitbox": {
            "size": [32, 32],
            "offSet": [16, 16],
            "isEnemy": true
        },
        "Health": {
            "health": 1
        },
        "Animator": [
            {
                "name": "default",
                "speed": 10,
                "texture": "assets/graphics/enemy/red_ship.png",
                "frameCount": 8,
                "frameSize": [32, 32],
                "scale": [2, 2],
                "rotation": 0,
                "loop": true
            }
        ],
        "CppScripts": [
            "RedShip"
        ]
    }
}
  • tag
    represents the "class" of the entity, it's the variable used to load the prefab:
    mobs::Entity loadPrefab(const std::string &prefabName, GameContext &gameContext);
  • staticObject
    A boolean variable to state if the entity should stay between scenes

  • components list of components attached to the entity, each component can be used in a scirpt in the following way:

    Transform &transform= registry.get<Transform>(_entity);
    transform.position = mlg::vec3(50, 100, 0): 

Here's a brief desciption of the most usefull components:

  • Transform: position of the entity in game
  • Hitbox: collision box of the entity
  • Sprite: the appearance of your entity
  • CppScripts: scripts to modify the behaviour of your entity

Creating a cppScript

class TemplateScript : public RType::ICppScript
{
   public:
    void update(mobs::Registry &registry, GameContext &gameContext) override
    {
        if (gameContext._runtime->getKeyDown(KeyCode::H))
        {
            std::cout << "Hello, World! from " << _entity << " " << counter << std::endl;
            counter += 1;
        }
    }
    void setEntity(mobs::Entity entity) override { _entity = entity; }

   private:
    mobs::Entity _entity;
    int counter = 0;
};

A script is a tool to control the behaviour of an entity through its components, it is composed of two parts:

  1. the update loop where you can trigger events
  2. the private variables that are unique to each entity, even if they uses the same script

In the above example we use the getKeyDown event to trigger a helloWorld print along with the incremetation of a simple counter.

The mandatory part for a script are those 2 lines:

    void setEntity(mobs::Entity entity) override { _entity = entity; }
    mobs::Entity _entity;

Adding animation to an entity

Json configuration

to add an animation to an entity you must add the animator component, let's take the example of the player:

{
    "Animator": [
            {
              "name": "default",
              "speed": 1,
              "texture": "assets/graphics/player/ship/idle.png",
              "frameCount": 1,
              "frameSize": [32, 16],
              "scale": [2, 2],
              "rotation": 0,
              "loop": true
            },
            {
              "name": "down",
              "speed": 1,
              "texture": "assets/graphics/player/ship/down.png",
              "frameCount": 1,
              "frameSize": [32, 16],
              "scale": [2, 2],
              "rotation": 0,
              "loop": false
            },
            {
              "name": "up",
              "speed": 1,
              "texture": "assets/graphics/player/ship/up.png",
              "frameCount": 1,
              "frameSize": [32, 16],
              "scale": [2, 2],
              "rotation": 0,
              "loop": false
            }
}

The animator component is a list of individual animation, each animation is composed of 8 variables:

  • name ( name of the animation )
  • speed ( speed at which the animation is played, higher is faster )
  • textrue ( path to the sprite-sheet )
  • frameCount ( number of frames in the animation )
  • frameSize ( size of a frame inside the sprite-sheet )
  • scale ( scale of the animation in game, 1 is the default size )
  • rotation ( how the sprite is rotated in game )
  • loop ( should the animation be played only once or not ? )

Beware!

the name of the first animation must always be set to "default" because it is the first animation to be played when the entity spawn.
it is therefor important that loop is set to true or your entity will stop it's animation at the first cycle.

It is also important to note that the name of each animation must be unique because they are called using their names ( and not with indexes or anything else )

apart from that case all other variables are self explanatory.


Script configuration

Once you have setup your list of animation in your Json file you might want to control which animation is played at a certain time. That can be done inside a Script. The animator component has some methods under the hood for you to use.

void PlayAnim(std::string animName)

the only method you truly need, play the animation that has the same name as the parameter you provide.

std::string getCurrentAnim()

if you want to know wich animation is currently in play, return the name of that animation.

let's take a look at an example of a pratical use case:

class AnimThrusterScript : public RType::ICppScript
{
   public:
    void update(mobs::Registry &registry, GameContext &gameContext) override
    {
        if (gameContext._runtime->getKeyDown(KeyCode::RightArrow))
        {
            AnimationList &animations = registry.get<Animator>(_entity).animations;
            animations.playAnim("low");
        }
        if (gameContext._runtime->getKeyUp(KeyCode::RightArrow))
        {
            AnimationList &animations = registry.get<Animator>(_entity).animations;
            animations.playAnim("default");
        }
    }
    void setEntity(mobs::Entity entity) override { _entity = entity; }

   private:
    mobs::Entity _entity;
};

Here when the right arrow key is pressed:

    if (gameContext._runtime->getKeyDown(KeyCode::RightArrow))

We get the animationList out of the Animator component:

    AnimationList &animations = registry.get<Animator>(_entity).animations;

And we then play the "low" animation:

    animations.playAnim("low");

And if the RightArrow key is released we reset the animation by calling: animations.playAnim("default");

That's all you need to animate any entity you want, have fun exploring the limit of the framerate!

Clone this wiki locally