4 ms·
I am a great lover of functional programming, so much so as to seek out and find a summer job in Clojure this year, and to have written my own functional Lisp d
by jarcane 11y ago
I am a great lover of functional programming, so much so as to seek out and find a summer job in Clojure this year, and to have written my own functional Lisp dialect.
Lately though, as I've been weighing engine options for a CRPG project, I have become increasingly skeptical of its applicability or utility to games.
The simple point of the matter is that games are humongous state machines, but even more importantly, humongous state machines that are performance sensitive.
The standard approach so far has been to simply deal with this either monadically or atomically, having some big state object that gets passed through each cycle, copied again and again with every frame. This is all well and good when the full extent of your game state is a handful of blocks and a paddle, but stop and think how many, say, console-style RPGs you've seen done in functional languages to completion.
In the Pokemon games, there is a move called Defense Curl, that increases the users defense. Simple enough. Then in the second gen games, it was very silently given another effect: there is a particular attack move whose damage is doubled if the user has previously used Defense Curl in that fight. In the third gen, this was done again for an additional move that, at the time and for three more iterations of the series, was only available to a single character.
That is an incredibly specific state detail. And that's just one. The entire game is filled with little quirks and mechanical details like that. There are over 600 moves in the game, many with other unique effects, not to mention the 700+ creatures, almost 200 abilities, plus an entire hidden second stat system with the IVs.
Try passing a state object containing all the flags you need to keep track of that 30 or 60 frames a second.
Is it any wonder then that you see so little done with FP languages that isn't just clones of old arcade games? I know of one company working on an A-level game in Haskell. Beyond that, I've seen a couple Quake 3 ports and a whoooole lot of unfinished projects.
I'm just not convinced it's up to the task yet, and the research and theoretical end still seems to focus on trivial toy examples instead of full-scale projects that are on a whole other order of magnitude from Pac-Man. I seriously start to wonder how much of the learning so far and the 'obvious' patterns and solutions that seem to already just be accepted dogma, really have anything to do with real-world games programming in the large.
Maybe Wayward Tide will finally release source and prove me horribly wrong here, or Elm will indeed prove as promising as it looks when extended beyond simple browser toy experiments, but in the meantime I'm veering hard back to commercial, traditional engines instead.
- whateveracct 11y agoPokemon rules would probably be wonderfully modeled as ADTs. Every "modifier" could be in a big sum type and then you would just express all your rules explicitly in terms of the current modifiers in play along with pokemon stats, type, and moves. In the end you have a function State -> Move -> State. You would take inputs, and apply them with the current state to get the new state. You would encode all your rules in this transition function.
- fallat 11y agoOr maybe, FP is the wrong tool for that job.
- alkonaut 11y agoA real world megabudget game has the money to make a high perf C++ state machine, make all the microoptimizations and platform tweaks necessary to reach the time budget for each frame on each platform. As soon as a more efficient tool promises something that can save time in development, of course it is adopted. Scripting languages are used in many enginess for example. The engines themselves seem to be firmly in C++, but I think this is at least as much down to available dev skill, tools etc. Large games Will probably not go from C++ to Haskell, but instead (hopefully) from C++ to Rust, where the developer can choose a more elegant functional approach where possible, and will still have compiler guarantees about the parts that are mutable.
- dllthomas 11y ago"Try passing a state object containing all the flags you need to keep track of that 30 or 60 frames a second." You can structure your data such that you only need to rewrite a portion of it, based on what changed. I couldn't more highly recommend "Purely Functional Data Structures" by Chris Okasaki.
- dllthomas 11y agoFollowing up on this... With regards to the Pokemon example given, I can think of two good ways to encode it: First, simply a bunch of single-bit flags, one per move per competitor. Each turn, for move tracking, we update at most one bit in one of these arrays by copying the array and updating a pointer. We can track 1000+ moves, and only need to copy 128 bytes. You can do thousands of comparable things and still be done in a single frame. Second, a list of turn information. A move could ask arbitrary questions about the history of the current fight by walking the list. An append-only list trivially has an immutable sublist, and you only need to "pass" a single pointer. Walking the list should be trivially possible well inside a single frame, provided you don't have many thousands of turns in a single fight. All that leaves aside the fact that you don't actually need to fit your world updates in a single frame render - you can interpolate/extrapolate. This is especially easy in a turn-based game like Pokemon, where it mostly consists of "smoothly progress through the same animation".