Enemy Idle, Detection, and Movement Script

What is it?

  1. It’s a script that’s attached to an enemy object in unity.

  2. It handles the following logic for that enemy:

    1. How the enemy moves when it’s idle.

    2. How it detects the player character in the environment.

    3. How it moves when the player character is detected.

  3. It also handles connections to:

    1. The animator for the enemy object for idle, detection, and movement animations.

 

Production Overview:

Producing this script is completed over two steps:

  • Step 1: Prove the three systems of Enemy Idling, Detecting the Player, And Moving towards the player works as intended.

  • Step 2: Once proven Produce the other variations of Idle Types, Detection Types, and Movement Types.

 

Enemy Idle, Detection, & Movement Logic Flow Chart

Here’s a flow chart that connects the multiple design elements expressed within this page

It diagrams how each element transitions to the next and creates a dynamic movement and attack script.

 

Pathfinding Details

Pathfinding is done through the Package Asset: https://assetstore.unity.com/packages/tools/ai/simple-tile-pathfinding-136493

The documentation for how to interface with the asset is located in this file:

This document also includes all the API information for this package from Page 24 and beyond.

 

Asset Locations in:

The assets that came with this package is located under Assets → Simple Tile Pathfinding

 

Integration Locations in Hierarchy:

The main script is located in the object “Grid Dungeon Environment” and it links together both the tilemap it’s associated with as well with a block tile.

 

Pathfinding Tilemap Visibility

To turn Block Tile sprites on to show up in editor and game: Enable the tilemap renderer on the object “Tilemap Enemy Navigation”

The Block Tiles will then become visible in the editor:

 

Idle Types

All Enemies start in a “Idle” State when a level is loaded or a enemy is spawned in.

The enemy moves to the beat of the music as determined in the scripts properties.

There are three different types of Idles:

  • Static Idle: The Enemy does not move while idle.

  • Waypoint Idle: The Enemy will follow along a path of premade waypoints on a repeating loop.

    • Each waypoint is 1 dungeon tile away from the last.

    • Movement starts on the waypoint of the smallest number and progresses to each increasing number: ie: 1-2-3-4-5-6.

    • The location of waypoints in the environment is set by the designer when designing enemy locations and spawns.

  • Boundary Idle: The Enemy will randomly roam 1 dungeon tile at a time within the boundary of a pre-set trigger box collider.

Static Idle Example

Waypoint Idle Example

Boundary Idle Example

 

Player Detection Types

There are two different ways in which an enemy can detect the presence of player character.

Detection is EITHER one or the other for each enemy. Both can’t be used at the same time.

Radial Detection:

  • Radial distance to Player: The player characters moves onto a dungeon tile that's within the detection radius of the enemy.

    • Used for single enemies.

    • Practical Use: This is used for enemies we don’t want activating until the player character moves in proximity to.

Screengrab Notes:

  • Enemy Detectors are given the “Enemy Detector” tag.

  • They’re positioned +10 on the Z Axis, so the collider doesn’t interact with different types of colliders.

 

Detection Trigger Area

  • Player enters Detection Trigger Area: The player enters a dungeon tile that’s a part of a detection trigger box collider associated with that environment location and linked to one or more enemies.

    • Used for one or more enemies in a space.

    • Practical Use: This is used for a “Room Activation” whereby one or more enemies will go from idle to active movement once the player enters that particular room or space of the dungeon.

    • If enemies are set to this type of detection then they’re linked automatically to the trigger area the enemy spawns into.

Screengrab Notes:

  • Enemy Detectors are given the “Enemy Detector” tag.

  • They’re positioned +10 on the Z Axis, so the collider doesn’t interact with different types of colliders.

 

Radial Distance to Player Example:

 

Player Enters Detection Area Example:

Player Character Asset Setup for Detection:

The player character has a 1 square trigger-based box collider that’s been tested to work with entering the trigger area on the same z-pane and object tag:

  • +10 on the Z Axis in Unity

  • Tagged as “Enemy Detector”

 

