"Invincible Heroes" (1)

Note: It is recommended to watch the corresponding video tutorial before reading this article. This article is mainly used as a reference for learners who still have questions about the video tutorial

Video tutorial: https://www.bilibili.com/video/BV12s411g7gU?p=136

Table of contents

enemy module

demand analysis 

EnemyMotor enemy motor class

EnemyStatusInfo Enemy status information class 

EnemyAnimation enemy animation class 

enemy generator

demand analysis

EnemySpawn enemy spawner class 

Path route class


enemy module

1. The enemy moves along the designated route

2. Blood loss and death after being hit

3. Arrive at the end and attack the player 

4. Play running animation for sports, attack animation for attack, idle animation for attack interval, and death animation for death

demand analysis 

EnemyMotor enemy motor class : provides movement, rotation, pathfinding functions 

EnemyStatusInfo Enemy status information class : define blood volume, provide functions of injury and death

EnemyAnimation Enemy animation class : define various animation names and provide the function of playing animation

ps: Since there is no corresponding game material, this article uses print("play XX animation") to replace the part of the animation in the scene. Secondly, this article recommends creating several corresponding empty animations to meet the running conditions 

For the creation of animation and precautions for using the old animation system in the new version, please read the content about Animation in Unity script (3)

EnemyAI Enemy AI class: By judging the state , perform pathfinding or attack

ps: The above components should be mounted on the enemy's prefab, but it is not recommended to directly construct the components on the model in actual development, you should create an empty object as its parent and mount the components to the parent on, as shown below

   

EnemyMotor enemy motor class

1. Define the method to move forward 

2. Define the method of rotation towards the target point

3. Define the method of pathfinding

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//敌人马达,提供移动、旋转、寻路功能
public class EnemyMotor : MonoBehaviour
{
    public Path path;
    //当前路径点的索引
    private int currentPointIndex = 0;
    public float moveSpeed;

    private void Update()
    {
        PathFinding();
    }

    //向前移动
    public void MovementForward()
    {
        transform.Translate(0, 0, moveSpeed * Time.deltaTime);
    }

    //注视选转
    public void LookRotation(Vector3 target)
    {
        this.transform.LookAt(target);
    }

    //寻路,沿路线移动
    public bool PathFinding()
    {
        //return true;继续寻路
        //return false;到达终点,无需寻路

        //如果到达目标点
        //更新目标点(向下一个点移动)

        if (path == null || currentPointIndex >= path.wayPoints.Length) return false;
        //朝向目标点
        LookRotation(path.wayPoints[currentPointIndex]);
        //向前移动
        MovementForward();
        //如果达到目标(当前位置接近于目标点)
        if (Vector3.Distance(transform.position, path.wayPoints[currentPointIndex]) < 0.1f)
        {
            currentPointIndex++;
        }
        return true;
    }
}

EnemyStatusInfo Enemy status information class 

1. Define variable: current health value

2. DEFINING METHODS: INJURY, DEATH

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//敌人状态信息类,定义敌人信息,提供受伤死亡功能
public class EnemyStatusInfo : MonoBehaviour
{
    public float HP = 200;
    public float maxHP = 200;
    //死亡延迟销毁时间
    public float deathDelay = 5;
    public EnemySpawn spawn;

    //受伤
    public void Damage(float damage)
    {
        //扣血
        HP -= damage;
        //血量为0时,调用死亡方法
        if (HP <= 0)
            Death();
    }

    //死亡
    public void Death()
    {
        //播放死亡动画
        var anim = GetComponent<EnemyAnimation>();
        anim.action.Play(anim.deathAnimName);
        print("播放死亡动画");
        //销毁当前物体  
        Destroy(gameObject, deathDelay);
        //设置路线状态
        GetComponent<EnemyMotor>().path.isUsable = true;
        //产生下一个物体
        spawn.GenerateEnemy();
    }

    //测试方法,鼠标点击敌人,对其造成50点伤害
    private void OnMouseDown() {
        Damage(50);
    }
}

ps: Be sure to mount the collision component (Collider) on the enemy's prefab, otherwise OnMouseDown() will not take effect

EnemyAnimation enemy animation class 

1. Define variables for various animation names, such as running, idle, attack

2. Define the AnimationAction class to provide animation-related behaviors 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyAnimation : MonoBehaviour
{
    //跑步动画名称
    public string runAnimName;
    //攻击动画名称
    public string attackAnimName;
    //闲置动画名称
    public string idleAnimaName;
    //死亡动画名称
    public string deathAnimName;
    //行为类
    public AnimationAction action;

    private void Awake()
    {
        //action=new AnimationAction(?);
        action=new AnimationAction(GetComponent<Animation>());
    }
}

