Had some trouble logging in to my site (Weebly kept getting caught in a log in loop) but eventually solved it by just using a different browser. Which I could really have done with thinking of earlier...
Anyway, I have a number of projects on the go now: I am now a member of the Pixel Spill studio!
I'm still faffing around in Unity though in my spare time, and I've picked up a few tricks that might be worth passing along...
Dynamic State Systems
Mostly I build this pattern in response to a problem I was having with character controllers. In the interests of code re-use, I wanted the player to simply be an 'Actor' driven around by their input, whilst AI characters were 'Actors' pushed around by their AI overlords. Functionally, these Actors are the same.
However, I didn't want all Actors created equal; for example some simple enemies just need to be able to move, but the Player needs to be able to run, jump, crouch and do all manner of wonderful things. The natural solution is to simply use a class hierarchy - HumanActor: Actor in my case - but how to build in a state machine whilst also supporting polymorphism?
Another related issue I was having was essentially a form of 'property bloat', where I needed to define various parameters repeatedly for different states (ie speed when crouching vs speed when standing vs speed when falling through the air and so on).
Ultimately, I solved this by transferring state mechanics and paramaters to nested classes. The basic code is as follows: (Pastebin)
The core feature is that the states themselves and their unique behaviours are defined in custom, nested classes. We keep a dictionary of these classes, allowing us to set state by passing a string as input; child classes can thus add more states by expanding that dictionary. In my case, I had an Actor class with a GroundState and an AirState, and HumanActor which also introduced a CrouchState.
As a bonus, because the State-unique properties are defined in the state itself, you get a collapsible rollout in the Unity Inspector! Making things much easier to handle.
There are a few 'gotchas' - the most obvious being the 'what happens if I use a string it doesn't recognise', which is fairly easy to catch. The other is that you need to initialise every state on startup; otherwise the state class won't know what it's supposed to be controlling and you'll probably get flooded with null reference errors.
You don't have to use strings, of course: I just used them here to support polymorphism. If that's not a problem, you can just as easily ditch the dictionary and use an enum of states and a switch statement in SetState instead (which I've done for my game camera).
Another curious 'gotcha' I ran into relates to a bug in Monodevelop. I had a camera script that, amongst other things moved itself around to orbit a follow target according to mouse input, but I wanted it to have extra modes of functionality (like being able to detach and move around independently), so I built it a state system similar to the above.
As there was no point in re-typing the old orbiting code, I just copied it over into the Follow State's Update() function, using properties in the base CameraState to link to the camera's transform (so I didn't have to change everything to owner.transform), again as in the pastebin code. This worked in the other Camera States I made which also changed transform.position etc in their own way, but with this copied one I got an error stating a nested class couldn't access an instance property in its parent. Even though Follow State had a transform property, Monodevelop still thought it was referring to the monobehaviour's transform property. Simply re-writing the offending line (without actually changing anything) solved it; it appeared to be a case of Monodevelop's metadata shooting itself in the foot.
Hope this proves useful! I have a few other topics I've picked up to talk on, and a log of development I hadn't been able to post until now, but that can wait.
Anyway, I have a number of projects on the go now: I am now a member of the Pixel Spill studio!
I'm still faffing around in Unity though in my spare time, and I've picked up a few tricks that might be worth passing along...
Dynamic State Systems
Mostly I build this pattern in response to a problem I was having with character controllers. In the interests of code re-use, I wanted the player to simply be an 'Actor' driven around by their input, whilst AI characters were 'Actors' pushed around by their AI overlords. Functionally, these Actors are the same.
However, I didn't want all Actors created equal; for example some simple enemies just need to be able to move, but the Player needs to be able to run, jump, crouch and do all manner of wonderful things. The natural solution is to simply use a class hierarchy - HumanActor: Actor in my case - but how to build in a state machine whilst also supporting polymorphism?
Another related issue I was having was essentially a form of 'property bloat', where I needed to define various parameters repeatedly for different states (ie speed when crouching vs speed when standing vs speed when falling through the air and so on).
Ultimately, I solved this by transferring state mechanics and paramaters to nested classes. The basic code is as follows: (Pastebin)
The core feature is that the states themselves and their unique behaviours are defined in custom, nested classes. We keep a dictionary of these classes, allowing us to set state by passing a string as input; child classes can thus add more states by expanding that dictionary. In my case, I had an Actor class with a GroundState and an AirState, and HumanActor which also introduced a CrouchState.
As a bonus, because the State-unique properties are defined in the state itself, you get a collapsible rollout in the Unity Inspector! Making things much easier to handle.
There are a few 'gotchas' - the most obvious being the 'what happens if I use a string it doesn't recognise', which is fairly easy to catch. The other is that you need to initialise every state on startup; otherwise the state class won't know what it's supposed to be controlling and you'll probably get flooded with null reference errors.
You don't have to use strings, of course: I just used them here to support polymorphism. If that's not a problem, you can just as easily ditch the dictionary and use an enum of states and a switch statement in SetState instead (which I've done for my game camera).
Another curious 'gotcha' I ran into relates to a bug in Monodevelop. I had a camera script that, amongst other things moved itself around to orbit a follow target according to mouse input, but I wanted it to have extra modes of functionality (like being able to detach and move around independently), so I built it a state system similar to the above.
As there was no point in re-typing the old orbiting code, I just copied it over into the Follow State's Update() function, using properties in the base CameraState to link to the camera's transform (so I didn't have to change everything to owner.transform), again as in the pastebin code. This worked in the other Camera States I made which also changed transform.position etc in their own way, but with this copied one I got an error stating a nested class couldn't access an instance property in its parent. Even though Follow State had a transform property, Monodevelop still thought it was referring to the monobehaviour's transform property. Simply re-writing the offending line (without actually changing anything) solved it; it appeared to be a case of Monodevelop's metadata shooting itself in the foot.
Hope this proves useful! I have a few other topics I've picked up to talk on, and a log of development I hadn't been able to post until now, but that can wait.