Enemy Movement Types

Once the enemy has detected the player it’s no longer in an idle state it transitions to an Movement state.

All movement is done to the beat.

The type of Movement state the enemy uses is assigned by the designer in Unity.

Different Movement state types include:

  • Static: Doesn’t move at all. (Movement Disabled) Will attack the player when players gets into attack range by themselves.

  • Hunt: Moves towards the player as directly as possible.

  • Wondering: Moves generally towards the player but often diverging off to move in another directions.

  • Repelled: Moves away from the player as directly as possible.

  • Stand Ground: Will only move a few tiles from its spawn point before retreating back to the spawn point tile.

Static Example

Hunt Example

Wondering Example

Repelled Example

Stand Ground Example

 

Collision Detection Before Moving:

Regardless of the type of idle and movement types chosen: all movement adheres to not moving onto collision that’s on the walls of the dungeon or attached to other objects.

  • Before each movement is made by an enemy:

    1. A check is done to see if the direction the enemy wants to move in is being blocked by a collision collider.

    2. If it is then it’ll choose another direction and check again until it finds a direction it can move to.

    3. If it cannot find a valid direction to move to then it will stay on the tile until such time as it can.

  • It will do a new collision check in adherence to that enemies set speed of movement.

Enemy to Player Collision:

Enemies cannot move into a space that the player has occupied.

Avoiding other Enemies:

Each enemy asset will have a collision box that’s named the same as those used in walls and objects in the dungeon.

Therefore enemies should treat each other as if they where a wall or object: Something that they can’t move into.

Speed of Movement:

Speed of movement is determined by that enemy’s relationship to the beat of the music.

Some enemies will move once per beat. Other enemies will move only once every number of beats.

This speed is determined by an exposed number on on the script called “Move per Beats”

1 = 1 movement per every beat

2 = 1 movement per every 2 beats

3 = 1 movement per every 3 beats.

4 = 1 movement per every 4 beats

etc.

Syncing Enemies to Different Speeds of Movement:

Whenever an enemy transitions from detection to movement state it must wait for the next primary beat.

The “Primary Beat” is whatever beat that other enemies set to the same speed of movement is. ie:

  • If the enemy is set to 1 movement every 2 beats. It must move the same time every other enemy is set to 1 movement every 2 beats.

  • This will make movement look grouped and uniform when multiple enemies are on screen.

 

Attacking the player

Summary: Attacking the player is handled separately through a combination of collision box trigger volumes and FSM State machines to detect when the player character is in range of that enemy.

There should be no association or dependencies with this script.

 

Enemy Animations Associated with this Script

There are three enemy animations that’ll be linked with this script:

Idle Animation - Set by a Animator Bool:

  • This animation plays on repeat until the bool is set to false once the player has been detected.

  • The animation will be of the enemy in an idle state.

Detected Animation - Set by a Animator Bool:

  • This animation plays once once the bool is set to true once the player has been detected.

  • The animation will be an animated “!” Alert that shows the enemy has detected the player.

Movement Animation - Set by a animator trigger that activates per movement.

  • This animated plays once the player has been detected and the enemy moves. It shows the enemy visually moving.

 

Script Inspector Exposed Settings:

The following settings need to be exposed in the script’s inspector for the benefit of the designer.

For example: As seen in the character controller

Description

Type of Input

Default Input:

Description

Type of Input

Default Input:

Idle Type Selector - Determines which Idle Type is active on this script.

Pick an option from a drop down.

  • Static Idle

Other Inputs in drop down:

  • Waypoint Idle

  • Boundary Idle

Waypoint Idle - Waypoints Location - The location where all waypoint objects are located in the editor. - Needed for waypoint pathing to work.

Object Location

Empty

Beats per Move - How many Beats it takes to make a single idle movement. (For Waypoint and Boundary)