AnimationAction animation behavior class

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//动画行为类,提供有关动画的行为
public class AnimationAction
{
    //附加在敌人模型上的动画组件引用
    private Animation anim;

    //创建动画行为类
    public AnimationAction(Animation anim)
    {
        this.anim=anim;
    }

    //播放动画
    public void Play(string animName)
    {
        anim.CrossFade(animName);
    }

    public bool IsPlaying(string animName)
    {
        return anim.IsPlaying(animName);
    }

}

enemy generator

1. Spawn the specified number of enemies at the beginning

2. Randomly select an available route for each person

3. The enemy type and the delay time generated are random

4. When the enemy dies, the next enemy will be spawned until the number of spawns reaches the upper limit

demand analysis

1. Create a root route and add multiple routes with waypoints

2. EnemySpawn enemy generator class : attached to the root route, providing the function of generating enemies

3. Path route class : the included attributes are, waypoint coordinates Vector3[] wayPoints, bool IsUseable or not

4. When the generator is enabled, calculate all possible routes

5. When an enemy is generated, randomly select an available route

EnemySpawn enemy spawner class 

Define variables:

GameObject[] enemyTypes : used to record enemy prefabs

int startCount : Used to record the number of enemies that need to be created at the beginning

int spawnedCount : Used to record the number of enemies that have been spawned

int maxCount : Used to record the upper limit of the number of enemies generated

int maxDelay : used to record the maximum delay time for spawning enemies

Definition method: 

CalculateWayLines() : used to calculate all routes and coordinates

GenerateEnemy() : Used to generate an enemy. 

using System.Net.Mail;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemySpawn : MonoBehaviour
{
    //需要创建的敌人预制件
    public GameObject[] enmeyType;
    //需要创建敌人的最大数目
    public int maxCount = 5;
    //初始创建的敌人数目
    public int startCount = 2;
    //已经创建的敌人数目
    private int spawnCount;
    private Path[] paths;
    public int maxDelay = 10;

    //生成一个敌人
    public void GenerateEnemy()
    {
        spawnCount++;
        //如果生成数量已达到上限
        if(spawnCount>=maxCount) return;
        //延迟时间随机
        Invoke("GreateEnemy", Random.Range(0, maxDelay));
    }

    private void GreateEnemy()
    {
        //选择所有可以使用的路线
        Path[] usablePaths = SelectUsablePath();
        //随机选择一条可以使用的路线
        Path path = usablePaths[Random.Range(0, usablePaths.Length)];
        int randomIndex = Random.Range(0, enmeyType.Length);
        //Instantiate(敌人预制件,位置,旋转角度);
        GameObject go = Instantiate(enmeyType[randomIndex], path.wayPoints[0], Quaternion.identity) as GameObject;
        //配置信息
        EnemyMotor motor = go.GetComponent<EnemyMotor>();
        motor.path = path;
        path.isUsable = false;
        //传递生成器引用
        go.GetComponent<EnemyStatusInfo>().spawn=this;
    }

    private void Start()
    {
        CalculateWayLines();
        GenerateEnemy();
    }

    private void CalculateWayLines()
    {
        paths = new Path[this.transform.childCount];
        for (int i = 0; i < paths.Length; i++)
        {
            //每一条路线
            //路线变换组件的引用
            Transform path = this.transform.GetChild(i);
            //创建路线对象
            paths[i] = new Path(path.childCount);
            for (int pointIndex = 0; pointIndex < path.childCount; pointIndex++)
            {
                paths[i].wayPoints[pointIndex] = path.GetChild(pointIndex).position;
            }
        }
    }

    //闲置可以使用的路线
    private Path[] SelectUsablePath()
    {
        List<Path> res = new List<Path>(paths.Length);
        //遍历所有路线
        foreach (var path in paths)
        {
            //如果可以使用,添加到res中
            if (path.isUsable) res.Add(path);
        }
        return res.ToArray();
    }
}

Path route class

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Path
{
    public Vector3[] wayPoints { get; set; }
    public bool isUsable{ get; set; }

    //构造函数
    public Path(int wayPointCount){
        wayPoints=new Vector3[wayPointCount];
        isUsable=true;
    }
}

Guess you like

Origin blog.csdn.net/qq_53401568/article/details/128516344