incrementally npc

In building this game world as it is, filled with floors and walls and shelves and light swtiches and everything else, I knew I was eventually going to run headlong into what I perceived as my biggest challenge: the NPC.

What is an NPC? For all you non-gaming folks out there, the term NPC stands for Non Player Character, or anything in your game world that is for all intents and purposes “alive” and mobile. Mostly though, the term NPC refers to the people, animals and (in some games but so far not mine) monsters or enemies.

The thing is, it is all fine and simple to build a wall or a shelf, but it’s a whole other undertaking to build in code something that has behaviours—behaviours like walking around the room and interacting with objects and having conversations with the player, et cetera, et cetera. 

I mean, think about it this way: to move the player around the screen I have (of course) lots of hard rules built into the system about boundary collisions and input directions and all of that can be negotiated in real time by a human being playing the game with a brain inside their head poking at a keyboard.  

But on the other hand, an NPC needs to be literally programmed to do things in the game. These are not magic or automatic. They are code, and carefully plotted tangles of logic loops. Like, simply to appear to move, an NPC needs to have a route to follow around the room, a kind of connect the dots map, and then of course to follow that map completely independently of whatever the player (with the aforementioned brain) is doing in the foreground and too, while everything else is going on. In every frame of game time, a hundred times per second, I need to have coded in a “what do I do now” kind of command that also tracks a “what have I already done” and a “what do I need to do next” and “where the heck am I in this multi-dimensional universe anyways” state of existence. 

Sounds pretty straightforward, huh?

To be fair, it is only just mathematics around geometry and timers and coordinate planes and incremental counters, joined together in an elaborate choreography upon an invisible stage that needs to itself be tracked and moved in perfect synchronization with the player movement and the more little factors that are considered the more lifelike it all appears until the player (and sometimes event the programmer) forgets that the little pixel art moving around the screen isn’t really a person or an animal and is instead a picture being projected in perfect and elaborate lockstep to everything else already going on.

The game kinda resembles a digital layer cake of geometric planes. For our purposes in discussing the NPC challenge, there are three key layers: 

  1. the player layer on top which is little more than a picture (that never actually moves anywhere) of a little dude moving his legs or whatever, 
  2. the room plane on the bottom, which is a grid map to which every square of a matrix of about thirty by thirty is bolted an image of a single floor tiles or a single wall, maybe a single decoration or a single object, or aything else that doesn’t move, essentially a thousand times over to form a literal gridded map that comes together to make the picture of what looks like a furnished room, and 
  3. an NPC plane upon which the in-game life-forms persist through time and are continually moved  from square to square like upon an invisible chess board, revealed when they are in the same room as the player or hidden when not.  

When the player moves anywhere—around the geometry of a room or through a door to another room—both the room plane and the NPC plane shift around on the screen.  It’s as if—to go back to the chess analogy—you were holding your player piece still in your hand just barely above the board and someone was shifting the board around under your piece.  And then you held your piece in the air while they swapped everything out for a new board from another game, over and over, every time you made your move in one game, swapping to the next board, for thirty five different boards. 

Convoluted, huh? 

It really kinda is, and so you see the challenge I faced.

how does this all work, really tho?

Like everything, though, I worked through this incrementally.:

Can I spawn that middle layer? Yup.

Now, can I spawn an NPC sprite onto that middle layer independent of the other two layers? Ok, that works, but it doesn’t move relative to the player.

Okay, so can I make my NPC sprite seem to stand in one spot in the room? Yes. I lock the coordinate geometry of the NPC plane to the plane of the room.

Next I need to make it move around realistically relative to the room, so can I do that? Well, I add a coordinate path vector and loop through that moving the NPC around on its own plane while tracking its progress along the track.

Okay, can I do that with more than one NPC in different rooms? Sure. Add a conditional loop to spawn a second NPC linked to a different room id.

Oops, now both NPCs appear in both rooms, each following their own path, can I fix that? Of course. I trigger a check and change in visiblity when whenever the player moves rooms. 

Great, but now how do I interact with my new NPCs? Um. One more system to check if the player and the NPC “collide” geometrically in game plane maths and then pass that state along to the rest of the game to await further instruction.

Yikes. It works.

The result of all this is a complex—but actually robustly elegant-ish—tool that lets me spawn as many NPCs as I may need in the game simply by adding new “data” to a file with some simple starting and trigger variables. I even tested having 250 spiders walking around one room just to check and it seemed pretty solid.

The whole process of building this game has been something like this. 

Ask a question, then increment through the solution until something works, then refine until it works well. Then move onto the next question.

Game design, huh?

Comments

Leave a Reply

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