Unity3D學習筆記(十七):IK動畫、粒子系統和塔防
阿新 • • 發佈:2019-02-12
hpa 狀態 ram erl 代碼調整 tar 處理 rtu 需要 新動畫系統:
反向動力學動畫(IK功能):
魔獸世界(頭部動畫),神秘海域(手部動畫),人類一敗塗地(手部動畫)
如何啟用(調整)
1、必須是新動畫系統Animator
設置頭、手、肘的目標點
2、動畫類型必須是Humanoid,除此之外其他類型都不可以
3、動畫系統對應層級的IKPass必須開啟
4、相應的IK調整方法只能寫在OnAnimatorIK(腳本掛載和Animator同一級別)
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DefaultAvatarIK : MonoBehaviour {public Animator anim; public Transform lookPoint; public Transform HandPoint; public Transform ElbowPoint; // Use this for initialization void Start () { } // Update is called once per frame void Update () { } privatevoid OnAnimatorIK(int layerIndex) { //用代碼調整頭部看向的方向 anim.SetLookAtPosition(lookPoint.position); //調整IK動畫的權重 //如果是1代表完全按代碼邏輯播放動畫(完全融合) //如果是0完全按原動畫播放 anim.SetLookAtWeight(1); //調整四肢IK的目標點 anim.SetIKPosition(AvatarIKGoal.LeftHand, HandPoint.position);//AvatarIKGoal是枚舉 anim.SetIKPositionWeight(AvatarIKGoal.LeftHand, 1); //調整四肢IK關節的目標點 anim.SetIKHintPosition(AvatarIKHint.RightElbow, ElbowPoint.position); anim.SetIKHintPositionWeight(AvatarIKHint.RightElbow, 1); //調整四肢IK的朝向 //anim.SetIKRotation(); } }
取消物體描邊
粒子系統: Particle System一統江湖,主流離子發射器思想,調整發射器參數發射離子,如AE Legacy都是老的粒子系統一個粒子效果由若幹個Particle System構成
修改大小 我們沒有辦法通過GameObject的Scale改大小,Scale只是改變發射區域的大小 可以通過StartSize可以通過SizeOverLife曲線
啟用碰撞 碰撞系統,火焰濺射效果 打開粒子的Collision功能,選擇Type為World,平面改3D也可以選擇Type為Planes,設置一個平面觸發效果
拖尾效果
腳本使用:播放,停止,銷毀
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ParticleTest : MonoBehaviour { public ParticleSystem ps; // Use this for initialization void Start () { } // Update is called once per frame void Update () { if (Input.GetKeyDown(KeyCode.Alpha1)) { //調用粒子系統播放 ps.Play(); } if (Input.GetKeyDown(KeyCode.Alpha2)) { //調用粒子系統停止 ps.Stop(); } if (Input.GetKeyDown(KeyCode.Alpha3)) { if (ps.isStopped) { //失活粒子 gameObject.SetActive(false); } } } }
重載,連同子級一起處理,填flase只負責自身
取消喚醒,改為代碼播放
塔防遊戲: 怪物管理器: 添加路點(路點放在拐點處),給怪物子類添加路點列表 currentPathNodeID:記錄當前路點的變量 pathNodeList.Count-1:路點的最後一個點 移動邏輯 數組越界問題:調整currentPathNodeID++的位置到最後using System.Collections; using System.Collections.Generic; using UnityEngine; public class MonsterA : MonsterBase { public Animator anim; public Transform pathParent; public List<Transform> pathNodeList; public int currentPathNodeID; public float speed; // Use this for initialization void Start () { anim = GetComponent<Animator>(); //初始化路點列表 pathNodeList = new List<Transform>(); //把路點導入到路點列表 for (int i = 0; i < pathParent.childCount; i++) { pathNodeList.Add(pathParent.GetChild(i)); } //把自己放在路點的第一個位置 transform.position = pathNodeList[0].position; currentPathNodeID = 0; monsterSta = MonsterSta.Move; anim.SetBool("isMove", true); } // Update is called once per frame void Update () { #region 動畫測試 //if (Input.GetKeyDown(KeyCode.Alpha1)) //{ // monsterSta = MonsterSta.Move; // anim.SetBool("isMove", true); //} //if (Input.GetKeyDown(KeyCode.Alpha2)) //{ // monsterSta = MonsterSta.Idle; // anim.SetBool("isMove", false); //} //if (Input.GetKeyDown(KeyCode.Alpha3)) //{ // monsterSta = MonsterSta.Death; // anim.SetTrigger("Death"); //} #endregion Action(); } public override void Action() { switch (monsterSta) { case MonsterSta.Idle: Idle(); break; case MonsterSta.Move: Move(); break; case MonsterSta.Death: Death(); break; default: break; } } public override void Move() { //如果怪物還沒有到達路點中最後一個點 if (currentPathNodeID < pathNodeList.Count-1) { //向下一個點前進 float distance = Vector3.Distance(transform.position, pathNodeList[currentPathNodeID + 1].position); transform.position = Vector3.Lerp(transform.position, pathNodeList[currentPathNodeID + 1].position, speed/ distance*Time.deltaTime); //如果我離下一個點的距離到達某一個值 Quaternion targetRot = Quaternion.LookRotation(pathNodeList[currentPathNodeID + 1].position - pathNodeList[currentPathNodeID].position); transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, 0.1f); //transform.LookAt(pathNodeList[currentPathNodeID + 1]); if (distance < speed * Time.deltaTime) { //改變我的當前點,進而改變目標點,成下一個點 currentPathNodeID++; } } } }
保留原動畫狀態機的邏輯,可以替換原動畫片段
機槍塔,需要瞄準,攻擊速快 炮塔,不用瞄準,攻速慢 塔基 外層(空物體):縮放(1,1,1) 內層(Tower_Base):縮放(0.4,0.4,0.4) 外層添加剛體內層添加球形碰撞體,勾選Is Trigger
塔基父類代碼邏輯
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GunBase : MonoBehaviour { public float attackRange; public MonsterBase tragetMonster; public SphereCollider attackTrigger; // Use this for initialization void Start () { } // Update is called once per frame void Update () { } public virtual void Indit() { attackTrigger.radius = attackRange; } public virtual void Attack() { } }
塔基子類代碼邏輯
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GunB : GunBase { public Transform gunPos; public ParticleSystem ps; // Use this for initialization void Start () { Indit(); } // Update is called once per frame void Update () { Attack(); fireCDTime += Time.deltaTime; } public override void Attack() { if (tragetMonster!=null) { if (AttackCheck()) { if (fireCDTime> fireCD) { Fire(); } } else { RotatGun(); } } else { ps.Stop(); } } public void RotatGun() { Vector3 dir = tragetMonster.transform.position - gunPos.position; dir.y = 0; Quaternion targetRot = Quaternion.LookRotation(dir); gunPos.rotation = Quaternion.Slerp(gunPos.rotation, targetRot, 0.5f); } float fireCD = 0.1f; float fireCDTime; public void Fire() { fireCDTime = 0; tragetMonster.Damage(); ps.Play();//特效代碼邏輯 } public bool AttackCheck() { Vector3 monsterDir = tragetMonster.transform.position - gunPos.position; monsterDir.y = 0; if (Vector3.Angle(gunPos.forward, monsterDir)<5) { return true; } return false; } //如果有物體進入我的攻擊範圍 private void OnTriggerEnter(Collider other) { //如果我沒有目標 if (tragetMonster==null) { //如果進入我攻擊範圍的Collider標簽是"Monster" if (other.tag == "Monster") { //把這個Monster設置成我的目標 tragetMonster = other.GetComponent<MonsterBase>(); } } } //如果有物體離開我的攻擊範圍 private void OnTriggerExit(Collider other) { //如果我有目標 if (tragetMonster != null) { //如果離開的目標是我的目標 if (tragetMonster == other.GetComponent<MonsterBase>()) { //我的目標為空 tragetMonster = null; } } } }
設置攻擊範圍
塔基父類代碼邏輯:設置Indit初始化,給碰撞器添加攻擊範圍
public virtual void Indit() { attackTrigger.radius = attackRange; }攻擊檢測:炮塔轉向 球形差值,正負轉向 線性差值,只能正向
public override void Attack() { if (tragetMonster!=null) { if (AttackCheck()) { if (fireCDTime> fireCD) { Fire(); } } else { RotatGun(); } } else { ps.Stop(); } } public void RotatGun() { Vector3 dir = tragetMonster.transform.position - gunPos.position; dir.y = 0; Quaternion targetRot = Quaternion.LookRotation(dir); gunPos.rotation = Quaternion.Slerp(gunPos.rotation, targetRot, 0.5f); }目標點不對的問題: dir.y = 0;轉向方法的y軸清零 monsterDir.y = 0;攻擊檢測的角度也要清零
public void RotatGun() { Vector3 dir = tragetMonster.transform.position - gunPos.position; dir.y = 0; Quaternion targetRot = Quaternion.LookRotation(dir); gunPos.rotation = Quaternion.Slerp(gunPos.rotation, targetRot, 0.5f); } float fireCD = 0.1f; float fireCDTime; public void Fire() { fireCDTime = 0; tragetMonster.Damage(); ps.Play();//特效代碼邏輯 } public bool AttackCheck() { Vector3 monsterDir = tragetMonster.transform.position - gunPos.position; monsterDir.y = 0; if (Vector3.Angle(gunPos.forward, monsterDir)<5) { return true; } re
Unity3D學習筆記(十七):IK動畫、粒子系統和塔防