Skip to content

Adding NPCs to the map

jjppof edited this page Aug 13, 2023 · 9 revisions

Adding NPCs to the map

This tutorial will show how to add NPCs to a map in GSHTML5.

Registering an NPC in the engine

In order to add an NPC to the map, first, this NPC needs to be registered in the engine. This can be done by adding its basic info in the assets/dbs/npc_db.json file. This file contains an array of objects, each object represents an NPC. So in order to register an NPC, just adding one more object to this array with its info is enough.

The info passed to this object will be common for each instance of this NPC you'll create in the maps you want to add it. So keep in mind that registering an NPC in this file doesn't mean you'll add an NPC somewhere, here you're just registering the NPC and setting its common settings that all instances will have by default. In this file, you'll set settings like spritesheet data, walk speed, collision body radius, sprite anchor point, voice sfx, key name, etc. The full list of these options can be found here.

Example for Alex:

[
  {
    "key_name": "alex",
    "anchor_y": 0.8,
    "initial_action": "idle",
    "collision_body_bevel": 3,
    "interaction_pattern": "tik_tak_toe",
    "body_radius": 7.0,
    "walk_speed": 60,
    "voice_key": "adult_male_1",
    "actions": {
      "idle": {
        "frame_rate": [[0.2, 6, 0.3, 2, 0.4, 1, 1]],
        "animations": [
          "down",
          "up",
          "left",
          "right",
          "up_left",
          "up_right",
          "down_left",
          "down_right"
        ],
        "frames_count": 7,
        "initial_animation": "down",
        "spritesheet": {
          "image": "assets/images/spritesheets/npc/alex_idle.png",
          "json": "assets/images/spritesheets/npc/alex_idle.json"
        },
        "loop": true
      },
      "walk": {
        "frame_rate": 7,
        "animations": [
          "down",
          "up",
          "left",
          "right",
          "up_left",
          "up_right",
          "down_left",
          "down_right"
        ],
        "frames_count": 6,
        "initial_animation": "down",
        "spritesheet": {
          "image": "assets/images/spritesheets/npc/alex_walk.png",
          "json": "assets/images/spritesheets/npc/alex_walk.json"
        },
        "loop": true
      }
    }
  }
]

So any time we add an Alex NPC in a map, by default, this NPC will have the above settings.

Please notice that here is where you define the spritesheets of this NPC and how these sprites will be animated. The "actions" property will hold each action available for this NPC, in the case of Alex in this example, we set "walk" and "idle". Each action will have its own spritesheet files containing all the available directions, that are defined by "animations" property. The engine allows you to control whether those animations will loop or not, how long each frame will last, etc. You can find full details on these properties here.

Instantiating an NPC

Now that you registered the NPC, it's time to add it to a map. In order to do so, you need to open the map file you want to add the NPC on Tiled. Once you opened it, click on Map > Map Properties... (steps 1 and 2), then add a new map property (step 3) of type string (step 4) with the following key name: npc/alex (Step 5). The engine will know that this property is to create an NPC because its key name starts with npc/, and the alex after it could be any unique name that reminds the NPC you're creating. Press OK to confirm (step 6).

Setting NPC instance unique properties

We'll now set the value of the npc/alex property. It expects a json object containing the unique properties of this NPC you're adding to this map, like position in map, interaction message, animation, etc. The full list of these options can be found here. For this NPC, we'll only add the following:

{
  "key_name": "alex",
  "x": 6,
  "y": 6,
  "movement_type": "idle",
  "message": "This the NPC tutorial!",
  "animation": "down",
  "base_collision_layer": 2
}

It's good practice to always set "base_collision_layer" value. But if not passed, the default value is 0.

The result:

Random walk

The NPC can also perform a random walk. For this, you just need to add the following properties:

{
  "key_name": "alex",
  "x": 6,
  "y": 6,
  "message": "This the NPC tutorial!",
  "animation": "down",
  "base_collision_layer": 2,
  "movement_type": "random",
  "max_distance": 16,
  "step_duration": 10,
  "wait_duration": 90,
  "base_step": 4,
  "step_max_variation": 2
}

The result:

Firing events

You can also fire Game Events when interacting with an NPC. For this example, we'll make Alex jump to the other house. In the below events sequence, Alex first tells what he's going to do, then he moves next to the gap, jumps it, walks a little bit more, then invites Isaac to also jump it. In these events, in order to identify Alex in the events, we added the "label" property. This property should receive a unique key name that only this NPC has, then we can safely refer to this NPC when defining the events.

{
  "key_name": "alex",
  "x": 6,
  "y": 6,
  "animation": "down",
  "label": "alex",
  "base_collision_layer": 2,
  "movement_type": "idle",
  "events": [
    {
      "type": "dialog",
      "dialog_info": {
        "text": "Let's try to jump this gap!"
      },
      "npc_hero_reciprocal_look": true,
      "reset_reciprocal_look": false,
      "finish_events": [
        {
          "type": "move",
          "is_npc": false,
          "dash": false,
          "dest": {
            "x": 5,
            "y": 7
          },
          "finish_events": [{
            "type": "face_direction",
            "is_npc": false,
            "direction": "right"
        }]
        },{
          "type": "move",
          "is_npc": true,
          "npc_label": "alex",
          "dash": false,
          "wait_after": 500,
          "dest": {
            "x": 8,
            "y": 6
          },
          "finish_events": [
            {
              "type": "jump",
              "is_npc": true,
              "npc_label": "alex",
              "jump_height": 16,
              "duration": 150,
              "dest": {
                "tile_x": 10,
                "tile_y": 6
              },
              "wait_after": 500,
              "finish_events": [
                {
                  "type": "move",
                  "is_npc": true,
                  "npc_label": "alex",
                  "dash": false,
                  "dest": {
                    "x": 12,
                    "y": 6
                  },
                  "finish_events": [
                    {
                      "type": "face_direction",
                      "is_npc": true,
                      "npc_label": "alex",
                      "direction": "left",
                      "wait_after": 500,
                      "finish_events": [
                        {
                          "type": "dialog",
                          "dialog_info": {
                            "text": "You should give it a try!"
                          }
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

The result:

These are the basics for NPCs. In order to have more examples, please check GSHTML5 default demo.

Clone this wiki locally