Int Number

2 (Two Beats = 1 Idle Movement )

Movement Transition Speed of the enemy object between tiles in the dungeon while idle. (like player movement)

Float Number

0.25 (One quarter of a second)

Description

Type of Input

Default Input:

Description

Type of Input

Default Input:

Detection Type Selector - Determines which selector is active on this script.

Pick an option from a drop down.

  • Player Enters the trigger Area

Other Inputs in Drop Down:

  • Radial Distance to Player

Radial Detection object Location in Editor

Object Location

Empty

Time between detection and starting to move. Measured in Seconds

Float Number

1.0 (1 Second)

Description

Type of Input

Default Input:

Description

Type of Input

Default Input:

Movement Type Selector - Determines which type of movement is active on this script.

Pick an option from a drop down.

  • Static

Other Inputs in drop down:

  • Hunt

  • Wondering

  • Repelled

  • Stand Ground

Movement Transition Speed of the enemy object between tiles in the dungeon when in movement state. (like player movement)

Float Number (In Seconds)

0.25 (One quarter of a second)

Beats per Move - How many Beats it takes to make a move.

Int Number

2 (Two Beats = 1 Movement)

Movement Type - Stand Ground = Max Number of squares from enemy spawn point the enemy will move.

Int Number

2 (2 squares in any direction)

No inputs needed.

Enemy Animator Exposed Settings:

Description

Type of Input

Default Input:

Description

Type of Input

Default Input:

The object location of the animator script associated with the enemy

Object Location

Empty

The Name of the “Detection” Bool in the animator. So when detection is triggered it can make that bool set to true

Name of the detection bool for the animator script

Detection

The Name of the “Idle” Bool in the animator. So when idle is no longer active it can set that bool set to false.

Name of the Idle bool for the animator script

Idle

The Name of the “Movement” Trigger animator. So when movement is triggered it can trigger.

Name of the Movement Trigger for the animator script.

Movement

 

Script Production Checklist:

The following is a checklist to mark off progress with producing and testing the script.

Task Name

Production Step

Functionality Description

Is it done? (And Tested)

Designer Approved?

Task Name

Production Step

Functionality Description

Is it done? (And Tested)

Designer Approved?

Idle Type - Static

1

Can enemies idle statically (This should be easy. XD )

In Game and Tested?

Idle Type - Waypoint

2

Can enemies move to their set beat via associated waypoints.

In Game and Tested?

Idle Type - Boundary

2

Can enemies move within a set boundary area

In Game and Tested?

Detection Type - Radial Distance

1

Can the enemy detect the player via a radial distance associated to the enemy.

Detection Type - Static Trigger Area

2

Can the enemy detect the player via a trigger volume placed in the environment.

Movement Type - Static

1

Can Enemies be static once they’ve detected a player

Movement Type - Hunt

1

Will enemies move towards the player once the player is detected.

Movement Type - Wonder

2

Will enemies move towards the player once the player is detected.

Movement Type - Repelled

2

Will enemies move away from the player once the player is detected.

Movement Type - Stand Ground

2

Will enemies move towards the player once the player is detected.

Animator - Animator Object Link

1

Does the script link to the enemy’s animator object in the inspector.

Animator - Idle Bool

1

Does the Idle Animation Play while the Enemy is idle.

Animator - Movement Trigger

1

Does the enemy play the movement animation when they move

Animator - Detection Bool

1

Does the enemy play the detection animation when they detect the player.

All Exposed Settings for Enemy Idle

2

Are the exposed settings in the scripts inspector view?

All Exposed Settings for Detection

2

Are the exposed settings in the scripts inspector view?

All Exposed Settings for Movement

2

Are the exposed settings in the scripts inspector view?

All Exposed Settings for Animator

2

Are the exposed settings in the scripts inspector view?

 

Development Feedback

The following is feedback given as the scripts and assets are being developed for the feature, kept on this page for continuity.

