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

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

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

      gogoDragon

      導航

      Unity自學--CreatorKit代碼解析 1

      Unity初學者項目 Creator Kit Beginner

      ExampleScene 樣例場景如下

       1.附著腳本:(Character)

      Character對象是游戲項目的PLayer,即玩家操縱的游戲對象,對于Character來說,需要擁有自己的運行腳本。

      附著在Character對象上的運行腳本有如下:

       

       可以看到,除了基礎的Transform模塊外還存在CapsuleCollider 用于檢測碰撞,NavMeshAgent用于自動尋路,Rigidbody用于描述物體的物理性質,官方文檔有詳細描述。

      2.CharacterControl 代碼解析

      using System.Collections;
      using System.Collections.Generic;
      using System.Data;
      using System.Timers;
      using CreatorKitCode;
      using UnityEngine;
      using UnityEngine.AI;
      using UnityEngine.EventSystems;
      using UnityEngine.Serialization;
      
      namespace CreatorKitCodeInternal {
          //繼承了基類,實現了攻擊,移動的接口
          public class CharacterControl : MonoBehaviour, 
              AnimationControllerDispatcher.IAttackFrameReceiver,
              AnimationControllerDispatcher.IFootstepFrameReceiver
          {
              //單例對象
              public static CharacterControl Instance { get; protected set; }
          
              //移動速度
              public float Speed = 10.0f;
      
              //角色數據 => 依賴于m_CharacterData 即附著在Character中的CharacterData腳本類
              public CharacterData Data => m_CharacterData;
              //目標數據 => 依賴于m_CurrentTargetCharacterData 即附著在其他對象中的CharacterData腳本類
              public CharacterData CurrentTarget => m_CurrentTargetCharacterData;
      
              //武器的位置數據等
              public Transform WeaponLocator;
          
              //[Header] 顯示標頭 在Unity中顯示Audio
              [Header("Audio")]
              //音頻數據
              public AudioClip[] SpurSoundClips;
          
              //最后射線的位置
              Vector3 m_LastRaycastResult;
              //動畫播放器
              Animator m_Animator;
              //尋路器
              NavMeshAgent m_Agent;
              //用戶數據
              CharacterData m_CharacterData;
      
              //高光類,用于高光渲染
              HighlightableObject m_Highlighted;
      
              //RaycastHit用于存儲RayCast(射線)命中的數據
              RaycastHit[] m_RaycastHitCache = new RaycastHit[16];
      
              int m_SpeedParamID;
              int m_AttackParamID;
              int m_HitParamID;
              //眩暈id
              int m_FaintParamID;
              //復位,出生ID
              int m_RespawnParamID;
      
              bool m_IsKO = false;
              float m_KOTimer = 0.0f;
      
              //交互層級--層級
              int m_InteractableLayer;
              int m_LevelLayer;
              //碰撞器
              Collider m_TargetCollider;
              //交互對象
              InteractableObject m_TargetInteractable = null;
              //主視角
              Camera m_MainCamera;
              //自動尋路組件產生的路徑,保存在corners中
              NavMeshPath m_CalculatedPath;
              //主角音頻
              CharacterAudio m_CharacterAudio;
              //目標層 當前目標數據
              int m_TargetLayer;
              CharacterData m_CurrentTargetCharacterData = null;
              //this is a flag that tell the controller it need to clear the target once the attack finished.
              //usefull for when clicking elwswhere mid attack animation, allow to finish the attack and then exit.
              //當攻擊完成后需要清除的標志位,用于攻擊動畫途中點擊某個位置時允許退出攻擊狀態并離開
              bool m_ClearPostAttack = false;
      
              //復生點,當經過存在復生點的區域時,設置復生點
              SpawnPoint m_CurrentSpawn = null;
          
              //枚舉狀態 默認 受擊 攻擊
              enum State
              {
                  DEFAULT,
                  HIT,
                  ATTACKING
              }
      
              //當前狀態
              State m_CurrentState;
      
              //初始化實例 獲得主攝像機 Camera.main tag標簽為MainCamera的攝像機
              void Awake()
              {
                  Instance = this;
                  m_MainCamera = Camera.main;
              }
      
              // Start is called before the first frame update
              void Start()
              {
                  //QualitySettings品質接口 此處為不等待垂直同步 (垂直同步防止跳幀,撕裂(關閉會更流暢))
                  QualitySettings.vSyncCount = 0;
                  //嘗試60fps 設置了QualitySettings.vSyncCount之后,targetFrameRate不使用,使用平臺默認刷新率
                  Application.targetFrameRate = 60;
              
                  //新建路徑
                  m_CalculatedPath = new NavMeshPath();
              
                  //獲取尋路組件,動畫組件
                  m_Agent = GetComponent<NavMeshAgent>();
                  m_Animator = GetComponentInChildren<Animator>();
              
                  //尋路的速度設為當前移動速度
                  m_Agent.speed = Speed;
                  //設置最大回轉速度 需要轉彎的速度
                  m_Agent.angularSpeed = 360.0f;
      
                  //射線位置設為當前位置
                  m_LastRaycastResult = transform.position;
      
                  //初始化動畫ID
                  m_SpeedParamID = Animator.StringToHash("Speed");
                  m_AttackParamID = Animator.StringToHash("Attack");
                  m_HitParamID = Animator.StringToHash("Hit");
                  m_FaintParamID = Animator.StringToHash("Faint");
                  m_RespawnParamID = Animator.StringToHash("Respawn");
      
                  //獲得人物數據
                  m_CharacterData = GetComponent<CharacterData>();
      
                  //給人物數據中的武器裝備動作提供
                  m_CharacterData.Equipment.OnEquiped += item =>
                  {
                      if (item.Slot == (EquipmentItem.EquipmentSlot)666)
                      {
                          //初始化預制件,父類是當前對象,不在世界坐標系下生成(父類坐標系下生成)
                          var obj = Instantiate(item.WorldObjectPrefab, WeaponLocator, false);
                          //將每一層都變為PlayerEquipment層循環調用
                          Helpers.RecursiveLayerChange(obj.transform, LayerMask.NameToLayer("PlayerEquipment"));
                      }
                  };
              
                  m_CharacterData.Equipment.OnUnequip += item =>
                  {
                      if (item.Slot == (EquipmentItem.EquipmentSlot)666)
                      {
                          //摧毀所有的角色
                          foreach(Transform t in WeaponLocator)
                              Destroy(t.gameObject);
                      }
                  };
                  
                  //角色數據初始化
                  m_CharacterData.Init();
              
                  //獲得層級位置
                  m_InteractableLayer = 1 << LayerMask.NameToLayer("Interactable");
                  m_LevelLayer = 1 << LayerMask.NameToLayer("Level");
                  m_TargetLayer = 1 << LayerMask.NameToLayer("Target");
      
                  //設置默認狀態
                  m_CurrentState = State.DEFAULT;
      
                  //設置音頻
                  m_CharacterAudio = GetComponent<CharacterAudio>();
              
                  //受傷時的動作函數 (設置動畫,調用Hit函數播放)
                  m_CharacterData.OnDamage += () =>
                  {
                      m_Animator.SetTrigger(m_HitParamID);
                      m_CharacterAudio.Hit(transform.position);
                  };
              }
      
              // Update is called once per frame
              void Update()
              {
      
                  Vector3 pos = transform.position;
      
                  //判斷是否死了,死了設置復活時間m_KOTimer,達到3s后調用GoToRespawn()復活
                  if (m_IsKO)
                  {
                      m_KOTimer += Time.deltaTime;
                      if (m_KOTimer > 3.0f)
                      {
                          GoToRespawn();
                      }
      
                      return;
                  }
      
                  //The update need to run, so we can check the health here.
                  //Another method would be to add a callback in the CharacterData that get called
                  //when health reach 0, and this class register to the callback in Start
                  //(see CharacterData.OnDamage for an example)
                  //當前生命值為 0時死亡
                  if (m_CharacterData.Stats.CurrentHealth == 0)
                  {
                      //設置眩暈狀態
                      m_Animator.SetTrigger(m_FaintParamID);
      
                      //尋路停止
                      m_Agent.isStopped = true;
                      //清空路徑
                      m_Agent.ResetPath();
                      //狀態值為死亡
                      m_IsKO = true;
                      //設置復活計時器
                      m_KOTimer = 0.0f;
                  
                      //調用死亡函數
                      Data.Death();
                      
                      //調用死亡音頻
                      m_CharacterAudio.Death(pos);
                  
                      return;
                  }
                  
                  //沒死亡的話 獲取在鼠標位置射線
                  Ray screenRay = CameraController.Instance.GameplayCamera.ScreenPointToRay(Input.mousePosition);
              
                  //交互對象不為空 ,進入交互狀態
                  if (m_TargetInteractable != null)
                  {
                      CheckInteractableRange();
                  }
      
                  //目標數據不為空 判斷對象是否死亡,是置為空,否則進入攻擊狀態
                  if (m_CurrentTargetCharacterData != null)
                  {
                      if (m_CurrentTargetCharacterData.Stats.CurrentHealth == 0)
                          m_CurrentTargetCharacterData = null;
                      else
                          CheckAttack();
                  }
              
                  //鼠標滾輪事件
                  float mouseWheel = Input.GetAxis("Mouse ScrollWheel");
                  //如果滾動了
                  if (!Mathf.Approximately(mouseWheel, 0.0f))
                  {
                      //獲取當前的鼠標位置(從屏幕空間變換為視口空間)
                      Vector3 view = m_MainCamera.ScreenToViewportPoint(Input.mousePosition);
                      //如果處在攝像機范圍內
                      if(view.x > 0f && view.x < 1f && view.y > 0f && view.y < 1f)
                          //變換攝像機視角
                          CameraController.Instance.Zoom(-mouseWheel * Time.deltaTime * 20.0f);
                  }
              
                  if(Input.GetMouseButtonDown(0))
                  { //if we click the mouse button, we clear any previously et targets
      
                      //按下按鍵但不是攻擊狀態時,清空所有的對象(攻擊對象,交互對象) 否則攻擊后清除
                      if (m_CurrentState != State.ATTACKING)
                      {
                          m_CurrentTargetCharacterData = null;
                          m_TargetInteractable = null;
                      }
                      else
                      {
                          //處于攻擊狀態時
                          m_ClearPostAttack = true;
                      }
                  }
      
                  //EventSystem.current.IsPointerOverGameObject()判斷觸點是否在對象上而不是UI上
                  if (!EventSystem.current.IsPointerOverGameObject() && m_CurrentState != State.ATTACKING)
                  {
                      //Raycast to find object currently under the mouse cursor
                      //用射線的方式獲取光標位置下的對象
                      //設置為高光對象 沒有 則不設置
                      ObjectsRaycasts(screenRay);
                  
                      if (Input.GetMouseButton(0))
                      {
                          //如果按下按鍵
                          if (m_TargetInteractable == null && m_CurrentTargetCharacterData == null)
                          {
                              //判斷高光對象
                              InteractableObject obj = m_Highlighted as InteractableObject;
                              if (obj)
                              {
                                  InteractWith(obj);
                              }
                              else
                              {
                                  CharacterData data = m_Highlighted as CharacterData;
                                  if (data != null)
                                  {
                                      m_CurrentTargetCharacterData = data;
                                  }
                                  else
                                  {
                                      //高光對象也為NULL則尋路檢查
                                      MoveCheck(screenRay);
                                  }
                              }
                          }
                      }
                  }
      
                  //設置平滑的移動
                  m_Animator.SetFloat(m_SpeedParamID, m_Agent.velocity.magnitude / m_Agent.speed);
              
                  //Keyboard shortcuts
                  //按I鍵獲取物品欄
                  if(Input.GetKeyUp(KeyCode.I))
                      UISystem.Instance.ToggleInventory();
              }
      
              void GoToRespawn()
              {
                  m_Animator.ResetTrigger(m_HitParamID);
              
                  //設置代理路徑
                  m_Agent.Warp(m_CurrentSpawn.transform.position);
                  //停止尋路
                  m_Agent.isStopped = true;
                  //清空路徑
                  m_Agent.ResetPath();
                  //復活
                  m_IsKO = false;
      
                  //所有狀態重置
                  m_CurrentTargetCharacterData = null;
                  m_TargetInteractable = null;
      
                  m_CurrentState = State.DEFAULT;
              
                  m_Animator.SetTrigger(m_RespawnParamID);
      
                  //恢復狀態
                  m_CharacterData.Stats.ChangeHealth(m_CharacterData.Stats.stats.health);
              }
      
              void ObjectsRaycasts(Ray screenRay)
              {
                  //bool值
                  bool somethingFound = false;
      
                  //first check for interactable Object
                  //往screenRay方向投射球體,半徑為1,m_RaycastHitCache存儲命中對象,m_InteractableLayer遮罩層忽略不在層中的對象
                  int count = Physics.SphereCastNonAlloc(screenRay, 1.0f, m_RaycastHitCache, 1000.0f, m_InteractableLayer);
                  //緩沖區個數不為0時
                  if (count > 0)
                  {
                      for (int i = 0; i < count; ++i)
                      {
                          //獲取每個碰撞體中的可交互對象(附著體)
                          InteractableObject obj = m_RaycastHitCache[0].collider.GetComponentInParent<InteractableObject>();
                          //不為NULL且可交互時
                          if (obj != null && obj.IsInteractable)
                          {
                              //調用函數使物體高光
                              SwitchHighlightedObject(obj);
                              //設置為找到東西,跳出循環
                              somethingFound = true;
                              break;
                          }
                      }
                  }
                  else
                  {
                      //往screenRay方向投射球體,半徑為1,m_RaycastHitCache存儲命中對象,m_InteractableLayer遮罩層忽略不在層中的對象
                      count = Physics.SphereCastNonAlloc(screenRay, 1.0f, m_RaycastHitCache, 1000.0f, m_TargetLayer);
      
                      if (count > 0)
                      {
                          CharacterData data = m_RaycastHitCache[0].collider.GetComponentInParent<CharacterData>();
                          //數據不為null時
                          if (data != null)
                          {
                              SwitchHighlightedObject(data);
                              somethingFound = true;
                          }
                      }
                  }
      
                  //沒找到對象并且高光對象不為NULL時
                  if (!somethingFound && m_Highlighted != null)
                  {
                      //清除高光對象
                      SwitchHighlightedObject(null);
                  }
              }
      
              void SwitchHighlightedObject(HighlightableObject obj)
              {
                  //高光對象不為null時 取消高光
                  if(m_Highlighted != null) m_Highlighted.Dehighlight();
      
                  //設置高光對象
                  m_Highlighted = obj;
                  //高光對象不為null時 設置高光
                  if (m_Highlighted != null) m_Highlighted.Highlight();
              }
      
              //移動檢測
              void MoveCheck(Ray screenRay)
              {
                  //判斷尋路狀態是否在目的地終止 NavMeshPathStatus.PathComplete
                  if ( m_CalculatedPath.status == NavMeshPathStatus.PathComplete)
                  {
                      //設置新路徑
                      m_Agent.SetPath(m_CalculatedPath);
                      //清除路徑
                      m_CalculatedPath.ClearCorners();
                  }
              
                  if (Physics.RaycastNonAlloc(screenRay, m_RaycastHitCache, 1000.0f, m_LevelLayer) > 0)
                  {
                      //拋射對象大于0時,點擊位置的對象,選擇碰到的第一個
                      //獲取第一個對象
                      Vector3 point = m_RaycastHitCache[0].point;
                      //avoid recomputing path for close enough click
                      //避免重復計算近距離點擊(點在上次點的位置附近的就不移動了)
                      if (Vector3.SqrMagnitude(point - m_LastRaycastResult) > 1.0f)
                      {
                          NavMeshHit hit;
                          //NavMesh.SamplePosition判斷是否是可行區域  point 目標點 hit 輸出最近路徑 NavMesh.AllAreas全路段
                          if (NavMesh.SamplePosition(point, out hit, 0.5f, NavMesh.AllAreas))
                          {//sample just around where we hit, avoid setting destination outside of navmesh (ie. on building)
                              //是可行區域設置之前的位置
                              m_LastRaycastResult = point;
                              //m_Agent.SetDestination(hit.position);
      
                              //計算路徑并將其儲存到m_CalculatedPath中
                              m_Agent.CalculatePath(hit.position, m_CalculatedPath);
                          }
                      }
                  }
              }
      
              //交互
              void CheckInteractableRange()
              {
                  //攻擊狀態,則不交互
                  if(m_CurrentState == State.ATTACKING)
                      return;
      
                  //ClosestPointOnBounds與目標碰撞體碰撞的最近的位置  相減得出距離
                  Vector3 distance = m_TargetCollider.ClosestPointOnBounds(transform.position) - transform.position;
              
                  
                  //距離小于一個范圍
                  if (distance.sqrMagnitude < 1.5f * 1.5f)
                  {
                      //停止尋路
                      StopAgent();
                      //交互
                      m_TargetInteractable.InteractWith(m_CharacterData);
                      //交互完了,交互對象為NULL,再次點擊才會繼續交互
                      m_TargetInteractable = null;
                  }
              }
      
              //停止尋路
              void StopAgent()
              {
                  m_Agent.ResetPath();
                  //速度為0 立刻停止
                  m_Agent.velocity = Vector3.zero;
              }
      
              void CheckAttack()
              {
                  //處于攻擊狀態,返回
                  if(m_CurrentState == State.ATTACKING)
                      return;
                     
                  //是否達到攻擊范圍
                  if (m_CharacterData.CanAttackReach(m_CurrentTargetCharacterData))
                  {
                      //達到,停止尋路
                      StopAgent();
      
                      //if the mouse button isn't pressed, we do NOT attack
                      //判斷是否按下攻擊鍵
                      if (Input.GetMouseButton(0))
                      {
                          //獲得兩者的距離
                          Vector3 forward = (m_CurrentTargetCharacterData.transform.position - transform.position);
                          //垂直距離為0
                          forward.y = 0;
                          //歸一化
                          forward.Normalize();
      
                          //設置標準化矢量
                          transform.forward = forward;
                          //判斷是否能夠攻擊到目標
                          if (m_CharacterData.CanAttackTarget(m_CurrentTargetCharacterData))
                          {
                              //能則進入攻擊狀態
                              m_CurrentState = State.ATTACKING;
      
                              //播放動畫和音效
                              m_CharacterData.AttackTriggered();
                              m_Animator.SetTrigger(m_AttackParamID);
                          }
                      }
                  }
                  else
                  {
                      //沒達到則設置攻擊目標的位置為尋路位置
                      m_Agent.SetDestination(m_CurrentTargetCharacterData.transform.position);
                  }
              }
      
              public void AttackFrame()
              {
                  //攻擊幀 攻擊人物不存在了 放棄攻擊 返回
                  if (m_CurrentTargetCharacterData == null)
                  {
                      m_ClearPostAttack = false;
                      return;
                  }
      
                  //if we can't reach the target anymore when it's time to damage, then that attack miss.
                  //攻擊范圍是否達到了
                  if (m_CharacterData.CanAttackReach(m_CurrentTargetCharacterData))
                  {
                      //攻擊
                      m_CharacterData.Attack(m_CurrentTargetCharacterData);
                      //設置攻擊位置和播放動畫和音頻
                      var attackPos = m_CurrentTargetCharacterData.transform.position + transform.up * 0.5f;
                      VFXManager.PlayVFX(VFXType.Hit, attackPos);
                      SFXManager.PlaySound(m_CharacterAudio.UseType, new SFXManager.PlayData() { Clip = m_CharacterData.Equipment.Weapon.GetHitSound(), PitchMin = 0.8f, PitchMax = 1.2f, Position = attackPos });
                  }
      
                  //攻擊過了
                  if(m_ClearPostAttack)
                  {
                      //清空所有對象
                      m_ClearPostAttack = false;
                      m_CurrentTargetCharacterData = null;
                      m_TargetInteractable = null;
                  }
                  //恢復默認狀態
                  m_CurrentState = State.DEFAULT;
              }
      
              //設置出生點
              public void SetNewRespawn(SpawnPoint point)
              {
                  //設置為死寂狀態(enable屬性為可用)
                  if(m_CurrentSpawn != null)
                      m_CurrentSpawn.Deactivated();
      
                  m_CurrentSpawn = point;
                  //設置為活躍狀態
                  m_CurrentSpawn.Activated();
              }
      
              //交互函數
              public void InteractWith(InteractableObject obj)
              {
                  if (obj.IsInteractable)
                  {
                      //可交互則獲得碰撞器
                      m_TargetCollider = obj.GetComponentInChildren<Collider>();
                      //獲得交互對象
                      m_TargetInteractable = obj;
                      //設置尋路目標
                      m_Agent.SetDestination(obj.transform.position);
                  }
              }
      
              //實現的接口函數
              public void FootstepFrame()
              {
                  Vector3 pos = transform.position;
              
                  m_CharacterAudio.Step(pos);
              
                  SFXManager.PlaySound(SFXManager.Use.Player, new SFXManager.PlayData()
                  {
                      Clip = SpurSoundClips[Random.Range(0, SpurSoundClips.Length)], 
                      Position = pos,
                      PitchMin = 0.8f,
                      PitchMax = 1.2f,
                      Volume = 0.3f
                  });
              
                  VFXManager.PlayVFX(VFXType.StepPuff, pos);  
              }
          }
      }

      3.整體人物邏輯設計(Update邏輯詳解)

       

      posted on 2022-04-05 19:36  我不知道學些啥  閱讀(320)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 国产福利社区一区二区| 亚洲欧美卡通另类丝袜美腿| 人人做人人澡人人人爽| 亚洲精品毛片一区二区| 国产精品爽爽va在线观看网站| 少妇人妻真实偷人精品| 凭祥市| 亚洲人成网站18禁止无码| 国产成人综合网亚洲第一| 久久久久久综合网天天| 久久精品国产亚洲av忘忧草18| 好紧好滑好湿好爽免费视频| 国产午夜福利视频在线| 精品无码国产日韩制服丝袜| 精品 日韩 国产 欧美 视频| 久久久久久久久久久久中文字幕| 高潮迭起av乳颜射后入| 欧美福利电影A在线播放| 亚洲熟妇久久精品| 亚洲国产午夜精品福利| 九色国产精品一区二区久久| 亚洲精品久久7777777国产| 晋江市| 国产av一区二区午夜福利| 亚洲日本精品一区二区| 精品一区二区三区波多野结衣 | 少妇人妻偷人偷人精品| 成年午夜免费韩国做受视频| 亚洲国产福利成人一区二区| 风流少妇bbwbbw69视频| 无码h黄肉动漫在线观看| 久久精品一本到99热免费| 一区二区三区av天堂| 2022最新国产在线不卡a| 日韩熟女乱综合一区二区| 女主播扒开屁股给粉丝看尿口| 女性高爱潮视频| 日韩精品一区二区三区中文无码| 亚洲最大成人免费av| 女厕偷窥一区二区三区| 伊人色综合九久久天天蜜桃|