国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

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

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

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

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

二是讓Agent跟隨動(dòng)畫(huà),關(guān)閉agent的updatePosition和updateRotation,通過(guò)計(jì)算agent的nextPosition和動(dòng)畫(huà)根節(jié)點(diǎn)的rootPosition的插值來(lái)進(jìn)行控制。這種方式比方式一要復(fù)雜,但是效果更好。以下將以一個(gè)游戲場(chǎng)景為例子,詳細(xì)介紹一下如何實(shí)現(xiàn)方式二。

游戲場(chǎng)景

在游戲中,對(duì)于NPC角色,當(dāng)前設(shè)置了幾個(gè)狀態(tài),分別是漫游Wander,瞄準(zhǔn)Aim以及追蹤C(jī)hase。NPC剛開(kāi)始是漫游狀態(tài),在場(chǎng)景中自由地進(jìn)行移動(dòng),這時(shí)是通過(guò)Root motion來(lái)驅(qū)動(dòng)的。當(dāng)NPC檢測(cè)到玩家時(shí),會(huì)進(jìn)入瞄準(zhǔn)狀態(tài)。如果玩家進(jìn)行躲避NPC,則NPC會(huì)進(jìn)入追蹤狀態(tài),自動(dòng)跑到上一次發(fā)現(xiàn)玩家的位置,這時(shí)NPC是由Navigation來(lái)驅(qū)動(dòng),實(shí)現(xiàn)自動(dòng)尋路??梢?jiàn)對(duì)于NPC是需要按照不同的場(chǎng)景來(lái)用Root motion或Navigation來(lái)驅(qū)動(dòng)的。

Animator設(shè)置

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

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

Move狀態(tài)是一個(gè)BlendTree,通過(guò)Speed來(lái)進(jìn)行Idle,Walk,Run這三種動(dòng)作的混合,改變Speed的值,可以看到人物動(dòng)作的改變。

Unity Blendtree動(dòng)畫(huà)

改變Speed的值,可以看到人物的動(dòng)作的改變。

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

現(xiàn)在給游戲?qū)ο笤黾右粋€(gè)名為EnemyAI的腳本文件,實(shí)現(xiàn)游戲?qū)ο笤趫?chǎng)景中漫游。代碼如下:

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;}}}
}

以上代碼大致邏輯是一開(kāi)始設(shè)置狀態(tài)為漫游狀態(tài),然后通過(guò)一個(gè)StatusTimer來(lái)計(jì)時(shí),每次計(jì)時(shí)器到時(shí)就隨機(jī)設(shè)置一個(gè)速度值。在onAnimatorMove函數(shù)中通過(guò)插值的方法來(lái)平滑改變速度值,并設(shè)置Animator的speed值,實(shí)現(xiàn)通過(guò)root motion動(dòng)畫(huà)來(lái)驅(qū)動(dòng)游戲?qū)ο?。另外還設(shè)置一個(gè)DetectTimer來(lái)計(jì)時(shí),定期調(diào)用DetectObstacle函數(shù)來(lái)檢測(cè)游戲?qū)ο笮羞M(jìn)方向上是否有障礙物,如有則進(jìn)行隨機(jī)轉(zhuǎn)向。運(yùn)行場(chǎng)景,可以看到游戲?qū)ο笤趫?chǎng)景中可以自由地進(jìn)行漫步。

實(shí)現(xiàn)瞄準(zhǔn)狀態(tài)

現(xiàn)在我們要增加一個(gè)檢測(cè)玩家的功能,讓游戲?qū)ο笤诼竭^(guò)程中能發(fā)現(xiàn)玩家,并且進(jìn)入瞄準(zhǔn)狀態(tài)。對(duì)以上代碼做改動(dòng)

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()}...}
}

在原來(lái)的Detect代碼中增加一個(gè)對(duì)檢測(cè)玩家的DetectPlayer的調(diào)用,當(dāng)檢測(cè)到玩家時(shí),設(shè)置狀態(tài)為Aim,并且設(shè)置Animator的Aim觸發(fā)器,播放瞄準(zhǔn)動(dòng)作。

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

當(dāng)游戲?qū)ο髾z測(cè)到玩家之后,玩家可以躲避游戲?qū)ο蟮拿闇?zhǔn),例如跑到一旁的障礙物隱藏。游戲?qū)ο笳也坏酵婕?#xff0c;這時(shí)應(yīng)該跑去之前發(fā)現(xiàn)玩家的地方,進(jìn)行搜索。要實(shí)現(xiàn)這個(gè)功能,簡(jiǎn)單的一個(gè)想法是通過(guò)Unity的Navigation自動(dòng)尋路功能來(lái)實(shí)現(xiàn),讓游戲?qū)ο笞孕袑ぢ?#xff0c;而不是通過(guò)代碼來(lái)控制。但是如前面提到的,Navigation和Root motion同時(shí)驅(qū)動(dòng)游戲?qū)ο缶蜁?huì)產(chǎn)生沖突,因此我們可以采取方式二來(lái)解決,即讓Navigation agent跟隨動(dòng)畫(huà)來(lái)移動(dòng)。

給游戲?qū)ο笤黾右粋€(gè)Navmesh agent組件,然后對(duì)代碼進(jìn)行如下改動(dòng):

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;}} ...}
}

以上的代碼值得詳細(xì)講解一下,在Start函數(shù)中,設(shè)置了agent的updatePosition為false,即不讓agent來(lái)移動(dòng)游戲?qū)ο?#xff0c;同時(shí)設(shè)置agent的最大速度不要超過(guò)runspeed。在Update函數(shù)中,判斷如果當(dāng)前是Chase狀態(tài),那么計(jì)算agent的nextPosition與當(dāng)前位置的差值,然后計(jì)算在deltaTime時(shí)間間隔中,需要以什么速度來(lái)移動(dòng),并設(shè)置animator的speed,使得游戲?qū)ο蟮膭?dòng)作與移動(dòng)速度保持同步,不會(huì)出現(xiàn)腳底打滑的現(xiàn)象。在onAnimatorMove函數(shù)中,通過(guò)設(shè)置transform的位置為agent的nextPosition來(lái)實(shí)現(xiàn)移動(dòng)。在Detect函數(shù)中進(jìn)行修改,如果之前發(fā)現(xiàn)玩家,但現(xiàn)在沒(méi)有發(fā)現(xiàn),則進(jìn)入Chase狀態(tài), 把之前發(fā)現(xiàn)玩家的位置設(shè)置為agent的目的地,讓agent來(lái)進(jìn)行自動(dòng)尋路。注意在進(jìn)入Chase狀態(tài)時(shí)需要更新一下agent的nextPosition為當(dāng)前游戲?qū)ο蟮奈恢?#xff0c;因?yàn)槲覀冎霸O(shè)置了updatePostion為false,所以agent的當(dāng)前位置并不同步。

實(shí)現(xiàn)效果

Root Motion動(dòng)畫(huà)與Navigation結(jié)合

FPS教程

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

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

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

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

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

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

http://m.aloenet.com.cn/news/36133.html

相關(guān)文章:

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