• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
mklingen

Why Behavior Architectures?

12 posts in this topic

In AI, it seems very common to want to make some kind of "Behavior Architecture" for ordering and building different ways that agents can interface with the world. I see a lot of state machines, Behavior Trees, HSFMs,  etc. I've implemented these for many different projects (and for my research in robotics as well), but recently I'm starting to doubt their usefulness. 

 

What benefit do I get out of using such an architecture over just coding the entirety of the behavior using modular, native functions and built in control structures (or, if we're concerned about compilation or runtime modification, with simple scripts in a scripting language?) Am I missing something conceptually here?

 

EDIT:

And by the way, what I mean by this is literally interpreting the concept of a behavior architecture as a series of explicit "State" or "Behavior" nodes that interact with each other dynamically as opposed to just straight code calling and evaluating functions in any way the programmer desires. I've been on so, so many projects where development starts with "class Behavior ..." or "class State ..." and then proceeds to link them up in data files dynamically or (much worse) using C macros.

Edited by mklingen
2

Share this post


Link to post
Share on other sites

i've only ever found one type of AI superior to all others.   and its by and large what you describe.    i don't know if it has an official name.    its sort of a combo of decision tree, hierarchical state machines, and expert systems.   well,  sort of...     it layered in a hierarchy, overall its an expert system  - or at least it damn good at what it does, if not expert.  but it does use states, and a a tree type structure as far as the decision process goes.  really, its hierarchy of expert systems.  each one has it own implementation, usually a rule based expert system or state machine / decision tree type stuff.

0

Share this post


Link to post
Share on other sites

Contrasting traditional AI architectures with getting things done with "modular, native functions and built in control structures" etc. is illogical, because they represent different levels: well-written code realizes a certain architecture.

Reading between the lines, you are actually comparing AI architectures: the proven and principled ones vs doing things completely ad-hoc. 

AllEightUp gives a good summary of the practical software engineering benefit of contrasting complicated and open-ended modifications by having a regular architecture with a place for everything, and there's also the more formal benefit of being able to reason about one's AI thanks to its systematic organization. For example, the structure of a behaviour tree makes it very easy to prove that some behaviours can never happen together, and will continue to be mutually exclusive as long as they are behind appropriate selection and conditional nodes.  

0

Share this post


Link to post
Share on other sites

 

 

well-written code realizes a certain architecture.

 

True, but it also provides me the flexibility to change things if I desire. It's very frustrating to spend 20 minutes thinking about how I'm supposed to do a simple switch statement or increment a variable in a Behavior Tree when such a thing could be done with one line of code otherwise. It's also extremely frustrating to spend all of my time writing code about checking which state the agent is in, and formally defining state transitions in a state machine.

 

Overall, you guys make good points about things like predictability, balance, and formally verifying systems.

 

I guess what I really want is this:

 

A behavior architecture which doesn't require me to write thousands of lines of bloated window dressing just to get started, which allows me to do if, else, foreach, while, and switch statements, and which allows me to pass data between behaviors in a natural, easy way.

 

My preferred method of programming is something like this:

// Just a complicated function
function Example(arguments)
{

// I want to be able to evaluate arbitrary arguments.
// Also, I should be able to block for as long as I want
// while waiting on a result.
result = DoSomething(arguments);

// I want to be able to do branching
if(MeetsCondition(result))
{
   result2 = DoSomething2(result);
   
   // I want to be able to short circuit and return
   // something if it needs no further processing.
   if(MeetsCondition(result2))
   {
       return result 2;
   }
   // I should be able to simply pass a variable through
   // as many functions as I please and get a processed result out.
   else return DoSomething4(DoSomething3(result2));
}
else if(!MeetsOtherCondition(result))
{
   // I should be able to dynamically generate lists
   // of results and evaluate them.
   list = ComputeList(result);
   
   // I should be able to easily iterate through lists
   // of results.
   foreach(element in list)
   {
      elementResult = DoSomething2(element);
      
      if(MeetsCondition(elementResult))
      {
          return elementResult
      }
   }
   // Here, nothing in the list met some condition.
   return error1; // (or throw an exception)
}
// I should be able to evaluate error conditions
else
{
  return error2; // (or throw an exception)
}

}

I.e., I like to think somewhat functionally, with a very clear flow of data into and out of functions. I like to be able to iterate over the results of functions. I like to be able to return whatever I please from a function. If I wanted to do something like the above in a Behavior Tree, for example, I would need to do one of two things: 1. turn this into a complex leaf behavior and throw away the return value (or write it to some kind of shared state), 2. I could spend hours upon hours trying to refactor it so it works with the three or four operations I have with a behavior tree, and the fact that I simply can't pass the result of one behavior into another one without serious work.

0

Share this post


Link to post
Share on other sites

I don't know what horrible languages and frameworks you have endured, and how much you have suffered, to consider somewhat uncluttered syntax a success rather than a basic expectation and to associate a rigid (but appropriate) architecture with "thousands of lines of bloated window dressing just to get started", but you are mistaken on both counts.

 

Your pseudocode example is only the bare minimum expectation for a decent programming language; learn nice languages like Python or Lisp variants to see how far good language design can help you.

Regarding architecture, you can implement AI techniques in your own style without bloat (it's entirely possible) but also without allowing them to degenerate into unreliable algorithmic anarchy. The design effort will be repaid the first time you don't throw away an entire incomprehensible, inextricable module because you suddenly find yourself unable to make a change or locate a bug.

1

Share this post


Link to post
Share on other sites

I recently went through 3ish years of a large robotics project where the main focus was on doing complex robotic tasks through behavior trees. There were a couple of limitations on the trees:

  • They had to be binary.
  • They had to return either true or false
  • They could not pass information at runtime between each other as arguments.
  • We had the following conditional operators: Sequence (&&), Select (||), Parallel (*), While, For, and Match (which is a sort of switch).

Each behavior was a C++ class with a single function called "execute" which returned true or false. This function was then called in a thread. To develop behavior trees, we used a horrible combination of C++ operator overloading, macros, and so on. We could then view the resulting behavior tree in a little window with colorful boxes and arrows. The resulting code ended up looking something like this:

// A very high level robotics task. Robot initializes, searches for a rock, and tries to pick it up
// with either its right or left hand.
Behavior& PickUpRock()
{
    return 
        // These are examples of behavior creation macros which take in an ordinary C++ function. They get expanded
        // into something along the lines of Behavior(name, boost::bind(function, argument 1, argument 2, ...))
           BEHAVIOR(InitializeSystem)
        && BEHAVIOR1(SearchFor,"table")
        && BEHAVIOR1(SearchFor,"rock")

        // Choosing left or right hand involves the usage of a cryptic switch
        // statement substitute.
        && Match(IsOnLeft("rock"), 1,
                 Grasp(LEFT_ARM, "rock")
                 BEHAVIOR1(GoHome, LEFT_ARM)
                 )

        || Match(IsOnLeft("rock"), 0,
                 Grasp(RIGHT_ARM, "rock")
                 BEHAVIOR1(GoHome, RIGHT_ARM)
                 );
         
                         
       
}

// This is an example of a sub-behavior which uses arguments
// It is just a sequence of less abstract sub-behaviors.
Behavior& Grasp(Arm arm, string object)
{
  return  CreateGraspSet(arm)
       && PlanToGrasp(arm)
       && GraspPreshape(arm, object)
       && ServoToTarget(arm)
       && CloseHand(arm);
}

// Many thousands of lines defining all the sub-behaviors follow in multiple files... 
// At the very bottom we finally get to write straight C++ code. It will usually be just a dozen or so lines. 
// If the Behaviors fail to compile you will get very cryptic error messages from boost and STL.

You can see that what's happened is we've just created a less useful, harder to write meta-language on top of C++, instead of using C++ directly. Even worse, we were forced to use static singletons everywhere just to transfer data between behaviors. This led to things being extremely hard to debug, since we couldn't easily infer what data was getting changed where by which behavior. Contrast this with simply writing the whole thing in an ad-hoc script, where you can store local data and very clearly see where the data is going to and where it comes from.

 

I've yet to find a BT implementation which doesn't involve either extreme verbosity or crypitc meta-language symbols.

 

Take for example this library, which in its main example, takes dozens upon dozens of cryptic lines full of "news"  to make what is equivalent to a few function calls and a while loop within if/else brackets -- or perhaps this library, which uses cryptic C# operators to make a meta-language, much like in my example. I'm beginning to suspect that the whole drive behind BT is to make it easy to create plug-and-play graphical programming in an editor (why you would want to do this if you're not writing middleware for non-programmer designers I have no idea).

 

Is this how BTs are really used in the industry? Is there a better way?

Edited by mklingen
2

Share this post


Link to post
Share on other sites
I guess what I really want is a behavior architecture ... which allows me to do if, else, foreach, while, and switch statements, and which allows me to pass data between behaviors in a natural, easy way.

 

I notice the above desires describe almost exclusively one type of thought process: Production Rules. Production Rules represent procedural knowledge, and generally take the form of "if-then" propositions. Given a scenario, draw an appropriate response. Production rules are a variant of memorization; they involve storing information and then later retrieving that information for use when conditions are met. So if you find that your application has a lot of use for that type of thinking, then it might be appropriate to investigate advances in information storage and retrieval.

 

For example, let's say that our application examines an entity and activates a response based on that observation. A nieve and rather poor implementation would be a long string of If/then statements. A sleightly better version of the same thing would be a long switch statement. A much better version is an associative array, such as a dictionary or hash map which encapsulates the key->value storage and look-up association.

 

Note that Production Rule thinking is only one of several types of thought processes we use. There's also the "is-a" Semantic Network relationships, the "has-a" Object Frame relationships, minimally detailed Mental Models of "how" stuff works, and Memory Organization Packet lists.

Edited by AngleWyrm
1

Share this post


Link to post
Share on other sites

I'm not saying that's the only way I wish to do things, but rather that I would like to be able to do it easily within the confines of a behavior architecture. Production rules are a basic building block of computer programs. They should be in any behavior meta language as well. They live in BTs as selectors and sequences. They live in FSMs as state transitions. In my opinion, not only should they be in such an architecture, they should be very easy and intuitive to implement. 

0

Share this post


Link to post
Share on other sites

I could make the case that programming languages and compilers add limitations onto what you could do writing straight up machine code. After all, aren't "if/then" statements just a branch in machine code? Why deal with all that messy stuff with variable passing when I can simply look something up at a memory location or in a register? I mean, do programming languages and compilers offer any value whatsoever? It all seems so complicated. 

0

Share this post


Link to post
Share on other sites

A better analogy would be *writing the entirety of a programming language and a compiler* every time I want to start a new project. By hand. And then debugging the underlying compiler and programming language before I even begin writing applications. And worse, the rest of my software is still all written in machine code.

 

Then, I've got to write tools for my new language in machine code. I've got to write authoring software. Debuggers. I've got to teach new people on the project my fancy new language. I've got to come up with style conventions. I have to handle corner cases.

 

Luckily, with high level programming languages, somebody already did that stuff for me decades ago.

 

Not so for these hand-rolled meta languages.

Edited by mklingen
2

Share this post


Link to post
Share on other sites

Perhaps state machine mechanics, decision trees, etc., should be provided as optional tools, rather than as a framework - er - into which - you must plug.

 

My team once implemented co-routines (that is, the ability to "Yield" and have processing resume from the same spot next frame- so as to wait, in the middle of a logical flow - for a condition to be met) because we were sure it would make behaviors easier to write.  It didn't really.  A stone-age switch-statement state-machine was just as clear, and effectively as simple to use.

 

Although I have to admit, I have occasionally daydreamed about a graphical state machine tool.

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0