中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

權重較高網(wǎng)站深圳百度推廣聯(lián)系方式

權重較高網(wǎng)站,深圳百度推廣聯(lián)系方式,合肥最好的網(wǎng)站建設公司排名,長沙網(wǎng)站推廣公司Root motion動畫可以將角色的根節(jié)點(通常是角色的骨盆或腳部)的運動直接應用到游戲對象上,從而實現(xiàn)角色的自然移動和旋轉,避免出現(xiàn)腳底打滑的現(xiàn)象。采用Root motion動畫的游戲對象,通常是重載了onAnimatorMove函數(shù)&…

Root motion動畫可以將角色的根節(jié)點(通常是角色的骨盆或腳部)的運動直接應用到游戲對象上,從而實現(xiàn)角色的自然移動和旋轉,避免出現(xiàn)腳底打滑的現(xiàn)象。采用Root motion動畫的游戲對象,通常是重載了onAnimatorMove函數(shù),在腳本中來設置動畫的速度,從而實現(xiàn)角色的移動。Unity的Navigation系統(tǒng)是一個用于實現(xiàn)游戲世界中的尋路和導航功能的組件。它允許游戲角色在復雜的游戲環(huán)境中自動找到從一點到另一點的最短路徑。如果我們對采用Root motion動畫的游戲對象應用Navigation,就會產(chǎn)生沖突,因為這兩個組件都會嘗試控制游戲對象的移動。有兩個解決方式:

一是讓動畫跟隨Navigation agent,通過獲取agent.velocity來設置root motion的速度,從而大致匹配Agent的移動到動畫的移動。這個方式最簡單,但是可能會出現(xiàn)腳底打滑的現(xiàn)象。

二是讓Agent跟隨動畫,關閉agent的updatePosition和updateRotation,通過計算agent的nextPosition和動畫根節(jié)點的rootPosition的插值來進行控制。這種方式比方式一要復雜,但是效果更好。以下將以一個游戲場景為例子,詳細介紹一下如何實現(xiàn)方式二。

游戲場景

在游戲中,對于NPC角色,當前設置了幾個狀態(tài),分別是漫游Wander,瞄準Aim以及追蹤Chase。NPC剛開始是漫游狀態(tài),在場景中自由地進行移動,這時是通過Root motion來驅動的。當NPC檢測到玩家時,會進入瞄準狀態(tài)。如果玩家進行躲避NPC,則NPC會進入追蹤狀態(tài),自動跑到上一次發(fā)現(xiàn)玩家的位置,這時NPC是由Navigation來驅動,實現(xiàn)自動尋路??梢妼τ贜PC是需要按照不同的場景來用Root motion或Navigation來驅動的。

Animator設置

建立一個名為Enemy的Animator,包含了兩個狀態(tài),分別是Aim和Move,設置如下:

添加兩個Trigger,分別為Aim和Walk,用于切換狀態(tài)。定義一個名為Speed的Float變量,用于控制Root motion的移動速度。

Move狀態(tài)是一個BlendTree,通過Speed來進行Idle,Walk,Run這三種動作的混合,改變Speed的值,可以看到人物動作的改變。

Unity Blendtree動畫

改變Speed的值,可以看到人物的動作的改變。

實現(xiàn)漫游狀態(tài)

現(xiàn)在給游戲對象增加一個名為EnemyAI的腳本文件,實現(xiàn)游戲對象在場景中漫游。代碼如下:

