Day 6 of Getting Started with Unity: Enemy AI, Map Randomly Generated


\beautiful/
This article describes how to make enemy tanks attack smarter and how to generate random maps


Writing the enemy AI

In the plan, the enemy (silver tank) appears at the top of the game, and through a series of moves, it finally reaches the base and knocks down the heart. So the enemy moves automatically without human intervention. In order to realize this design, we modified the move method of the original player script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// enemy movement
private float v;
private float h;
// timer to change direction
private float timeValChangeDirection = 4;
// How to move the tank
private void Move(){
//If the timer is longer than four seconds, change the direction once
if(timeValChangeDirection >= 4){
//Generate one randomly from the eight numbers 0-7
int num = Random.Range(0,8);
//Because we want the enemy to attack the base, the probability of going down is adjusted to 3/8
if(num>5){
v = -1;
h = 0;
}
//2/8 left and right, 1/8 up
else if(num == 0){
v =1;
h = 0;
}
else if(num >0 && num <=2){
h = -1;
v =0;
}
else if(num > 2 && num<=4){
h = 1;
v=0;
}
// reset the timer
timeValChangeDirection = 0;
}
else{
//The timer will accumulate if it is less than four seconds
timeValChangeDirection += Time.fixedDeltaTime;
}

//Delete the identification "space" in the Attack method and the identification "w, a, s, d" in the Move method
//++++++++++++Preliminary completion of artificial intelligence++++++++++++

The current AI looks stupid and often hits the wall, there should be an update next day

Thinking of the bosses of soul games, they use different skills by identifying the distance and position between the player and themselves, and even feinting tricks. It makes people unpredictable and think that designing an intelligent boss is a lot of work.


map generation

Create a new GameObject in hierarchy and name it MapCreation. After writing, you can randomly generate maps and enemies. Only MapCreation is left in hierarchy, everything else can be deleted, it looks very neat.

Here is a generated map:

When you don’t know the exact coordinates, you can move the player’s tank and find the critical point in the Game interface. Here is (10,8), (10,-8), (-10,8), (-10,-8).

The generation of the map is divided into:

  • Fixed base and brick wall generation next to base
  • Random Brick Wall, Iron Wall, Grass, River Generation
  • Fixed player and enemy spawns
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class MapCreation : MonoBehaviour
    {
    //The array used to decorate the objects needed to initialize the map
    //0. Base, 1. Wall, 2. Obstacle, 3. Birth Effect, 4. River, 5. Grass, 6. Air Wall
    //Drag into the GameObject in turn in the "hierarchy" interface
    public GameObject[] item;

    //Add all generated positions to the list
    //Note that the L of List should be capitalized
    private List<Vector3> itemPoistionList = new List<Vector3>();

    //Instantiate in awake(), let the map be generated before all other objects
    private void Awake(){
    //Instantiate the base
    //Quaternion.identity: The currently instantiated object has no rotation angle, what is the rotation angle of the prefab, and how much is obtained by instantiation
    CreateItem(item[0], new Vector3(0,-8,0), Quaternion.identity);
    // Enclose the base with walls
    CreateItem(item[1], new Vector3(-1,-8,0), Quaternion.identity);
    CreateItem(item[1], new Vector3(1,-8,0), Quaternion.identity);
    //The lazy builds three brick walls with a for loop
    for (int i = -1; i<2; i++){
    CreateItem(item[1], new Vector3(i,-7,0), Quaternion.identity);
    }
    //Instantiate the air wall to prevent tanks from running around and recover bullets
    for (int i = -11; i<12; i++){
    CreateItem(item[6], new Vector3(i,9,0), Quaternion.identity);}
    for (int i = -11; i<12; i++){
    CreateItem(item[6], new Vector3(i,-9,0), Quaternion.identity);}
    for (int i = -8; i<9; i++){
    CreateItem(item[6], new Vector3(-11,i,0), Quaternion.identity);}
    for (int i = -8; i<9; i++){
    CreateItem(item[6], new Vector3(11,i,0), Quaternion.identity);}

    //Initialize the player
    GameObject go = Instantiate(item[3], new Vector3(-2, -8, 0), Quaternion.identity);
    //Get the component and set the create player to true, that is, create the player
    go.GetComponent<Born>().createPlayer = true;


    //spawn enemy
    CreateItem(item[3], new Vector3(-10, 8, 0), Quaternion.identity);
    CreateItem(item[3], new Vector3(0, 8, 0), Quaternion.identity);
    CreateItem(item[3], new Vector3(10, 8, 0), Quaternion.identity);
    //Repeat call (method name, call this method after a delay of a few seconds, how often to call it)
    InvokeRepeating("CreateEnemy", 4, 5);


    //Instantiate the map
    for(int i = 0; i<60;i++){
    CreateItem(item[1], createRandomPosition(), Quaternion.identity);
    }

    for(int i = 0; i<20;i++){
    CreateItem(item[2], createRandomPosition(), Quaternion.identity);
    }

    for(int i = 0; i<20;i++){
    CreateItem(item[4], createRandomPosition(), Quaternion.identity);
    }

    for(int i = 0; i<20;i++){
    CreateItem(item[5], createRandomPosition(), Quaternion.identity);
    }
    }

    //Let instantiated objects appear as components of MapCreation, not scattered on Hierarchy
    private void CreateItem(GameObject createGameObject,Vector3 createPosition, Quaternion createRotation){
    // instantiate the object
    GameObject itemGo = Instantiate(createGameObject, createPosition,createRotation);
    //Set MapCreation as the parent layer
    itemGo.transform.SetParent(gameObject.transform);
    //Add to the location list
    itemPoistionList.Add(createPosition);
    }

    // method to generate random positions
    public Vector3 createRandomPosition(){
    //Do not generate x=-10 and 10 columns; y=-8 and 8 lines, otherwise the tank will be stuck (small probability)
    while (true)
    {//The Random.Range() method of type int includes the first number, excluding the second number
    Vector3 createPosition = new Vector3(Random.Range(-9,10), Random.Range(-7,8), 0);
    //If this position has not been generated, return an available random position and jump out of the loop
    if(hasThePosition(createPosition) == false){
    return createPosition;
    }
    }
    }

    // Determine if this location exists in the location list
    private bool hasThePosition(Vector3 createPos){
    //The length of the list is represented by .Count
    for (int i=0; i < itemPoistionList.Count; i++)
    {
    if (createPos == itemPoistionList[i]){
    return true;
    }
    }
    //If there is no same position after traversing, return false to indicate that a new position can be established
    return false;
    }

    // method to spawn enemies
    private void CreateEnemy(){
    // Enemy randomly generated position
    int num = Random.Range(0,3);
    Vector3 enemyPos = new Vector3();
    if (num == 0){
    enemyPos = new Vector3(-10, 8, 0);
    }
    else if (num == 1){
    enemyPos = new Vector3(0, 8, 0);
    }
    else{
    enemyPos = new Vector3(10, 8, 0);
    }
    CreateItem(item[3], enemyPos, Quaternion.identity);
    }
    }

There is still the AI update, and the UI and game judgments are about to be completed.