<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      luoyikun

      導航

      unity3d:小地圖UV,UGUIshader毒圈挖孔,吃雞跑毒縮圈

      運行效果

      場景中縮圈

      在這里插入圖片描述

      小地圖中挖孔

      在這里插入圖片描述

      大地圖中挖孔

      在這里插入圖片描述

      小地圖

      方案1使用Mask

      給了一個方形的mask組件,然后根據玩家位置計算出地圖左下角的位置進行移動。這種實現方式雖然簡單,但是會有兩個問題:
      1.Overdraw特別大,幾乎很多時候會有整個屏幕的overdraw;
      2.玩家在移動過程中,因為一直在持續移動圖片的位置(做了適當的降頻處理),所以會一直有UI的Mesh重建過程。

      方案2使用RawImage,UV

      小地圖使用RawImage,設置顯示大小為300*300,其中Texture,放入場景的頂視圖
      在這里插入圖片描述

      如何確定小地圖的UV范圍

      1.先確定w的值為0.1,代表會從整個頂視圖中取寬度占比0.1
      2.再確定h的值,因為地圖長寬不相等,按照 w 總寬 = h*總高,這樣可以得到一個正方形顯示

              public float m_mapWidth = 1680; //世界中場景的寬度,米
              public float m_mapHeight = 960; //世界中場景的高度,米
              m_xScale = 0.1f;
              m_yScale = m_xScale * m_mapWidth / m_mapHeight;
      

      這樣得到w = 0.1,h = 0.175

      如何確定小地圖的UV中X,Y

         public void SetMeInMini()
         {
             float posPlayerX = m_player.position.x / m_mapWidth;
             float posPlayerY = m_player.position.z / m_mapHeight;
      
             m_imgMap.uvRect = new Rect(posPlayerX - m_xScale / 2, posPlayerY - m_yScale / 2, m_xScale, m_yScale);
             Vector3 oriArrow = m_playerArrow.transform.eulerAngles;
             oriArrow.z = -m_player.eulerAngles.y;
             m_playerArrow.eulerAngles = oriArrow;
         }
      

      假設地圖的起點是從0點開始(實際項目時可以加偏移值,x,y,代表3d場景是從偏移點開始,并且增加3d場景的實際寬高)。這里為了簡單實現,未加偏移值,與實際寬高
      在這里插入圖片描述

      因為地圖從0點開始
      x方向,我占地圖的百分比 float posPlayerX = m_player.position.x / m_mapWidth;
      y方向,我占地圖的百分比float posPlayerY = m_player.position.z / m_mapHeight;
      m_imgMap.uvRect = new Rect(posPlayerX - m_xScale / 2, posPlayerY - m_yScale / 2, m_xScale, m_yScale);
      x方向百分比-m_xScale的一半,即為uv的x
      y方向百分比-m_yScale的一半,即為uv的y
      這樣顯示出玩家的位置,一定是在小地圖的中間,并加上箭頭表示我的方向
      在這里插入圖片描述

      如何確定地圖上目標在小地圖位置

      把目標的世界坐標,轉換成小地圖的localPosition

          public Vector3 GetTarget2MiniMapPoint(Vector3 targetWorldPos,Vector3 posPlayer)
          {
              //世界坐標上與me的差,
              float x = (targetWorldPos.x - posPlayer.x) * m_meter2Pixel;
              float y = ( targetWorldPos.z  - posPlayer.z) * m_meter2Pixel;
              return new Vector3(x, y,0);
          }
      

      小地圖大小為300*300,因為是正方形,所以300像素單位最多代表的米為

          public float m_mapWidth = 1680; //世界中場景的寬度,米
          public float m_xScale = 0; //表示 uv 的取值w, 0-1,例如x = 0.1
          public float m_totalMeter = 0; //小地圖,總像素長代表的米  
          m_totalMeter = m_mapWidth * m_xScale; 
      

      那么每個像素單位可代表的米

      m_viewWidth = m_imgMap.rectTransform.rect.width;
       m_meter2Pixel = m_viewWidth / m_totalMeter;
      

      用目標的世界坐標x-我的世界坐標x,結果*m_meter2Pixel,則為目標在小地圖localPosition
      在這里插入圖片描述

      這里需要注意:
      1.小地圖的Pivot,min,max為0.5,才能讓localPosition等于anchoredPosition,否則只能用anchoredPosition設置目標在小地圖位置
      在這里插入圖片描述

      2.目標點localPosition超過小地圖的長寬,可以設置該點顯示隱藏。或者使用RestMask2d

      大地圖

      點擊小地圖,可展開大地圖

      如何確定我大地圖的localPosition

      在這里插入圖片描述

      世界坐標單位米與大地圖上像素對應

      float m_widthPixel = 1680; //大地圖頂視圖這張圖的尺寸,單位像素
          float m_heightPixel = 960;
              public float m_widthScene = 1680; //場景中真實的最大寬,單位米
          public float m_heightScene = 960;
           public float m_scale = 0; //1米可對應多少像素。單位為  像素/米
           m_scale = m_widthPixel / m_widthScene;
      

      在這里插入圖片描述
      在這里插入圖片描述

      大地圖采用真實像素大小,1680,960。雖然在1280*720的視圖中有些邊界顯示不到,那是項目設計如此,邊界不可達到

      世界坐標轉大地圖localPosition

         public Vector2 PosWorld2Local(Vector2 pos)
         {
             Vector2 ret = Vector2.zero;
             float x = pos.x * m_scale;
             x -= m_widthPixel / 2;
      
             float y = pos.y * m_scale;
             y -= m_heightPixel / 2;
      
             ret = new Vector2(x, y);
             return ret;
         }
      

      目標位置x * m_scale,可得到像素坐標x,-m_widthPixel / 2,地圖bg的像素的一半,可得到在大地圖中的localPosition

      縮圈機制

      1.小圓一定是全部包含在大圓內部。運動的是大圓,直到大圓與小圓圓心,半徑重合
      2.縮圈運動分兩個階段,第一階段為向內切運動:大圓圓心不變,按照速度縮小大圓半徑,直到大圓半徑 = 圓心距離+小圓半徑
      3.第二階段為先小圓運動:大圓圓心向著小圓圓心移動,同時大圓半徑縮小,直到大圓半徑= 小圓半徑

      第一階段內切運動

      在這里插入圖片描述

      小圓一開始在大圓內部,如果大圓半徑R1> 小圓半徑R2+圓心距離,說明還處在第一階段向內切運動,否則轉向第二階段,向小圓運動

      第二階段向小圓運動

      在這里插入圖片描述

      大圓的圓心P1向小圓圓心P2移動,每幀半徑減少
      float diffBigR = m_circleData.speed * Time.deltaTime
      那么大圓圓心在x,y方向上變化量為
      m_circleData.bigPos.x += diffBigR * m_circleData.cos;
      m_circleData.bigPos.y += diffBigR * m_circleData.sin;

      縮圈數據

      public class CircleData
      {
          public float bigR; //大圓半徑
          public Vector2 bigPos; //世界坐標,大圓圓心
      
          public float smallR; //小圓半徑
          public Vector2 smallPos;//世界坐標,小圓圓心
      
          public float time = 10; //總共運動時間
          public float speed; //速度
          public float dis; //兩圓心初始距離
          public float cos;  //大圓移動x上投影分量
          public float sin; //大圓移動y上投影分量
      

      速度speed即為每幀大圓半徑需要減少數值,用半徑差/總時間

      speed = (bigR - smallR) / time;
      

      dis兩圓心初始距離

      dis = Vector2.Distance(bigPos, smallPos);
      

      cos,sin的運動分量
      內切運動運動結束后,每次大圓圓心,x方向+半徑變化值*cos,即為新的大圓圓心x位置
      有以下幾種狀態

      if (bigPos.x == smallPos.x && bigPos.y != smallPos.y)
              {
                  cos = 0;
                  sin = 1;
              }
              else if (bigPos.x != smallPos.x && bigPos.y == smallPos.y)
              {
                  cos = 1;
                  sin = 0;
              }
              else if (bigPos.x == smallPos.x && bigPos.y == smallPos.y)
              {
                  cos = 0;
                  sin = 0;
              }
              else 
              {
                  float a = smallPos.x - bigPos.x;
                  float b = smallPos.y - bigPos.y;
                  
                  cos = a / dis;
                  sin = b /dis;
              }
      

      大圓運動

      在update中執行
      1.每幀大圓半徑的變化量為m_circleData.speed * Time.deltaTime
      2.大圓半徑的減少為m_circleData.bigR -= diffBigR;
      3.當是向內切階段運動,則只會減少大圓半徑
      4.當是向小圓階段運動,減少大圓半徑的同時,大圓圓心運動
      m_circleData.bigPos.x += diffBigR * m_circleData.cos;
      m_circleData.bigPos.y += diffBigR * m_circleData.sin;
      5.直到大圓半徑《=小圓半徑,說明運動結束

      float diffBigR = m_circleData.speed * Time.deltaTime;
                  m_circleData.bigR -= diffBigR;
                  if (m_circleData.bigR > m_circleData.smallR + m_circleData.dis)
                  {
                      Debug.Log("內切");
                      UpdateTransCircle();
                  }
                  else if (m_circleData.bigR > m_circleData.smallR && m_circleData.bigR <= m_circleData.smallR + m_circleData.dis)
                  {
                      Debug.Log("小圓");
                      m_circleData.bigPos.x += diffBigR * m_circleData.cos;
                      m_circleData.bigPos.y += diffBigR * m_circleData.sin;
                      UpdateTransCircle();
                  }
                  else if (m_circleData.bigR <= m_circleData.smallR)
                  {
                      m_isMove = false;
                  }
      

      毒圈在場景中表現
      為一個去掉上頂,下底的圓柱體,每次移動改變它的坐標與縮放

          void UpdateTransCircle()
          {
              m_transCircle.position = new Vector3(m_circleData.bigPos.x, 0, m_circleData.bigPos.y);
              m_transCircle.localScale = new Vector3(m_circleData.bigR * 2, 1, m_circleData.bigR * 2);
          }
      

      在這里插入圖片描述

      UGUI上毒圈挖孔

      效果

      小地圖上顯示
      在這里插入圖片描述

      大地圖上顯示
      在這里插入圖片描述

      其中白圈為小圓,即最終安全區
      外圍大圈會大圓不斷縮小移動

      小地圖Mask

      使用跟小地圖同樣像素大小的RawImage。
      在這里插入圖片描述

      大地圖Mask

      在這里插入圖片描述

      可以使用不同像素大小,例如屏幕分辨率為1280720,大地圖bg實際為1680960。但是他們的中心點是一致的,這樣傳遞的localPosition在大地圖上,和傳遞到Mask上是對等的
      在這里插入圖片描述

      shader處理

      v2f vert(appdata_t v)
      				{
      					v2f o;
      					o.vertex = UnityObjectToClipPos(v.vertex);
      					o.worldPosition = mul(unity_ObjectToWorld, v.vertex);
      					o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
      					o.color = v.color;
      					return o;
      				}
      
      			
      				fixed4 frag(v2f i) : SV_Target
      				{
      					//顯示白圈
      					float2 diffCurWithSmallllCenter = float2(i.worldPosition.x, i.worldPosition.y) - float2(_CenterSmall.x, _CenterSmall.y);
      					float disCurWithSmallCenter = sqrt(diffCurWithSmallllCenter.x * diffCurWithSmallllCenter.x + diffCurWithSmallllCenter.y * diffCurWithSmallllCenter.y);
      					if (abs(disCurWithSmallCenter - _SmallR) < _SmallWidth )
      					{
      						return float4(1, 1, 1, 1);
      					}
      
      
      				   float2 center = float2(i.worldPosition.x, i.worldPosition.y) - float2(_Center.x, _Center.y);
      				   float disSquare = (center.x * center.x + center.y * center.y);
      
      				   //比較距離大小,可以不用開平方
      				   clip(disSquare - _BigRSquare);
      
      				   fixed4 col = tex2D(_MainTex, i.texcoord) * i.color;
      				   return col;
      				}
      

      顯示小圓白圈

      當前世界坐標與小圓圓心的坐標相差

      float2 diffCurWithSmallllCenter = float2(i.worldPosition.x, i.worldPosition.y) - float2(_CenterSmall.x, _CenterSmall.y);
      

      當前世界坐標與小圓圓心距離disCurWithSmallCenter,坐標開平方

      float disCurWithSmallCenter = sqrt(diffCurWithSmallllCenter.x * diffCurWithSmallllCenter.x + diffCurWithSmallllCenter.y * diffCurWithSmallllCenter.y);
      

      disCurWithSmallCenter - 小圓半徑的絕對值,< _SmallWidth,直接返回白色

      					if (abs(disCurWithSmallCenter - _SmallR) < _SmallWidth )
      					{
      						return float4(1, 1, 1, 1);
      					}
      

      因為小圓是要距離差的絕對值與圈寬_SmallWidth比較,所以不能使用平方比較

      大圓挖孔

      當前世界坐標與大圓圓心坐標差

      float2 center = float2(i.worldPosition.x, i.worldPosition.y) - float2(_Center.x, _Center.y);
      

      當前世界坐標與大圓圓心的距離的平方

       float disSquare = (center.x * center.x + center.y * center.y);
      

      距離的平方<大圓半徑的平方,則舍棄

      //比較距離大小,可以不用開平方
      clip(disSquare - _BigRSquare);
      

      因為只要比較距離的平方的大小,這樣省去一步開平方計算,提高點性能

      C#中傳遞參數給Shader

          public void SetClip(Vector2 vec, float radius, Vector2 smallPos,float smallR)
          {
              Vector3 centerWrold = transform.TransformPoint(new Vector3(vec.x,vec.y,0));
              m_mat.SetVector("_Center", centerWrold);
              Vector3 pointInCircle = new Vector3(vec.x + radius, vec.y,0);
              Vector3 pointInCircleWorld = transform.TransformPoint(pointInCircle);
              Vector2 diffVecWorld = centerWrold - pointInCircleWorld;
              float bigRSquare = diffVecWorld.x * diffVecWorld.x + diffVecWorld.y * diffVecWorld.y;
              m_mat.SetFloat("_BigRSquare", bigRSquare);
      
              Vector3 smallPosWorld = transform.TransformPoint(new Vector3(smallPos.x, smallPos.y, 0));
              m_mat.SetVector("_CenterSmall", smallPosWorld);
              Vector3 pointInCircleSmall = new Vector3(smallPos.x + smallR, smallPos.y, 0);
              Vector3 pointInCircleWorldSamll = transform.TransformPoint(pointInCircleSmall);
              Vector2 diffVecWorldSmall = smallPosWorld - pointInCircleWorldSamll;
              float smallRSquare = diffVecWorldSmall.x * diffVecWorldSmall.x + diffVecWorldSmall.y * diffVecWorldSmall.y;
              float smallRWorld = Vector2.Distance(smallPosWorld, pointInCircleWorldSamll);
              m_mat.SetFloat("_SmallR", smallRWorld);
          }
      

      傳遞圓心坐標值

      不管大地圖,小地圖,傳遞的坐標為基于地圖的localPosition,所以都要用Mask的transform轉為世界坐標。mask即是挖孔

      Vector3 centerWrold = transform.TransformPoint(new Vector3(vec.x,vec.y,0));
      

      傳遞半徑值

      大圓

      傳入參數radius是指UI上的像素值,先用圓心x+半徑,得到半徑上一點,在UI上localPosition

      Vector3 pointInCircle = new Vector3(vec.x + radius, vec.y,0);
      

      再轉為mask世界坐標上一點

      Vector3 pointInCircleWorld = transform.TransformPoint(pointInCircle);
      

      大圓只需要傳遞世界坐標下半徑的平方,在shader做為世界坐標差平方,與大圓半徑平方比較,進行clip。shader中減少一次開根運算

      Vector2 diffVecWorld = centerWrold - pointInCircleWorld;
              float bigRSquare = diffVecWorld.x * diffVecWorld.x + diffVecWorld.y * diffVecWorld.y;
              m_mat.SetFloat("_BigRSquare", bigRSquare);
      

      小圓

      小圓因為要畫一個白圈,具有一定的寬度,所以只能傳遞小圓半徑
      傳入半徑smallR,是UI上像素長
      先用圓心x+半徑,得到半徑上一點,在UI上localPosition

      Vector3 pointInCircleSmall = new Vector3(smallPos.x + smallR, smallPos.y, 0);
      

      再轉基于mask的世界坐標

      Vector3 pointInCircleWorldSamll = transform.TransformPoint(pointInCircleSmall);
      

      算出半徑上一點,與圓心的世界坐標上差距,即為小圓世界坐標下半徑長,傳入shader

      Vector3 pointInCircleWorldSamll = transform.TransformPoint(pointInCircleSmall);
              float smallRWorld = Vector2.Distance(smallPosWorld, pointInCircleWorldSamll);
              m_mat.SetFloat("_SmallR", smallRWorld);
      

      小地圖傳遞值

      大圓的世界坐標圓心,轉小地圖的localPosition

      Vector3 bigV3 = new Vector3(CircleMgr.instance.m_circleData.bigPos.x, 0, CircleMgr.instance.m_circleData.bigPos.y);
                  Vector3 bigPos = GetTarget2MiniMapPoint(bigV3, m_player.position);
      

      大圓的半徑轉成小地圖的像素值

      float bigR = CircleMgr.instance.m_circleData.bigR * m_meter2Pixel;
      

      小圓同理,傳遞進入Mask

                  Vector3 bigV3 = new Vector3(CircleMgr.instance.m_circleData.bigPos.x, 0, CircleMgr.instance.m_circleData.bigPos.y);
                  Vector3 bigPos = GetTarget2MiniMapPoint(bigV3, m_player.position);
                  float bigR = CircleMgr.instance.m_circleData.bigR * m_meter2Pixel;
      
                  Vector3 smallV3 = new Vector3(CircleMgr.instance.m_circleData.smallPos.x, 0, CircleMgr.instance.m_circleData.smallPos.y);
                  Vector3 smallPos = GetTarget2MiniMapPoint(smallV3, m_player.position);
                  float smallR = CircleMgr.instance.m_circleData.smallR * m_meter2Pixel;
      
                  m_circleClip.SetClip(bigPos, bigR, smallPos, smallR);
      

      大地圖傳遞值

      大圓圓心世界坐標轉地圖上localPosition

      Vector2 bigPos = PosWorld2Local(CircleMgr.instance.m_circleData.bigPos);
      

      大圓半徑世界坐標(米為單位)轉地圖上像素單位

      float bigR = CircleMgr.instance.m_circleData.bigR* m_scale;
      

      小圓同理,傳遞進入Mask

                  Vector2 bigPos = PosWorld2Local(CircleMgr.instance.m_circleData.bigPos);
                  Vector2 smallPos = PosWorld2Local(CircleMgr.instance.m_circleData.smallPos);
                  float bigR = CircleMgr.instance.m_circleData.bigR* m_scale;
                  float smallR = CircleMgr.instance.m_circleData.smallR* m_scale;
      
                  m_circleClip.SetClip(bigPos,bigR, smallPos, smallR);
      

      posted on 2023-06-18 17:36  luoyikun  閱讀(118)  評論(0)    收藏  舉報  來源

      主站蜘蛛池模板: 亚洲成年轻人电影网站WWW| 亚洲国产成人久久综合同性| 亚洲午夜福利网在线观看| 又长又粗又爽又高潮的视频| 116美女极品a级毛片| gogogo高清在线播放免费| 亚洲人成电影网站 久久影视| 国产精品三级中文字幕| 国产对白老熟女正在播放| 成人自拍小视频免费观看| www欧美在线观看| 暖暖 免费 高清 日本 在线观看5| 亚洲免费观看视频| 亚洲夜色噜噜av在线观看| 国产午夜亚洲精品国产成人| 国产在线播放专区av| av天堂久久天堂av| 国产偷国产偷亚洲高清午夜| 2019香蕉在线观看直播视频| 欧美老熟妇乱子伦牲交视频| 欧美性69式xxxx护士| 国精品无码一区二区三区在线| 精品国产精品午夜福利| 亚洲精品男男一区二区| 盱眙县| 亚洲一区二区av偷偷| 国产午夜亚洲精品国产成人| 亚洲av成人一区在线| 天堂在线最新版在线天堂| 新竹县| 国产av中文字幕精品| 亚洲狠狠婷婷综合久久久| 国产精品亚洲а∨无码播放| 亚洲精品自拍视频在线看| 国产xxxx做受视频| 开心久久综合激情五月天| 亚洲V天堂V手机在线| 精品国产一区AV天美传媒| 亚洲天堂成人一区二区三区| 国产97人人超碰caoprom| 精品天堂色吊丝一区二区|