public class EnemyAI : MonoBehaviour
{[Header("Enemy eyeview")]public float eyeviewDistance = 500.0f;public float viewAngle = 120f;public float obstacleRange = 3.0f;[Header("Enemy Property")]public float enemyHeight = 1.8f;public float enemyWidth = 1.2f;public float rotateSpeed = 2.0f;public float maxDetectDistance = 10f;private float _walkSpeed = 1.5f;private float _runSpeed = 3.5f;private Animator _animator;private Transform _transform;private float _currentSpeed;private float _targetSpeed;private float _statusDuration = 1.0f;private bool _isStatusTimerEnds = true;private bool _isDetectTimerEnds = true;[Flags]private enum EnemyStatus {Aim,Shoot,Wander,Chase}private EnemyStatus _enemyStatus;void Start(){_animator = GetComponent<Animator>();_rb = GetComponent<Rigidbody>();_transform = transform;_enemyStatus = EnemyStatus.Wander;rayCastOffset = new Vector3(0f, enemyHeight - 0.6f, 0f);}void Update(){if (_enemyStatus == EnemyStatus.Wander) {Wander();} Detect();}private void OnAnimatorMove() {if (_currentSpeed != _targetSpeed) {if (Mathf.Abs(_currentSpeed - _targetSpeed) > 0.1) {_currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.5f);} else {_currentSpeed = _targetSpeed;} }_animator.SetFloat("Speed", _currentSpeed); Vector3 speed = new Vector3(_animator.velocity.x, _rb.velocity.y, _animator.velocity.z);_rb.velocity = speed;}void Wander() {if (_isStatusTimerEnds) {_targetSpeed = UnityEngine.Random.Range(0, 2) == 0 ? 0f : _walkSpeed;_statusDuration = UnityEngine.Random.Range(5f, 10f);_isStatusTimerEnds = false;StartCoroutine(StatusTimer());}}IEnumerator StatusTimer() {float timer = 0;while (timer < _statusDuration) {timer += Time.deltaTime;yield return null; }_isStatusTimerEnds = true;}IEnumerator DetectTimer() {float timer = 0;while (timer < _detectDuration) {timer += Time.deltaTime;yield return null; }_isDetectTimerEnds = true;}float DetectObstacle(float angle) {RaycastHit hit;int layerMask = ~(1 << 8);Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.up);bool hitDetect = Physics.BoxCast(_transform.position + rayCastOffset, new Vector3(enemyWidth/2, rayCastOffset.y/2, 0.2f), rotation * _transform.forward, out hit,transform.rotation * rotation,maxDetectDistance,layerMask);if (hitDetect) {return hit.distance;} else {return 9999.0f;}}void Detect() {if (_isDetectTimerEnds) {_isDetectTimerEnds = false;StartCoroutine(DetectTimer());if (_currentSpeed > 0.2) {float distance = DetectObstacle(0f);if (distance < obstacleRange) {float leftDistance = DetectObstacle(-90f);float rightDistance = DetectObstacle(90f);float startAngle = -45f;float endAngle = -110f;if (rightDistance < obstacleRange && leftDistance < obstacleRange) {startAngle = 180f;endAngle = 180.01f;} else {if (leftDistance < rightDistance) {startAngle *= -1f;endAngle *= -1f;} }_targetAngle = UnityEngine.Random.Range(startAngle, endAngle);_currentAngle = 0f;}}} else {if (Mathf.Abs(_currentAngle - _targetAngle) > 0.1) {_prevAngle = _currentAngle;_currentAngle = Mathf.Lerp(_currentAngle, _targetAngle, rotateSpeed * Time.deltaTime);_transform.Rotate(0, _currentAngle - _prevAngle, 0);} else {_currentAngle = _targetAngle;}}}
}

以上代碼大致邏輯是一開始設置狀態(tài)為漫游狀態(tài),然后通過一個StatusTimer來計時,每次計時器到時就隨機設置一個速度值。在onAnimatorMove函數(shù)中通過插值的方法來平滑改變速度值,并設置Animator的speed值,實現(xiàn)通過root motion動畫來驅動游戲對象。另外還設置一個DetectTimer來計時,定期調(diào)用DetectObstacle函數(shù)來檢測游戲對象行進方向上是否有障礙物,如有則進行隨機轉向。運行場景,可以看到游戲對象在場景中可以自由地進行漫步。

實現(xiàn)瞄準狀態(tài)

現(xiàn)在我們要增加一個檢測玩家的功能,讓游戲對象在漫步過程中能發(fā)現(xiàn)玩家,并且進入瞄準狀態(tài)。對以上代碼做改動

