6
\$\begingroup\$

The idea

I have an idea for a game. A few games, actually, that can built on top of the same general design.

There is a game world that the player and the other actors exist in. The player can get information from the world about his surroundings. The player can also interact with the world, picking up an object for example. Now, I would like the same thing to be possible for other, scripted actors. They are the player's competition. Instead of navigating the world and performing actions based on human input, a script should decide what they do.

An example

I want to do this using a 2d world eventually, so I might as well give the example I want to build:

There is a 2d world with objects of various sizes and shapes. Every actor has their own field of view. They get information from the world about the objects in their field of view. For the player, this information is displayed on the screen of the user. The player navigates the world by user input.

Scripted actors navigate the world in a scripted way. They walk in a general direction, they follow a wall or things like that. Their scripts should be able to get the information about the objects in their field of view and act on it. If an other actor is detected in their field of view, they should walk in that direction for example.

All of this should happen in pretty much real-time.

The information gotten from the world (showed to the player, and given to the scripted actors) in this case would be something like a collection of "what", "where", and "in what orientation".

The question

My question is: how I can program this effectively and efficiently?

I am thinking to build this with C and Lua. C++ is also an option. I would store the game state and display the graphics using C. The part that I don't know how to handle is the interaction between C and Lua. Not programming-wise, but design-wise. The interaction between the world and the scripted actors.

Should C provide the Lua actors with information, and then have the Lua actors call C functions that change their direction, move a step forward, etc? Will this work in real-time?

I realize that this question is broad, but I think it's not unreasonable. There are obviously ways to do this and I would like to know some.

\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

I'd recommend not writing long scripts for actors, and instead just having each script be an instant 'reaction' script - ie. it runs and terminates quickly and decides a state for the actor to be in. So, I'd implement a few event handling functions in script, to be called as a result of significant in-game events, and an update script which is called once a frame or something. Pass in a small amount of context about the event in question, and the script should be able to call back into C++ functions to query the environment, set new objectives, etc. For the most part the important changes to behaviour and state should occur on the C++ side: the scripts should be limited to querying the current environment and quickly making a decision, passing that back to the engine.

So for example, you don't continually call a script which then calls a C++ function to say "take a step forward", you call one saying "move me to X,Y" and then the normal C++ update loop will do that without reference to script for the next few seconds. When you arrive, you might call a script (eg. 'on_arrival') where the NPC can choose its next goal.

I don't recommend trying to run actors via long-running scripts with lots of loops, conditionals, and storing state within the script, because this quickly becomes a concurrent system, and concurrent systems are REALLY HARD. If you use native threads to handle each character, you're going to hit multithreading bugs very, very quickly, unless you fully understand the implications of such a design (which sadly can't be explained in a single StackExchange post). If you decide to use some sort of user threads (eg. Stackless Python tasklets, Lua coroutines, etc) then you still need to understand the implications of cooperative multitasking - eg. being able to yield up control to other actors (ie. why while (1) { do_nothing(); } is not going to work for a sentry), and also to appreciate that even if your game is 'thread safe' the logic is not necessarily 'coroutine-safe' - a variable in one coroutine can easily become invalidated by another.

eg:

function duel():
    self.aim_at_foe()
    self.shoot_foe_dead()
    self.celebrate_victory()

a = new Sheriff()
b = new Outlaw()

run_both_at_same_time(a.duel(), b.duel())

What happens when the loser (whoever it is) tries to execute 'self.celebrate_victory()' and your system discovers that 'self' now refers to a dead actor? Or if it's reference counted, what if it allows a dead actor to celebrate his victory?

Of course, some people are used to this sort of problem and know what they're doing; anybody in that category can ignore much of the above. :)

\$\endgroup\$
2
\$\begingroup\$

I would recommend to use C++ and polymorphism (one of basic principles of OOP).

You can create a general Character class. It contains character's location, position in the world, inventory and other data, also virtual functions for updating and rendering character. Than you can subclass it with NPCharacter and PlayerCharacter.

Method PlayerCharacter::update() listens to user input events and updates Character's state accordingly.

Method NPCCharacter::update() implements some AI logics and controls NPC in any way you want.

You can create LuaCharacter also. LuaCharacter::update() simply calls Lua script that does the same thing as NPCCharacter, but from the script. Some games really call Lua script every frame. If you are concerned about performance, it is better to minimize Lua calls, you can use Lua to implement callbacks and listeners to user input or other events only (no need to call these scripts every frame).

foreach (characters as character)
   // we do not know what type of character it is - Player, AI, LuaScripted etc.
   // they all are updated in the same manner
   character.update(); 

The same can be done using composition and component-based approach, too. Just add different components to your game objects. For example, AICharacterCleverComponent, AICharacterDumbComponent, LuaScriptedAIComponent, PlayerInputControlComponent etc.

\$\endgroup\$
3
  • \$\begingroup\$ Without polymorphism in the entity (your "Character"), this can also be accomplished with an abstract AI base class and derivations, PlayerAi, NpcAi, LuaAi, etc. Even better perhaps would be for it all to be Lua controlled, and the Lua could do the controller "AI" processing. \$\endgroup\$ Oct 1, 2010 at 0:26
  • \$\begingroup\$ This is basically how it worked in the one game I worked on using Lua. Each thing that wanted Lua control had a LuaComponent, and that component had its own Lua VM which got a single 'tick' per frame. I can't say that it worked great, but it did result in a shipping game. \$\endgroup\$ Oct 1, 2010 at 0:27
  • \$\begingroup\$ True. Thank you for an addition to my answer about components. I'm really a fan of component-based approach. \$\endgroup\$
    – topright
    Oct 1, 2010 at 1:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .