tuduf.ruhobbytech.itdev.game › summon

write: 2021-12-01 / modified: 25/09/2024

Скрипт атакующего спутника/союзника/компаньона для 2D игры на Unity.

Спутник летает за игроком "_followPoint.position" и добавляет в лист ScansClosestEnemys() ближайших врагов в радиусе "detectRange" попутно выбирая активной целью самого близкого к игроку врага FindTarget(), как только текущая цель оказывается в зоне агро "agroRange" делает рывок к ней на "distance", и наносит урон. После чего сбрасывает текущую цель летит к игроку, ждет и выбирает новую ближайшую цель.

Так как у спутника больше нет в игре применений было решено зафигачить все свои хотелки в один скрипт. Скорее всего это не самая лучшая реализация, но это работает черт побери.

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

    public class SummonDemon: MonoBehaviour
    {
        public float detectRange = 3;
        public float agroRange = 3;
        public float distance = 1;z
        private float Speed = 3;
        public int Damage = 1;

        private CircleCollider2D _collider;
        private Transform _followPoint;

        public GameObject TargetEnemy;
        public bool TargetLocked;
        private bool LeaveState;
        public List<GameObject> Enemys = new List<GameObject>();
        private Color editorCircleColor = Color.green;

        private State state;
        private enum State { Normal, ChaseTarget, Attacking }

        private void Start() {
            _followPoint = GameObject.FindGameObjectWithTag("SummonFollowPoint").transform;
            if (transform.parent.parent != null)
            transform.parent = transform.parent.parent;
            Collider2D _collider = GetComponentInChildren<CircleCollider2D>();
        }

        private void Update() {
            Enemys.RemoveAll(item => item == null);
            if(TargetEnemy != null && TargetLocked) 
                Debug.DrawLine(transform.position, TargetEnemy.transform.position, Color.yellow);
        switch (state) {
        default:
        case State.Normal:
            if (TargetEnemy == null && Enemys.Count != 0 && !TargetLocked) {
                FindTarget();
        }
            transform.position = Vector2.Lerp(transform.position, _followPoint.position, Time.deltaTime*Speed);
            if (TargetEnemy != null && Vector3.Distance(transform.position, TargetEnemy.transform.position) < agroRange)
            if (!TargetLocked && LeaveState || TargetLocked && !LeaveState) {
             StartCoroutine(Wait());
        }
        break;
        case State.ChaseTarget:
            transform.position = Vector2.Lerp(transform.position, TargetEnemy.transform.position, Time.deltaTime*Speed);
                if (Vector3.Distance(transform.position, TargetEnemy.transform.position) > distance) {
                transform.Translate(new Vector3(Speed * Time.deltaTime, 0, 0));
            }
            float attackRange = 0.5f;
            if (TargetEnemy != null && 
            Vector3.Distance(transform.position, TargetEnemy.transform.position) < attackRange) {
                    state = State.Attacking;
        }
        break;
        case State.Attacking:
            Debug.Log("ATTACK!");
            TargetEnemy.GetComponent<IDamagable>().TakeDamage(Damage);
            TargetEnemy = null;
            state = State.Normal;
        break;
        }
    }
    IEnumerator Wait() {
            state = State.ChaseTarget;
            LeaveState = true;
        yield return new WaitForSeconds(5);
            TargetLocked = false;
            LeaveState = false;
     }
    private void OnTriggerEnter2D(Collider2D col) {
        Collider2D[] ScansEnemies = Physics2D.OverlapCircleAll(_followPoint.position, detectRange);
            foreach (Collider2D enemy in ScansEnemies) {
                if (enemy.gameObject.tag == "Enemy" && !Enemys.Contains(enemy.gameObject)) {
                    Enemys.Add(enemy.gameObject);
                    print(enemy.name + " added to list");
            }
        }
    }

    public void FindTarget() {
        Debug.Log("Targeting!");
        float lowestDist = Mathf.Infinity;
        for(int i=0; i<Enemys.Count; i++) {
            float dist = Vector3.Distance(Enemys[i].transform.position, _followPoint.position);
            if (dist<lowestDist) {
                lowestDist = dist;
                TargetEnemy = Enemys[i];
                TargetLocked = true;
                print(TargetEnemy.name + " new target locked");
            }
        }
    }

    void OnDrawGizmosSelected() {
        UnityEditor.Handles.color = editorCircleColor;
        UnityEditor.Handles.DrawWireDisc(this.transform.position, this.transform.forward, detectRange);
    }
    }
}

Демон был отрисован в двух кадрах размером 32x32 за 10 минут на сайте pixilart.com