2020年1月1日 星期三

Unity筆記:自動攻擊最近敵人,箭矢自動指向敵軍射擊。


public Basic 角色腳本;//只是角色的腳本

    private void OnTriggerEnter2D(Collider2D 對象)
    {
        if (!角色腳本.判定對象是否為範圍(對象.gameObject))
//只射擊碰撞到的實際對象,而不是其他物件的攻擊範圍
        {
            角色腳本.角色攻擊敵人(對象.gameObject);

            //Debug.Log(gameObject + "碰撞" + 對象);

        }


    }

    void OnTriggerStay2D(Collider2D 對象)
    {

        if (!角色腳本.判定對象是否為範圍(對象.gameObject))
        {
            角色腳本.角色攻擊敵人(對象.gameObject);

            //Debug.Log(gameObject + "碰撞" + 對象);

        }
    }

    void OnTriggerExit2D(Collider2D 對象)
    {
        if (角色腳本.可攻擊敵人列表.Contains(對象.gameObject))
        {
            角色腳本.可攻擊敵人列表.Remove(對象.gameObject);
        }
    }

//=======================================


 public List<GameObject> 可攻擊敵人列表;
    public void 角色攻擊敵人(GameObject 目標敵人)
    {
        if(是否攻擊敵人 == false)
        {
            float 攻擊速度 = 50 / (1 + 玩家.神力等級() / 3);

            if (目標敵人.GetComponent<itemBasic>().陣營 == 判定.陣營敵人.ToString())
            {
                if (可攻擊敵人列表.Contains(目標敵人) == false)
                {
                    可攻擊敵人列表.Add(目標敵人);
                }

                if (時間秒 - 角色上次攻擊時間 > 攻擊速度)
                {
                    角色上次攻擊時間 = 時間秒;

                    float 暫存距離 = 10000;
                    int 最近敵人 = 0;

                    for (int i = 0; i < 可攻擊敵人列表.Count; i++)
                    {
                        if (可攻擊敵人列表[i] == null)
                        {
                            可攻擊敵人列表.RemoveAt(i);
                            i = 0;
                        }
                        else
                        {
                            float 兩者距離 =
                                Vector2.Distance(player.transform.position, 可攻擊敵人列表[i].transform.position);

                            if (兩者距離 < 暫存距離)
                            {
                                最近敵人 = i;
                                暫存距離 = 兩者距離;
                            }
                        }
                    }


                    //目標敵人 = 可攻擊敵人列表[最近敵人];
                    Debug.Log(可攻擊敵人列表[最近敵人] + "攻擊距離" + 暫存距離);
                    //子彈列表.Add(Instantiate(角色子彈, player.transform.position, new Quaternion(0, 0, 0, 0)));

                    float 生成x位置 = 0;
                    float 生成y位置 = 0;

                    if (可攻擊敵人列表[最近敵人].transform.position.x - player.transform.position.x > 0)
                    {
                        生成x位置 = 0.5f;
                    }
                    else
                    {
                        生成x位置 = -0.5f;
                    }

                    if (可攻擊敵人列表[最近敵人].transform.position.y - player.transform.position.y > 0)
                    {
                        生成y位置 = 0.5f;
                    }
                    else
                    {
                        生成y位置 = -0.5f;
                    }

                    GameObject 暫存新子彈 = Instantiate(角色子彈, new Vector3(player.transform.position.x + 生成x位置, player.transform.position.y + 生成y位置, 0), new Quaternion(0, 0, 0, 0));

                    暫存新子彈.GetComponent<playerBullet>().遊戲管理員 = this;
                    暫存新子彈.GetComponent<playerBullet>().子彈發射(可攻擊敵人列表[最近敵人]);
                    暫存新子彈.GetComponent<playerBullet>().生成時間 = 時間秒;


                    for (int i = 0; i < 可攻擊敵人列表.Count; i++)
                    {
                        if (可攻擊敵人列表[i] == null)
                        {
                            可攻擊敵人列表.RemoveAt(i);
                            i = 0;
                        }
                        else
                        {
                            float 兩者距離 =
                                Vector2.Distance(player.transform.position, 可攻擊敵人列表[i].transform.position);

                            if (兩者距離 > 100)
                            {
                                可攻擊敵人列表.RemoveAt(i);
                                i = 0;
                            }
                        }
                    }
                }
            }
        }

        
    }

//===============================

 public void 子彈發射(GameObject 目標)
    {
        float 目標角度x = 目標.transform.position.x;
        float 目標角度y = 目標.transform.position.y;

        Vector2 目標向量 = new Vector2
(transform.position.x - 目標角度x, 
transform.position.y - 目標角度y);

        //RETURN一個角度值
        float angleZ = Mathf.Atan2(目標向量.y, 目標向量.x) * Mathf.Rad2Deg;

        //把角度值傳給物件
        transform.eulerAngles = new Vector3(0, 0, angleZ + 90);


        //Instantiate(特效, transform.position, transform.rotation);

        單純移動單位(this.gameObject, 20, 目標.transform.position, 遊戲管理員.時間秒, 100, true);
    }

//==============================


程式只是記一下而已,別太在意,
一開始其實直接用OnTriggerStay2D就可以自動攻擊了,
但是這樣沒辦法做出"最近"敵人的效果,
只用Trigger判定會出現鎖定一個敵人後就停不下來了,
土法煉鋼的話網路上是直接弄一個enemylist,
用tag之類的屬性每次尋遍一次,
但是對象有上百上千個時這種做法很吃效能,
還是要用Trigger於實際遇到目標時再弄可攻擊敵人的列表會更好一些,

分成三階段,
1.角色索敵範圍發現敵人,
使用Trigger進入與停在範圍內時發動攻擊,
2.發動攻擊時新增列表,在列表中挑出最近的可攻擊敵人攻擊,
3.攻擊後並且旋轉箭矢,面對敵人射擊,
4.將過遠、已摧毀、已離開攻擊範圍的單位移出列表,

中間卡了一陣子原來是把新增敵人列表的方法寫在了射擊速度延遲後才判定,
其實只要保持有碰撞時立刻判定就不會有這種問題了,
之後來弄個弓箭手、箭塔還有城堡好了,
箭矢有穿透兼少量的擊退效果和沒射中時插在地上一陣子的狀態感覺不錯。
(っ´ω`c)

沒有留言:

張貼留言

你發現了這篇網誌的留言板,在這留點什麼吧|д・)