I’ve been working really hard on a turn based RPG project, and we needed a simple AI solution to allow us to easily create different behaviours for different monsters.
Eventually I settled on creating a sort of swappable AI brain that we could attach to any AI character.
The way the AI brain works is pretty simple! What I’m most proud of is the extremely modular and extensible nature of the AI system I created.
The way the AI works is very simple at a basic level. The GetMove function does all the hard work. I pass in the current BattleSystem, which is the encapsulation of a single battle—it holds all the information necessary to hold a battle. That is, all the party members in the fight, the special modifiers on the party members, where they’re fighting, and more.
With this simple structure, I was able to create basic AI very easily. An AI that uses a skill randomly against a random opponent was trivial.
It feels so good to be able to create such a thing so quickly! I created a bunch of different ones for basic use in the game. A attacker that always attacks the lowest HP enemy, an attacker that attacked a specific class more frequently, a healer that supports its teammates… it was all very simple to create! I could add as difficult or simple logic into the GetCommand function as I wanted!
The fact that my AI brain architecture was so easily extended made more likely to play around with it. Eventually we wanted a sort of AI that could do multiple things. We wanted an AI to heal friendlies if they were low, revive friendlies if they were dead, and then dispel friendlies and enemies based on the context.
I could have written a huge AI class just like I created the SingleAttackAIRandom class, but I realized that I already had all the little parts to this semi-complex AI already! So then after much pondering I started creating a new AvAI class… that holds AvAIs!
This ConditionalAI is very simple! This AI merely holds a bunch of AvAIModules, which are wrappers for AvAIs that also hold a conditional. The module merely nullifies the wrapped AI’s output if the requisite conditionals aren’t met. Whenever the ConditionalAI is asked to return a move, it starts asking at each AI module in order. If the module returns null, then the move has been nullified by the conditional, meaning the condition wasn’t satisfied. If one of the modules is satisfied, then it will return a legitimate move, and the ConditionalAI will just spit that back out!
The result of this isn’t crazy cool or amazingly groundbreaking, and might be very obvious to some people, but it was very neat to me to be able to write AI by snapping AI blocks together. It makes it easy to program a huge variety of different behaviours, each getting more and more complex! I’m pretty proud of myself for making such a cool, extensible, and easy to program AI system for this game.
Did you know you can easily draw your own Gizmos for the scene view using a simple magic method? I sure didn’t. I had to create a tree visualization structure for the editor for the game I’m working on, and I was dreading the day I would have to get into Editor scripting just for this tiny thing.
Luckily, I don’t have to!
The magic method void OnDrawGizmos() and void OnDrawGizmosSelected() is all I needed to get this effect. OnDrawGizmos() is like an Update() function for when you’re inside the scene view. The “selected” variant is the same thing, except that it’ll only run if the object is selected in the editor.
In my OnDrawGizmos() function, all I did was loop through all child nodes and draw 9 lines for each. Why 9? Well, one line is to connect the two, and the 8 remaining lines are to draw the little arrow thing. There’s a way to use Handles.ArrowCap() to do the arrow drawing, but I like the wireframe look.
In the sample code below, you can see the rough structure (and a good one) to handle the drawing you see above. The DrawConnectedGizmos() function is nicely separated—all that does is do the maths for the arrow drawing. I used a very helpful script for the arrow drawing here.
For the text on each GameObject, I used the Handles.Label(Vector3, string) method. It’s rather straightforward. Just put the place you want the text to appear as the first argument, and the text you want to display in the second.
Once you finish, you’ll gasp at the results! Or at least I will.
I thought it was about time to update Zarvot’s main menu to make it look less crappy. I was heavily inspired by a lot of different games, but namely the mobile Hitman title. I absolutely adore how the developers made the game feel so physical! With light usage of Unity’s PBR system, it’s rather easy to create physically accurate lighting.
The great part is that I already made over 10 different “lighting schemes” that can interpolate to each other. I can then just trigger a random lighting scheme every time the game is started, for extra visual variety!
Above image rendered with Unity 5. Guitar was modeled from scratch in Blender and textured in Substance.
Substance is amazing. It allows you to texture according to PBR standards ridiculously easily, as long as your mesh is well made. The coolest thing to me is the fact that I can easily texture different parts of the mesh with different “materials.” For example, the metal thingies are metal, while the body is plasti-wood. It all renders down to one material! The guitar itself is just one mesh! That’s amazing to me. It only adds one draw call to the scene. Now I see where all the PBR hype comes from.
“Unity doesn’t support multithreading!”
I’ve heard that many times, by many different people. Yet there are some, if you search hard enough, who refute the fact. The truth is, coming straight to you from The Keyboard of SnowHydra Games, is that you can have multiple threads in a Unity game.
However, as you may have heard, threads in Unity projects have LIMITED FUNCTIONALITY.
You pretty much cannot use any Unity functions while multithreading.
This means you will not be able to set transform.position, nor rigidbody.AddForce, nor can you even think about just changing the name of a GameObject. That doesn’t mean you’re never allowed to do those things, it just means you can’t do them in a separate thread. Unity’s functions can only be called from the “main” thread that we have access to.
That’s OK though! You could always do your asynchronous calculations on that new thread, then set your transforms or what have you to the new values once you’re done calculating it. This of course would only be useful for more complex situations–there’s no use for the majority of circumstances.
SPOOKY THREAD INCONSISTENCY
It was rather spooky, to say the least. I pushed a change to a project that separated some calculations onto a separate thread. It worked all fine and dandy on my machine, but on another team member’s, it would crash his editor. Turns out when he stopped the game in the editor, the thread I created continued spinning for eternity.
Threads in Unity can be unpredictable like this. Fortunately we fixed it by making sure the thread doesn’t continuously spin, however it’s not to say that there could be other differences of thread behavior between different operating platforms.
Anyway I think the point of this is to say “Unity’s compiler will let you program things using threads and it’ll work” and “stay safe from threads, kids.”