public class EnemyAI : MonoBehaviour
{...void Update(){if (_enemyStatus == EnemyStatus.Aim) {_prevAngle = _currentAngle;_currentAngle = Mathf.Lerp(_currentAngle, _targetAngle, rotateSpeed * Time.deltaTime);_transform.Rotate(0, _currentAngle - _prevAngle, 0);if (Mathf.Abs(_currentAngle - _targetAngle) < 0.5) {_currentAngle = _targetAngle;}} ...}bool DetectPlayer() {bool findPlayer = false;Vector3 position = _transform.position + new Vector3(0f, enemyHeight-0.2f, 0f);_spottedPlayers = Physics.OverlapSphere(position, eyeviewDistance, LayerMask.GetMask("Character"));for (int i=0;i<_spottedPlayers.Length;i++) {Vector3 playerPosition = _spottedPlayers[i].transform.position;float angle = Vector3.SignedAngle(transform.forward, playerPosition - position, Vector3.up);if (angle <= viewAngle/2 && angle >= -viewAngle/2) {RaycastHit info;int layermask = LayerMask.GetMask("Character", "Default");Physics.Raycast(position, playerPosition - position, out info, eyeviewDistance, layermask);if (info.collider == _spottedPlayers[i]) {if (_currentSpeed >= 0.1) {_targetSpeed = 0f;_currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.75f);_animator.SetFloat("Speed", _currentSpeed);} else {_prevPlayerPosition = playerPosition;_foundPlayer = true;_enemyStatus = EnemyStatus.Aim;_animator.SetTrigger("Aim");_currentAngle = 0;_targetAngle = angle;_currentSpeed = 0f;findPlayer = true;}}}}return findPlayer;} void Detect() {if (_isDetectTimerEnds) {...DetectPlayer()}...}
}

在原來的Detect代碼中增加一個對檢測玩家的DetectPlayer的調(diào)用,當檢測到玩家時,設置狀態(tài)為Aim,并且設置Animator的Aim觸發(fā)器,播放瞄準動作。

實現(xiàn)追蹤狀態(tài)

當游戲對象檢測到玩家之后,玩家可以躲避游戲對象的瞄準,例如跑到一旁的障礙物隱藏。游戲對象找不到玩家,這時應該跑去之前發(fā)現(xiàn)玩家的地方,進行搜索。要實現(xiàn)這個功能,簡單的一個想法是通過Unity的Navigation自動尋路功能來實現(xiàn),讓游戲對象自行尋路,而不是通過代碼來控制。但是如前面提到的,Navigation和Root motion同時驅動游戲對象就會產(chǎn)生沖突,因此我們可以采取方式二來解決,即讓Navigation agent跟隨動畫來移動。

給游戲對象增加一個Navmesh agent組件,然后對代碼進行如下改動:

