Friends, food, and flourishing

MalberS magic: controlling a doggo in C#

I love animals, especially doggos. I’d like to come up with ways to make intelligent animals, methods I can use across Unity games. An animal stack, if you will.

MalberS sells great animal assets. I’ve bought a deer, raccoon, fox, rabbit, dragon, and others. They come with an animal controller (AC), to get animals to walk, run, swim, whatevs. They also have AI components, to patrol waypoints, move to a game object (GO)… the list goes on.

The MalberS’ AC could be my entire animal stack. There are two problems for me, though. First, I’d like to control animals from other vendors, like Red Deer. Second, I’d like to have C# scripts implement intelligence, using MalberS’ controller things to do it. This would, for example, let me use behavior trees, with the actions being implemented by calls to MalberS.

I’ve had trouble operating MalberS’ controllers in my own code. This post shows three ways that work for a simple behavior: walk to a cube.

Other posts show how I used AC on Red Deer animals. This one focuses on the AI bit. Remember, I’m not an expert. There are probably better ways to do things. I’m writing this post mainly to remind my future self.

Doggo structure

Here’s a doggo friend:

Doggo

Let’s call her Smartie.

There’s a cube on the left. I want Smartie to walk to the cube. This is quite easy to do using components MalberS supplies, with no programming. But that’s not the point of this post.

Here’s Smartie in the hierarchy:

Hierarchy

Doggo has three children. Arm_Dog is the bones and such. Retriever is the skin. AI is… the AI.

Here’s Doggo in the inspector:

Doggo components

Animal is MalberS’ animal controller. Retriever Controller is my own script, to test the three methods covered here.

Here’s AI:

AI components

It has two MalberS’ components: AI Control and Animal Brain.

It helps to think of Doggo as having a stack:

Animal stack

At the bottom are the usual components, like an animator, rigid body, and such.

Riding on top of them is an animal controller (AC). It handles animal body actions, like running, walking, and swimming. It doesn’t know where the animal is running to, just that it’s running. To do its work, the AC uses the components below it. For example, it sets parameters defined on the animator.

Above AC is an AI controller (AIC). Its main job is to tell the animal to go somewhere. It handles things like starting and stopping the animal. It uses AC to handle the body movements, and a nav mesh agent to find routes.

Above that is the animal brain (AB). It works at a tactical level. Like, go around some waypoints, and if you see an enemy, alert your friends, and attack. If your health gets too low, run away. AB uses AIC to navigate.

The layer model isn’t strict. For example, AB (tactical) can reach down to AC (body control) directly, bypassing AIC (navigate). An animal can stop and howl, without changing its destination, so the navigator doesn’t need to be involved.

So, custom code can interact with AC to control the animal’s body, AIC to control navigation, and AB to implement tactics, like running away.  Let’s see how, with the simple task of walking to a cube.

AI controller

This is the simplest case. AIC’s main purpose is to tell an animal to go somewhere, which matches the go-to-cube task exactly. We can set Smartie loose with one line in Start():

				
					animalAIControl.Target = cube;
				
			

AIC will use AC to handle the deets of animation. It will use a default speed.

AI controller with animal controller adjustment

Walking to the cube is the type of task that’s best handled by the AI controller. However, we might want to adjust the animal’s body in some way. For example, maybe Smartie should trot in fine weather, walk if there’s fog, and run if it’s raining.

We’ll tell AIC to go to the cube as before, but we’ll set the speed depending on the weather. AC has been set up with three speeds for the Ground speed set: Walk, Trot, and Run. Here’s some code:

				
					// Set speed depending on the weather.
int speedId = TrotSpeedId;
switch (weather)
{
    case Weather.Fine:
        speedId = TrotSpeedId;
        break;
    case Weather.Foggy:
        speedId = WalkSpeedId;
        break;
    case Weather.Raining:
        speedId = RunSpeedId;
        break;
}
animal.Speed_CurrentIndex_Set(speedId);
// Tell AIC to go to Cubey.
animalAIControl.Target = cube;
				
			

Line 15 sets something in the AC, before telling AIC to go to the cube. AIC tells AC to play the right animations, using whatever speed is already set. We’ve used AIC for navigation, using AC to make some body adjustments.

Animal brain

A third way to get to the cube is to use the animal brain (AB) component. No code is needed, just a lot of configuration. ABs have AI states, different from the body states of AC.

Brains have states

A state is a task sequence, and a decision sequence. Here’s the go-to-cube state:

State

The state has one task and one decision. The deets of the task are shown under the state. All states have some shared variables, like the current target. Once set, it carries over to other tasks, until it’s reset. The task type, setting the current target, is one of a bunch of task types MalberS provides.

The Move To Target checkbox tells the brain to set the target and then start the animal moving. I could have broken it up into two tasks:

  • Set the target
  • Start moving

Using the checkbox was easier. Easy is good.

Take a look at the way you set the target:

Setting the target

I thought I would drag the cube into a field, but that’s not how it works. There’s a hook whatsit. You add a component to the thing you want to target:

Hook

The transform var object links references in tasks to game objects.

States use one or more decision objects to control transitions to other states. The decision objects return either true or false. In this case:

Decision

If the animal has arrived, enter the Stop and idle state. Otherwise, stay in the Go to cube state.

To get this started in C#:

				
					[SerializeField] private MAIState startingState;
...
private void Start()
{
    // Set the AI state.
    animalBrain.currentState = startingState;
}
				
			

Drag the Go to cube state into startingState.

Of course, there’s quite a bit of setup. The weather thing would take more work than I’m willing to put in for this post.

Conclusion

For me, getting animal animation just right is hard. For example, when moving from idle to a location at, say, 120º means moving the animal forward while rotating to a new heading while bending the spine. MalberS’ AC does this well. AIC knows how to use AC to move an animal around the level. AIC lets you use AC directly to change, e.g., the animal’s stance while AIC is moving the animal.

I’m not so sure about AB, the brain. For me, it might be easier to write custom C# scripts for that. I’m not certain, though. AB has a lot of functionality I would have to duplicate. Still, suppose I want to control tactical-level behavior with, say, a behavior tree. It might be easier to have the behavior tree control AIC and AC, than have the behavior tree control the brain that then controls AIC and AC.

Leave a Reply

Your email address will not be published. Required fields are marked *

css.php