EnemyAI Script - June 20th 2022 feedback:

  • Partial Fix: In most cases, enemies are no longer intersecting with each other and occupying the same tile space.

  • Overall Bug: There are still cases when enemies will jump into the same space. It doesn’t happen as often as before but it can happen. Usually seems to involve enemies that are making movements at the same beat.

  • Bug with the golem enemy type: When the player is bound-up due to a golem attack and there are multiple enemies/golem next to them. These enemies will try and enter into the players space quickly after the player character frees themselves and occupying the same space as the player character. (This bug might have to do with the enemy AI script being turned on and off while the enemy is attacking.)

  • Requested expanded functionality: Right now when two enemies are lined up in front of the player, the furthest enemy is not intersecting with the closest enemy that’s attacking, which is good!

    But they’re also not rerouting around the attacking enemy to get to the player. It just stays put until the player moves. It would be good if that furthest enemy could reroute around the attacking enemy to get to the player.



  • Bug: Right now when two enemies are lined up in front of the player (like seen above) if the closest enemy is defeated, the furthest enemy will not realize the other enemy is remove and will not resume pursuing the player until the player moves nearer to that enemy. If the player moves further away from the now stuck enemy it will stay in place.

    It will resume moving and attacking only once the angle of direction towards the player has changed.

  • Bug: Enemies can sometimes get stuck against walls and not know what do to and become stuck. they only become unstuck once the player has moved to the other side of the enemy. (ie: If they’re stuck with the player on their right. They’ll get unstuck when the player moves past the obstruction and to the other side of the enemy. Their left.

     

  • Requested expanded functionality: A note on how the Enemy AI script functions when enemies attack and the possible need to change it:

    Right now when enemies attack the playmaker script that controls that switches the entire Enemy AI script off, which effectively stops movement while the enemy attacks. “If: this switching of the script on and off is causing bugs: then extra functionality should be added to replace the switching-off where-by the enemy AI script can be directed to a playmaker state machine (FSM) bool value which switches the enemy movement logic on and off instead of turning the whole script on and off.

 

Redevelopment Plan

The systems of player movement collision and Enemy AI need to be redeveloped to address the bugs and shortcomings they face.

Its redevelopment will be broken into 2 stages and a within each stage there’s a number of deliverables:

  • Stage 1 entails developing the systems to function to the same level seen currently in the game.

  • Stage 2 entrails taking these systems further by adding additional enemy AI functionality not yet seen in the game.

Stage 1

The objective of this stage is to get the collision and enemy AI functionality to the same level of functionality that the prior implementation created.

Deliverable 1 - Setting up for Enemy AI changes

  • Source control is setup and functioning.

    • This source control build will be separated from the main build version until the completion of Stage 1.

  • The underlying grid-based architecture has been setup for Enemy AI, Player Movement, and Collision work.

  • The Designer has implemented the programmers desired credits/name (and Link if desired) into the title-screen credits.

Deliverable 2 - Enemy Detection, Movement, and Enemy Attacking

Utilizing the new tile-based system and being completely disconnected from the prior systems of playmaker state machines and collider boxes.

Before this deliverable can start: The designer has delivered a “Stripped” alternative prefab of the enemies that has all the “Jank” playmaker logic and box colliders stripped out. (Trigger colliders for other purposes unrelated to these systems will remain)

  • The Enemy will be in a static idle state until it detects the player.

  • The Enemy can detect the player character when they move into a definable radial proximity of the enemy.

  • The Enemy will follow the player around in the “Hunt” style. Moving as directly as possible to engage the player.

    • The Playmaker based “Detection” state machine has been replaced, but the functionality it currently has has been replicated.

    • The enemy moves to the beat set by the settings in the Enemy AI script. (Associated to the Metronome Script)

  • The Enemy once in “Range” of the player will initiate an attack (Through triggering off an event in an “Attack” Playmaker state machine. )

    • Designer work: The enemy attack Playmaker State Machine will no longer disable the Enemy AI script while attacking.

    • The enemy will not move while attacking. Only reactivating the ability to move once a bool associated with the attacking state machine has changed back to the False state. (This will need to be setup on the playmaker end.)

  • Note: Collision logic is not a requirement for this deliverable owing to its association to the player character and the work needing to be done for all that. Enemy Collision is Deliverable 4.

Deliverable 3 - Player Movement, Collision, and Player Attacking

Utilizing the new tile-based system and discarding the collider objects (And discarding dynamic physics for movement and collision)

Before this deliverable can start: The designer has delivered a “Stripped” alternative prefab of the Player Character that has all the “Jank” playmaker logic and box colliders stripped out. (Trigger colliders for other purposes unrelated to these systems will remain)

  • The Player Character Moves directionally in the same method they used to.

  • A new method of assigning non-physics-based“colliders” to environmental objects such as walls, chests and scenery has been created.

  • The player character doesn’t move into environmental objects such as pillars and chests.

  • The player character doesn’t move into wall tiles.

  • Environmental Objects like doors can be opened and tiles once inaccessible to the player can now be moved into. (We have a prisoner type that’s a door that opens.)

  • The player character can move beside an enemy and successfully attack them. (Triggering off the Attack Playmaker State Machine.)

  • The playmaker integration properties of the current player movement script has been successfully ported over to this new script.

Deliverable 4 - Enemy Collision

Utilizing the new tile-based system and discarding the collider objects (And discarding dynamic physics for movement and collision)

  • Enemies don’t move into the same tile as walls and environmental objects and have to navigate their way around them.

  • There is a back-end prioritization system that handles multiple enemies moving at the same time when they move to the beat. Due to this system:

    • Enemies do not move into the same tile as other enemies or the player.

  • Enemies can navigate around other enemies to try and find a path to the player character.

  • There is some sort of consistent solution for if the player character tries to move into an enemy occupied tile while the enemy is transitioning into that new tile. (Currently the player just occupies the same tile space.)

 

Stage 2

The goal of this stage is to expand the functionality of the Enemy AI and Player Controller systems past what we’ve currently have:

Deliverable 1: Better Enemy Movement Visuals:

  • The enemy transitions from one tile to the next in much the same way the player character does.

    • The speed of the transition is an exposed and designer editable value.

    • There’s a linkage to an animator component where a “Moving” animation can be set off. (If defined by the designer. Otherwise nothing happens animation-wise.)

Deliverable 2: Enemy “Disengagement”

  • Enemies have a setting denoting the number of tiles the player character is away from them until they become “Disengaged”

  • Enemies return to a wondering idle state.

Deliverable 3: Waypoint and Boundary Idle Implementation.

  • The functionality for the Waypoint and Boundary Idle Types has been implemented.

  • Each enemy can be assigned one of the idle types.

  • Waypoint sets and Boundaries can be created in Environmental “Dungeon Tile” Prefabs by the designer for enemies to spawn into. (Due to the fact that enemies spawn into the game via radius to the player.)

Deliverable 4: Static Detection Area Implementation.

  • Enemies can be assigned the “Static Detection Area” Detection Type.

  • This is used as an alternative to the radial detection type.

  • The detection area is created in Environmental “ Dungeon Tile” Prefabs by the designer for enemies to spawn into who have this setting enabled.

Deliverable 5: Wonder, Repelled, And Stand Ground Movement Types Implementation.

  • The alternative types of enemy movement has been implemented.

 

April 2023 - Expanded Development Plan:

Summarized Task list:

Task Name

Task Type

Is it done? (And tested?)

Task Name

Task Type

Is it done? (And tested?)

Exposed Attack Speed Value + Linked to Animation Speed

New Functionality

Enemy “Attacking” Animations no longer play and need to play again.

Restoring Functionality

Slimes in particular can have detected the player but can take longer then usual to start moving towards the player

Bug Fixing

  • Golems will take a longer time to attack “again” if:

    • They’re just completed an attack

    • The player has moved and is staying on a tile directly next to the golem.

Bug Fixing

Enemies will “sometimes” refuse to move for 1-2 additional beats if they’re positioned diagonally next to the player.

Bug Fixing

Enemy Movement: Wonder, Repelled, And Stand Ground Movement Types Implementation.

New Functionality

Detailed Description of Tasks:

Player Controller Improvements (New Functionality)

Exposed Attack Speed Value + Linked to Animation:

  • I’d like for there to be a “Attack Speed Value” that can be exposed and changed. This is because there’s an RPG progression skill (Called Haste) that’s tied to the players attack speed.

  • “Attack Speed” is defined as a single input in which the player character does a single attack as well as its cool down time.

    • Functionality Wise: The action itself is taken immediately upon the input, but another attack cannot be started until the one currently playing completes. Think of it as the attacks “cooldown.”

    • At the beginning of the campaign that means players have to be more careful with attacking and interacting. It can’t be spammed.

    • Where as the reward for leveling up the associated RPG element will allow for more rapid attacks and damage output.

  • I’d like to link this to setting the speed of both the player attack animation as well as attack effects. So that the physical look of the attack is getting faster as the speed of the attack improves:

Animations Associated with Attacking Speed:

Enemy “Attacking” Animations no longer play and need to play again (Restoring Functionality)

  • This issue applies to all enemy prefabs. (Cultist, Slime, Golem)

  • When the attacking FSMs where made redundant, the attack animations that triggered where not integrated into the new enemy scripts.

  • There needs to be the ability to associate an animation to play when an enemy attack “Starts” and complete when an attack “Ends” - An animation bool is already set up on these enemy prefabs, so it’s more or less just linking these bools to attack starts and ends.

Enemy Movement and Attacking: Timing Consistency Improvements (Bug Fixing)

There’s a small amount of investigation and bug-fixing work to be done to improve the consistency of enemy movement and attacking:

Observed undesirable behavior:

  • Issue 1:
    Slimes in particular can have detected the player but can take longer then usual to start moving towards the player, and in some instances it looks like they get “Stuck” where they are and refuse to move until the player gets very close. The impression given is that the “Finder” code can’t find the player character.

    • This seems to happen once the slime has merged. Is the merging reverting them back to idling? Or perhaps they’ve been told to stay stationary for too long once merging. None the less something is making them act oddly.

    • I’m taking a guess here: But maybe this has less to do with code and more so tweaking the variables for the Simple Path Finding 2D script until an optimal ratio of “CPU performance to Reliability” has been reached?

      • It seems to be tied to performance to some extent. IE: This plays up much more when running in engine then if you export the game and play.

         

  • Issue 2:
    Golems will take a longer time to attack “again” if:

    • They’re just completed an attack

    • The player has moved and is staying on a tile directly next to the golem.

      1. They do attack again so they’re not hard-locked into not attacking. This might just be some janky playmaker script but can you check your code to see if there’s anything script wise that’s doing this?

  • Issue 3:
    Enemies will “sometimes” refuse to move for 1-2 additional beats if they’re positioned diagonally next to the player. Hard to say what causes this, maybe they’re making movement calculations and don’t think there’s anywhere relevant to move. Might be an issue related to the simple path finding 2D script again. It Warrants investigation.

 

Enemy Movement: Wonder, Repelled, And Stand Ground Movement Types Implementation. (New Implementation)

  • The alternative types of enemy movement has been implemented.

    • Wondering: Similar to hunt. But some intentional deviation away from the player every few moves.

    • Repelled: The enemy wants to run away from the player once detected.

    • Stand ground: The enemy will directly go towards the player once the player has invaded the enemies “Area” but the enemy will not leave that designated area.

Wondering Example

Repelled Example

Stand Ground Example