創作內容

12 GP

Unity的 RTS戰爭迷霧(Fog of War)

作者:is樂小呈│2019-09-10 16:13:44│贊助:24│人氣:150
用一種很暴力的方式完成了
沒有做特效,就是做出概念而已
可以用Shader讓邊不要是鋸齒狀,還有柔邊效果,但我不會做

我還不太會寫這種文,所以如果有那裡看不懂、不清楚的,請一定要提出!

參考資料



來講一下我的作法
我是用一大堆Sprite做出霧
用距離判斷視線範圍
在用物理碰撞判斷要不要隱藏

一共用了三個腳本
FogManager  - 管理所有霧塊
Sight - 讓物件具有視線
HideWithFogs - 讓物件在霧中隱藏

記得設置Layer,要兩個,一個是用來隱藏的,一個是霧的
設置碰撞,讓霧不會撞到東西

然後Camera的Culling Mask
要把Hide的 Layer拿掉
要把Hide的 Layer拿掉
要把Hide的 Layer拿掉
不然會沒用

FogManager - 變數的部分
  [SerializeField] Vector3 mapScale;                                                            //整張地圖的大小
  [SerializeField] Vector3 fogScale = Vector3.up;                                        //每一塊霧的大小

  [SerializeField] SpriteRenderer fogSprite;                                                 //霧的Prefab,
Layer是Fogs

  List<SpriteRenderer> fogs = new List<SpriteRenderer>();                       //用於儲存所有霧塊
  [SerializeField] List<Sight> sights = new List<Sight>();                            //儲存所有具有視線的物件

Sight - 變數的部分
    [SerializeField] float sightRange = 1;                                                         //視線範圍(半徑)
    public float SightRange { get => sightRange;}                                           

HideWithFogs - 變數的部分
    [SerializeField] Transform[] checkPoints;                                                  //檢查有沒有被霧蓋住的點
    [SerializeField] float pointRadius;                                                              //檢查點的半徑

    [SerializeField] LayerMask fogLayer;                                                        //霧的Layer
    [SerializeField] int hideLayer;                                                                    //用於隱藏的Layer
    int defaltLayer;                                                                                           //物件原本的Layer

FogManager - 生成霧塊
首先是生成所有霧塊,這部分應該不需要多做解釋
    void GenerateFogs()
    
{
        for (float x = 0; x < mapScale.x; x += fogScale.x)
        {
            for (float y = 0; y < mapScale.y ; y += fogScale.y)
            {
                Vector3 fogPos = new Vector3(x, y);

                SpriteRenderer fog = Instantiate(fogSprite, fogPos, Quaternion.identity, transform);

                fog.transform.localScale = fogScale;

                fogs.Add(fog);
            }
        }
    }

FogManager - 找出所有有視線的物件
我在Start()調用,如果有視線的物件增加,直接List Add就好
    void FindSights()
    
{
        sights = FindObjectsOfType<Sight>().ToList();
    }

FogManager - 更新霧塊狀態
透過視線與霧塊的座標計算距離,判斷霧塊是否在視線中
    void UpdateFogs()
    
{
        ResetFogs();                                                                                    //重設所有霧塊

        foreach (var sight in sights)                                                             //所有具有視線的物件
        {
            List<SpriteRenderer> sightInFog = fogs.FindAll(n => Vector3.Distance
                    (n.transform.position, sight.transform.position) < sight.SightRange);
                                                                                                               //找出所有在視線中的霧塊

            FogLight(sightInFog);                                                                 //隱藏所有在視線中的霧塊
        }
    }

FogManager - 重設所有霧塊
    void ResetFogs()
    
{
        foreach (var fog in fogs)
        {
            fog.gameObject.SetActive(true);                                                 //把所有霧塊啟用
        }
    }

FogManager - 隱藏(點亮?)霧塊
把進入視線的霧塊隱藏,做出視線的效果
並設定不透明度,達成 [開圖] 的效果
    void FogLight(List<SpriteRenderer> fogs)
    
{
        foreach (var fogSprite in fogs)
        {
            fogSprite.gameObject.SetActive(false);                                    //關閉在視線中的霧塊        

            Color fogColor = fogSprite.color;                      
            fogColor.a = 0.5f;                                               

            fogSprite.color = fogColor;                                                        //設置霧塊不透明度
        }
    }

然後是要隱藏在霧中的物件
HideWithFogs - 檢查物件是否在霧中
在幾個判斷點上,使用物理碰撞檢查點會不會撞到霧,對...撞到(所以才說用很暴力的方式)
如果有[任何一個點]沒撞到霧,就代表物件要現形,反之隱藏


    void CheckObjInFog()
    
{
        if (checkPoints.Length == 0) { return; }                                                //檢查有沒有設置判斷點             

        bool hideWithFog = true;

        foreach (var point in checkPoints)
        {
            if (!Physics2D.OverlapCircle(point.position, pointRadius,fogLayer))
//檢查點有沒有撞到霧
            {
                hideWithFog = false;
                break;
            }
        }

        int setLayer = (hideWithFog) ? hideLayer : defaltLayer;                       //設置要變換的Layer
        SetLayerRecursively(gameObject, setLayer);                                      //設置物件Layer
    }

HideWithFogs - 設置物件Layer
因為在運行時更改Layer,子物件的Layer不會跟著改,所以要另外做
用遞迴找出物件的所有子物件,然後設置Layer
  void SetLayerRecursively(GameObject obj,int layer)
    
{
        if(obj == null) { return; }                                                                         //判斷遞迴中斷

        obj.layer = layer;                                                                                   //設置Layer

        foreach(Transform child in obj.transform)                                             //foreach找出所有子物件
        {
            if(child == null) { continue; }                                                              

            SetLayerRecursively(child.gameObject, layer);                                //下一層遞迴
        }
    }

大概就這樣,應該沒有漏掉什麼吧
現在這個我有改過一次
原本更複雜的...突然想到有更簡單的方法就改了
有點佩服自己有辦法想出其他作法,但又有種我一個上午的努力全部放棄的感覺XD

第一次寫這種的
如我有不清楚的地方再跟我說,我再改

接續的

明天要幹嘛呢~


Brillinat
代數是啥啊 (´・ω・`)

引用網址:https://home.gamer.com.tw/TrackBack.php?sn=4524500
All rights reserved. 版權所有,保留一切權利

相關創作

同標籤作品搜尋:Unity

留言共 5 篇留言

腸腸統測模式-ωก̀

09-10 18:30

is樂小呈
我還沒補好啦XDD09-10 18:32
腸腸統測模式-ωก̀
[e10]

09-10 18:44

is樂小呈
補好ㄌ,不霸09-10 19:00
I2OI3
完了,我覺得我要重學Unity了

09-10 18:47

is樂小呈
沒關C,我查資料的時候也跟重學沒兩樣09-10 19:01
千緒@狐蘿模式
哇幹 有夠猛

09-10 20:51

is樂小呈
還好啦>\\\<09-10 21:01
米矢粒
猛猛的,不過不知道這個作法的效能好不好
如果效能不錯的話應該可以拿來做些奇怪的應用 [e16]

09-11 00:31

is樂小呈
效能嗎...如果地圖小一點應該還好,但真的用在RTS的地圖上應該會很吃力XD09-11 07:43
我要留言提醒:您尚未登入,請先登入再留言

12喜歡★angus945 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:Expansion To... 後一篇:Unity的 RTS戰爭...

追蹤私訊

作品資料夾

asd22552158悠閒的巴友
小屋更新有關剪刀和被詛咒的光碟片的短文後續!看更多我要大聲說昨天21:46


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】