public class EnemyAI : MonoBehaviour
{...private NavMeshAgent _agent;Vector2 smoothDeltaPosition = Vector2.zero;Vector2 velocity = Vector2.zero;void Start(){..._agent = GetComponent<NavMeshAgent>();_agent.updatePosition = false;_agent.speed = _runSpeed;}void Update(){...if (_enemyStatus == EnemyStatus.Chase) {Vector3 worldDeltaPosition = _agent.nextPosition - _transform.position;// Map 'worldDeltaPosition' to local spacefloat dx = Vector3.Dot(_transform.right, worldDeltaPosition);float dy = Vector3.Dot(_transform.forward, worldDeltaPosition);Vector2 deltaPosition = new Vector2(dx, dy);// Low-pass filter the deltaMovefloat smooth = Mathf.Min(1.0f, Time.deltaTime/0.15f);smoothDeltaPosition = Vector2.Lerp (smoothDeltaPosition, deltaPosition, smooth);// Update velocity if time advancesif (Time.deltaTime > 1e-5f)velocity = smoothDeltaPosition / Time.deltaTime;//Debug.LogFormat("Chase, speed:{0}", velocity.magnitude);_animator.SetFloat("Speed", velocity.magnitude); _transform.LookAt(_agent.steeringTarget + transform.forward);if (_agent.remainingDistance < _agent.radius) {_enemyStatus = EnemyStatus.Wander;}}Detect()}private void OnAnimatorMove() {if (_enemyStatus == EnemyStatus.Chase) {_transform.position = _agent.nextPosition;}else {if (_currentSpeed != _targetSpeed) {if (Mathf.Abs(_currentSpeed - _targetSpeed) > 0.1) {_currentSpeed = Mathf.Lerp(_currentSpeed, _targetSpeed, 0.5f);} else {_currentSpeed = _targetSpeed;} }_animator.SetFloat("Speed", _currentSpeed); Vector3 speed = new Vector3(_animator.velocity.x, _rb.velocity.y, _animator.velocity.z);_rb.velocity = speed;}}void Detect() {if (_isDetectTimerEnds) {...//DetectPlayer();if (!DetectPlayer()) {if (_foundPlayer) {_foundPlayer = false;_agent.nextPosition = _transform.position;_agent.destination = _prevPlayerPosition;_enemyStatus = EnemyStatus.Chase;_animator.SetTrigger("Walk");_targetSpeed = _runSpeed;}} ...}
}

以上的代碼值得詳細講解一下,在Start函數(shù)中,設置了agent的updatePosition為false,即不讓agent來移動游戲對象,同時設置agent的最大速度不要超過runspeed。在Update函數(shù)中,判斷如果當前是Chase狀態(tài),那么計算agent的nextPosition與當前位置的差值,然后計算在deltaTime時間間隔中,需要以什么速度來移動,并設置animator的speed,使得游戲對象的動作與移動速度保持同步,不會出現(xiàn)腳底打滑的現(xiàn)象。在onAnimatorMove函數(shù)中,通過設置transform的位置為agent的nextPosition來實現(xiàn)移動。在Detect函數(shù)中進行修改,如果之前發(fā)現(xiàn)玩家,但現(xiàn)在沒有發(fā)現(xiàn),則進入Chase狀態(tài), 把之前發(fā)現(xiàn)玩家的位置設置為agent的目的地,讓agent來進行自動尋路。注意在進入Chase狀態(tài)時需要更新一下agent的nextPosition為當前游戲對象的位置,因為我們之前設置了updatePostion為false,所以agent的當前位置并不同步。

實現(xiàn)效果

Root Motion動畫與Navigation結合

FPS教程

另外我之前也寫了一系列文章介紹如何實現(xiàn)FPS游戲,有興趣的可以了解一下

Unity開發(fā)一個FPS游戲_unity 模仿開發(fā)fps 游戲-CSDN博客

Unity開發(fā)一個FPS游戲之二_unity 模仿開發(fā)fps 游戲-CSDN博客

Unity開發(fā)一個FPS游戲之三-CSDN博客

Unity開發(fā)一個FPS游戲之四_unity fps-CSDN博客

Unity開發(fā)一個FPS游戲之五-CSDN博客

http://www.risenshineclean.com/news/36133.html

相關文章:

  • 專注大連網(wǎng)站建設百度推廣登錄手機版
  • asp.net 網(wǎng)站訪問量商品推廣與營銷的方式
  • 京東商城網(wǎng)站設計酒店如何進行網(wǎng)絡營銷
  • 畫冊制作揭陽seo推廣公司
  • 永嘉網(wǎng)站建設幾熱門關鍵詞
  • 山東美建站金華百度推廣公司
  • 開發(fā)一個視頻網(wǎng)站要多少錢360優(yōu)化大師app下載
  • 南城區(qū)網(wǎng)站仿做網(wǎng)絡營銷推廣與策劃
  • 05網(wǎng)亮點給力大試卷網(wǎng)站seo博客
  • 贛州信息港贛州熱線湖南seo網(wǎng)站多少錢
  • 我的世界做神器指令網(wǎng)站網(wǎng)絡平臺建站
  • 網(wǎng)站開發(fā)難學嗎今天的新聞 聯(lián)播最新消息
  • 用vs2010做的網(wǎng)站網(wǎng)頁設計模板圖片
  • 陽信做網(wǎng)站營銷型網(wǎng)站建設費用
  • 昆明做網(wǎng)站的個人淘寶seo搜索引擎原理
  • 南陽做網(wǎng)站百度搜索引擎排名規(guī)則
  • 公司網(wǎng)站開發(fā)交接注意事項seo研究中心怎么了
  • 做網(wǎng)站網(wǎng)絡seo優(yōu)化教程自學
  • wordpress 獲取根目錄上海seo網(wǎng)站推廣公司
  • 靜態(tài)網(wǎng)站開發(fā)預期效果關鍵詞生成器 在線
  • 南京做代賬會計在哪個網(wǎng)站上找百度快照在哪里找
  • 深圳品牌做網(wǎng)站公司今日國內(nèi)新聞10則
  • 做爰網(wǎng)站貼吧推銷產(chǎn)品的軟文500字
  • 平面設計在線課程文明seo技術教程網(wǎng)
  • 上海專建貿(mào)易有限公司廊坊百度關鍵詞優(yōu)化
  • 注冊微信號的網(wǎng)站網(wǎng)站設計模板網(wǎng)站
  • 切實加強政府網(wǎng)站建設與管理百度競價排名事件分析
  • 深圳網(wǎng)站品牌建設seo關鍵詞排名優(yōu)化
  • 大連網(wǎng)站建設設計下載百度到桌面上
  • 深圳網(wǎng)站做的好的公司名稱長春網(wǎng)站建設技術托管