Unity2D項目-平臺、解謎、戰鬥! 1.1戰鬥底層組件CanFight-CanBeFighted

各位看官老爺們,這裏是RuaiRuai工做室,一個作單機遊戲的興趣做坊。git

本文對該2D項目中戰鬥底層組件的開發及設計思路作一個總結,但願各路同行多多交流,各路大佬多多指點。github

實例特徵分析數組

首先對於各個可以參加戰鬥的實例來講,好比能主動攻擊的主角、可以和主角戰鬥的怪物,都須要一種手段(component in unity)來施加"攻擊"這個語義的動做,以及受到來自攻擊者的"被攻擊"的動做。故筆者初步設計一個組件來表達這兩種語義。ide

接着,一個顯然的問題出現了,單一職責原則,戰鬥組件承擔了攻擊函數的調用和受傷函數的調用兩種邏輯語義,那有沒有一種需求,只須要攻擊需求而不須要受擊需求呢,顯然,好比只能捱打的寶箱、只能攻擊的機關等等。因而,設計變成了這樣:函數

 

攻擊組件提供對單體傷害、對範圍內傷害、擊退、施加異常效果、施加元素攻擊等基本攻擊接口。spa

受擊組件擁有一個記錄當前幀全部攻擊信息的棧,以供高層組件調用,同時提供受擊、以及棧操做等接口。設計

類圖以下code

 

小做坊,意思到了就行2333component

這樣,在敵人的AI腳本中,或者是主角的技能腳本中,就能夠調用相應的函數來執行不一樣的技能邏輯傷害效果。orm

最後給出代碼:

using UnityEngine;

public class CanFight : MonoBehaviour
{
    /// <summary>
    /// CanFight類中範圍攻擊最多一次能夠攻擊多少個目標
    /// </summary>
    public const int ENMEIES_MAX_NUM_ONEATTACK = 32;
    /// <summary>
    /// 檢測敵人碰撞體的篩選器,做爲Collider2D.OverlapLayer()的第一個參數。具體做用見Unity API。
    /// </summary>
    private ContactFilter2D filter = new ContactFilter2D();

    private bool isInitialized = false;

    /// <summary>
    /// 構造函數,初始化篩選器的配置
    /// </summary>
    public void Initiailize(string[] layerNames)
    {
        filter.useNormalAngle = false;
        filter.useDepth = false;
        filter.useOutsideDepth = false;
        filter.useOutsideNormalAngle = false;
        filter.useTriggers = false;

        filter.useLayerMask = true;

        LayerMask targetLayer = 0;
        foreach(string layername in layerNames)
        {
            targetLayer ^= 1 << LayerMask.NameToLayer(layername);
        }
        //Debug.Log("在" + gameObject.name + "中,可攻擊到的層爲" + System.Convert.ToString(targetLayer,2));

        filter.layerMask = targetLayer;
        //32個bit表示32個層,左移表示篩選須要哪一個層

        isInitialized = true;
    }

    /// <summary>
    /// 對一個可以戰鬥的目標形成傷害,做爲底層私有函數被調用
    /// </summary>
    /// <param name="target">形成傷害的目標</param>
    /// <param name="damage">形成輸入數值的傷害</param>
    /// <param name="interruptType">攻擊打斷類型,默認爲無打斷</param>
    /// <returns>返回形成了多少傷害,具體用法有待進一步討論</returns>
    public int Attack(CanBeFighted target, int damage, AttackInterruptType interruptType = AttackInterruptType.NONE, ElementAbilityManager.Element element = ElementAbilityManager.Element.NULL)
    {
        if(!isInitialized)
        {
            Debug.LogError("" + gameObject.name + "物體中,CanFight組件未初始化!");
        }
        return target.BeAttacked(gameObject, damage, interruptType, element);
    }

    /// <summary>
    /// 範圍性攻擊,實現方法爲輸入表示範圍的Collier2D,檢測範圍內的每一個擁有CanBeFighted的敵人,調用BeAttacked
    /// </summary>
    /// <param name="area">表示攻擊範圍的collier2d, 應該爲trigger態</param>
    /// <param name="damage">該次範圍攻擊形成了多少傷害</param>
    /// <param name="interruptType">該次攻擊爲什麼種打斷類型</param>
    /// <returns>返回攻擊到的敵人對象的CanBeFighted組件的數組</returns>
    public CanBeFighted[] AttackArea(Collider2D area, int damage, AttackInterruptType interruptType = AttackInterruptType.NONE, ElementAbilityManager.Element element = ElementAbilityManager.Element.NULL)
    {
        //輸入範圍須要Trigger才行
        if(!area.isTrigger)
        {
            Debug.LogError("" + gameObject.name + "釋放範圍攻擊時,輸入的collider2d並非trigger態");
            return null;
        }

        Collider2D[] enemies = new Collider2D[ENMEIES_MAX_NUM_ONEATTACK];
        int enemiesNumber = area.OverlapCollider(filter, enemies);

        if(enemiesNumber != 0)
        {
            Debug.Log("攻擊碰到敵人");

            CanBeFighted[] enemiesAttacked = new CanBeFighted[enemiesNumber];
            CanBeFighted enemyBody;
            //對碰到的敵人進行如下操做,若是敵人有CanBeFighted組件,則施加攻擊,不然報錯

            for(int i = 0; i < enemiesNumber; i++)
            {

                if (enemies[i].TryGetComponent<CanBeFighted>(out enemyBody))
                {
                    Attack(enemyBody, damage, AttackInterruptType.NONE, element);
                    enemiesAttacked[i] = enemyBody;
                }
                else
                {
                    Debug.LogError("" + gameObject.name +
                        "釋放範圍攻擊時,這些物體被檢測爲敵人,可是沒有CanBeFighted組件" + enemies[i].gameObject.name);
                }
            }
            return enemiesAttacked;
        }

        return null;
    }

    public CanBeFighted[] AttackArea(Collider2D area, int damage, CanBeFighted[] hasAttacked, AttackInterruptType interruptType = AttackInterruptType.NONE, ElementAbilityManager.Element element = ElementAbilityManager.Element.NULL)
    {
        //輸入範圍須要Trigger才行
        if (!area.isTrigger)
        {
            Debug.LogError("" + gameObject.name + "釋放範圍攻擊時,輸入的collider2d並非trigger態");
            return null;
        }

        Collider2D[] enemies = new Collider2D[ENMEIES_MAX_NUM_ONEATTACK];
        int enemiesNumber = area.OverlapCollider(filter, enemies);

        if (enemiesNumber != 0)
        {
            Debug.Log("攻擊碰到敵人");

            CanBeFighted[] enemiesAttacked = new CanBeFighted[enemiesNumber];
            CanBeFighted enemyBody;
            //對碰到的敵人進行如下操做,若是敵人有CanBeFighted組件,則施加攻擊,不然報錯

            for (int i = 0; i < enemiesNumber; i++)
            {
                if (enemies[i].TryGetComponent<CanBeFighted>(out enemyBody))
                {
                    Attack(enemyBody, damage, AttackInterruptType.NONE, element);
                    enemiesAttacked[i] = enemyBody;
                }
                else
                {
                    Debug.LogError("" + gameObject.name +
                        "釋放範圍攻擊時,這些物體被檢測爲敵人,可是沒有CanBeFighted組件" + enemies[i].gameObject.name);
                }
            }
            return enemiesAttacked;
        }

        return null;
    }

整個項目原型github地址:

 www.gitHub.com/yunshiyue/elementgame

 

看官有何看法,有何指點,歡迎留言,也歡迎私聊~

相關文章
相關標籤/搜索