So far I have looked at motivations for scripting and the visual vs code approaches to scripting. Now I am going to talk about some of the specific formulations I have seen. Most of these can work either as visual or code implementations, and I have seen functional versions both ways.
The most straightforward is a script blob. You write some data and some logic, get it loaded, and then from someplace else it is magically invoked. It's flexible and powerful, and you could build anything you like on top of this.
Realistically, even if this is the underlying system, this is probably not the level at which you want most of your scripting to work. Looking back at motivations, this (maybe) gets you rapid development, but probably doesn't help with most of the other motivations.
A fairly common refinement on the code blob is the job/tasklet/strat/node. The difference between this and the blob is that there is a predefined data pattern and update mechanism that the script is operating within. The job will have a predefined entry point and may have one or more predefined data slots. This system may or may not differentiate between loading and activating a script. Once a script is activated, it is added to the list updated by the "script tick" and the entry point is invoked each script tick.
Having used this pattern several times, I know there is a lot of power in it. There is enough structure so that adding new functionality is quite easy. There is lots of flexibility, so you don't end up gerrymandering things in order to add broad functionality. As Scott pointed out in the comments, it is easy to have streaming functionality under a system like this.
It can fall down in a couple of places. The main one is as you tackle specific tightly constrained domains. Though it is structured, because the support offered is still high level you can end up doing a lot of work to support tailored functionality - e.g. animation state. You can also end up doing work in script that might be better done in code, such as an animation state system. For simple things this is not a huge problem - but things love to accumulate complexity.
The most venerable form is perhaps the finite state machine, with its many many children. FSMs are great for decomposing problems into neat little chunks. They can be excellent for dealing with time and synchronization (or not dealing with time as the case may be). When dealing with specific domains, like animation, props, AI, or world state, state machines allow you to address the problem directly and intuitively without having to worry about framework.
The drawbacks to FSM are well documented. Aside from the scaling issues of FSM (which provide much of the motivation for derived models like HFSM), there are performance and representational issues. While FSMs are easy to conceive, it can be much more difficult to build irregularly updating FSMs. Or to phrase it another way, many FSMs are based on a polling or tick model, rather than an event-driven model. In situations where you have a lot of FSMs that are inactive until poked, you can have difficulty optimizing performance. This is less about the model than the implementation, but I bring it up because converting late from polling to event-driven can be very painful.
On the representational front I have been finding that more and more of the interesting activity is about transitions rather than states. Looking at the animation and AI I have worked on recently, much more time is spent building and performing transitions than state. Particularly for animation I have begun to think that the notion of a steady-state is not terribly useful - especially when you are looking at characters that are performing multiple transitional blends simultaneously on different parts of the body.
Another fairly common approach is to use a tree structure for representing script. I have seen this used in a couple of different ways. One way is similar to what in AI circles is called a behavior tree. Each tree node is a script with a precondition. The tree is evaluated from the root and the first child node with a true precondition is run. The most traditional approach to re-evaluating the tree is to restart either from the root or the parent of the current active node. Other schemes can involve designating successor nodes.
Trees share a lot of the FSM's strengths, while providing several additional benefits. Trees are easier to represent visually than graphs. The indirect nature of the transitions in a tree are also a potential advantage. New nodes can be added to the tree without having to touch prior and successor nodes to add transitions.
The indirect nature of the transitions can be as much a problem as a strength. For simple hierarchies it can be easy to read the transitions. For more complex hierarchies, in addition to the visual muddle of the FSM you have to deal with figuring out what the possible transitions are.
One representation that I don't see as often as you might think is the timeline. While popular for video and sound, it is limited mostly to UI in games. I think it could offer a lot, especially for time-sensitive domains such as animation scripting.
Just within the five general categories I have suggested there are about a million variants. Any one have a favorite or a type I have totally missed?
Monday, April 12, 2010
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment