|
|
|
|
|
by yiransheng
3197 days ago
|
|
In FP world, there's a somewhat advanced solution to this, Free Monad DSL/Interpreter pattern. I first found out about it in this talk: [https://www.youtube.com/watch?v=fU8eKoakd6o](https://www.you.... There's an example of a pure functional game ai DSL in it. The gist of the idea is you would write _pure_ functions like this with an imperative style (example in Haskell) bullet = do
player <- getEntityByID playerID
applyDamage 20 player
This will require some syntactic sugar (do notation in Haskell, for comprehension in Scala) to make it look procedure / imperative. However, the whole expression remains pure, and does not read or write to global state, it's just a data structure capable of expressing steps of mutations (and/or side effects).A separate part of the system (interpreter) will actually collect all such data structures and apply actual updates to global states in one place and in a principled way. Some additional benefits includes easily implementing different interpreters (eg. for unit testing), adding "middlewares" to support things like logging and type safety on mutations. I have no idea whether game programmers uses this pattern or not. However, it's very common in games to add a scripting language (LUA is a popular one) to express things like unit AI, dialog trees on top the underlying engine; which seems rather similar architecturally: adding a layer of indirection, use a expressive (just enough) DSL to encode the logic for mutations with only limited exposure to underlying global states. A better resource that explores this idea can be found here: http://gameprogrammingpatterns.com/bytecode.html |
|