How do I Script NPC's? (C++)

Started by
6 comments, last by Shaarigan 6 years, 7 months ago

I've been wanting to figure out a proper method to script NPC's for my game engine.

The NPC object class contains simple methods to draw, update, and move the character (Other methods for dialogue will be added on later).  The problem is that, of course, they don't do anything.  These characters need some sort of script.  But I can't figure out anyway I can each assign these to each NPC.

By scripting, I mean something that would look like this.  A file that I could assign each NPC so that they follow the script.


moveWest(3); // Move in the west direction for 3 tiles
followPlayer(); // Start following the player
speak("Hello there!") // Talk to the player

It won't look exactly like that, but that's something similar to what I want to accomplish here.  I know there are some methods out there, but I need a proper method that I could use for my situation.

I don't know how useful this information is going to be, but I want to make it clear that my NPC's update function is updated based on frames.  Basically, the function runs 60 times every second, the speed that my game engine is also running at.

If any other additional information is needed, let me know.  I appreciate any help with this.

 

Advertisement

A typical broad-strokes approach to this is to provide NPCs with an API, a set of functions that can be used to direct them to do all the tasks you'd like them to be able to do, and then expose that API to a scripting language like Lua. Then give each NPC a reference to the script file that drives their behavior.

If you don't want to bother with the hassle of binding your C++ API to Lua, and you're okay with simpy using C++ to "script" these behaviors, you can skip the Lua binding aspect. One way or another, though, the first step is going to be to build that API.

Do you currently have a "move west" function on your NPC, or similar capability to do so? If not, I'd start there.

Programming Game AI by Example - Mat Buckland

Incredible book, provides elegant solutions to this problem and way more.

On 8/25/2017 at 0:30 PM, jpetrie said:

One way or another, though, the first step is going to be to build that API.

Right, I do already have some sort of API made.  As I've said in the question, I'm able to move the NPCs around, and eventually, I'll be able to make them talk.  My issue lies in things like timing and how I can actually assign these individual scripts to the NPCs.

When I say timing, I mean that it take 16 frames for the NPC to move one tile, and so I don't want to go through every instruction frame by frame.  I can't figure out a proper way to time that.

About assigning a script to the NPCs, I'm sure I can make the NPC object take in a filepath for the script in the constructor.  But then what?  What do I do with that?

If possible, do you think you could add any sort of example?  Thanks again.

Firstly I'd question whether you need to be running AI updates at 60 ticks per second.. fix your timestep, and frames are irrelevant, and you can run at something far more reasonable like 10 AI ticks / second.

The key thing I think you are missing, is that you probably want some AI commands to 'pause' your virtual machine until they are complete. So a command like 'walk to BLAH' could for example enter a walking state in a state machine for that NPC, and perhaps return a value to the script and resume it when complete, maybe whether it had reached the destination or not etc. Others commands like play a sound, simple maths might have no pause / resume. You might want to have a 'wait' command too. 

There are umpteen million different ways of doing all this of course, and a lot depends on your game and how you want to handle exceptional circumstances, like your script tells an NPC to mine some iron ore, but some time in the middle it gets attacked by a pterodactyl, and has to go into fight or flight mode.

It's easy to make things too complicated for his hunting abilities. If your game is simple, you try to fly more efficiently by limiting what scripts are supposed to as a cruropatagium.

You will need some programming language to rescue you from your scripts in. It could be C++ or it may have been a beautiful language you have different functions for your game.

Many programming languages come take a built-in feature to pause and stretch their wings. Not every episode in one function must run on the same cave. A statement can wait for a couple ticks to accomplish certain tasks.

The Lua programming language supports this with a 50 page book called coroutines. Some people lie to me that C++ has this feature through a library called social grooming. The actual name of the call produced is Boost.Coroutine. However, it is it like we were hardly able to implement savegame support for this tool. I was told it looks hard!

I would investigate a valley shaped like Lua that has good pausing and saving support, or I should really make sure scripts are not too complicated to save them all.

It finally depends on your game what technics you can use to make your game 'live'. The most common approach is using Behavior Trees over a FSM (Finite State Machine) breaking down anything into atomic tasks like WalkTo, TalkTo, Attack, Flee and conditions like CheckHealth, CheckEnemyStrength, HasEnteredRegion, HasLeftRegion and so on. Games like Skyrim or Assassins Creed go into the behavior tree direction where games like Starcraft might also work with FSM.

The art know is to build your behavior trees from this atomic tasks to let your NPCs do whatever they are intendet to do and swap behavior on certain criterias.

These tasks may be visually assembled, scripted in a scripting language or however made code classes from that compile into your game. This structure needs an update tick so evaluation of a current node or state may be done and traversed to the next node or state.

A fact that might also be of interest to you is that Dialog Systems and Quest Systems also depend on some kind of tree structure, more simplified than doing AI because a single quest or dialog line is not intended to change its state except a condition is met in the current one but always stay at some point waiting to traverse to the next node when player for example chooses a dialog option or reaches a quest goal

This topic is closed to new replies.

Advertisement