Advertisement

Tips for programming enemy behaviour more efficiently/clean?

Started by July 03, 2020 03:04 PM
6 comments, last by Thibault Ober 4 years, 4 months ago

Imagine e.g. a 2D-platformer boss fight with one central enemy but with multiple phases. How would you program that?

I usually do that with a switch-case in the looped method ("void Update()" in Unity) and add a variable “status” which keeps track of the current action the boss is doing (moving to specific point, idle animation, circling, attack1, etc.). After a certain action is done I then change the status so that it goes into another “case”.

However I often run into the problem that the code gets to confusing over time because of the too long switch-case and the even longer list of methods which are declared there further downwards.

My question is, if there are better methods to code such a boss fight that consists of many linear actions but randomly chooses an action/string of actions

Here an example how I used switch-case and the status variable for a boss' behaviour:

void Update()
    {
        switch (status)
        {
            case 0: //Circle Movenment

                Circling(Random.Range(360, 600), x, 1, 2.5f, 1.5f, 120f, false);
                break;
            case 1: //Preperation for 2. (Moving to Startingpoint)
 
                if(fromRight)
                {
                    MoveTo(7, 4, 3, 60, 2);
                }
                else
                {
                    MoveTo(-7, 4, 3, 60, 2);
                }
                break;
            case 2: //Flies above the ground left->right or right->left

                Hyperbole-Movenment(speed, fromRight);
                break;
            case 3: //Move back to origin
                if (fromRight)
                {
                    MoveTo(origin.x, origin.y - 1.5f, 3, 0, 0);
                }
                else
                {
                    MoveTo(origin.x, origin.y + 1.5f, 3, 0, 0);
                }
                break;
        }

I'd suggest to take a look at finite state machines (FSM). I'd also suggest to have a look at behaviour trees, which are far superior than FSMs but also more complex to use. Use whatever you think is best suited to your needs.

Advertisement

Thanks for the tips I will look into it =D

You can see a single behavior as an elementary action, and code that in a function or even an object.

That splits the problem in ‘decide sequence of single behaviors’ and ‘perform a single behavior’. It would give you a ‘current behavior’ which can do an incremental update until it's done. At that point you query the sequence generator for the next behavior.

Obviously, you can return codes from the behavior to the generator to steer what to do next.

Concretely, each ‘case’ above would become a more self-contained unit that manages itself until ‘done’.

@trapazza Would that FSM be the “Animation State Machines” in unity? There isn't a free tool for behaviour trees, is there?

@Alberth Could you explain what you mean with “incremental update until it's done”?

I think trapazza meant FSMs in general, ie a thing with locations (states) and transitions (edges) between them. You can use them for lot of things, including (as Unity does) for animations, but also for higher level things, such as my sequence generator.

“incremental update” means each time you call the function (or the object), you look at what you did so far, and update what should happen or be displayed this time. “incremental” as you make a next step relative to the last step, and “update” as you modify the data so it's ready for the next time you call it.

For example, if you call it each frame, it should update the boss position a little bit, so the boss appears to move, eg

class MoveBoss:
    def __init__(self, startx, starty, stepsize, stepcount):
        self.xpos = startx
        self.ypos = starty
        self.stepsize = stepsize
        self.stepcount = stepcount
        
    # Query boss position for display.
    def get_pos(self):
        return self.xpos, self.ypos
        
    # Are we done?
    def is_done(self):
        return self.stepcount <= 0
                
    # Update
    def update(self):
        if self.stepcount > 0:
            self.xpos = self.xpos + self.stepsize
            self.stepcount = self.stepcount - 1

This class gets a start position and ‘stepcount' steps of length ‘stepsize’. You can query the current position, you can ask whether it reached the end poistion (ie it's done moving), and you can perform an update of the position.

Advertisement

There are no free packages for behavior tree in unity, but they seems quite effective (ui for debug …)

I am not an expert on the subject, if you have some basics need and just want to clean up your code. I would recommend implementing a composition pattern and add a new class enemyBehaviour which can be derived in Phase1Behaviour, Phase2Behaviour … Then call its “updateBehaviour” in your update method.

If you want a more “industrial approach” You could try tree behaviour tree, I follow the guide line in this very good article:

https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php

which leads me to thoose c# scripts:

https://github.com/Paltoquet/2DShooter/blob/master/Assets/Animation/Scripts/BehaviourTree.cs

https://github.com/Paltoquet/2DShooter/blob/master/Assets/Animation/Scripts/EnemyBehaviour.cs

Hope it helps

This topic is closed to new replies.

Advertisement