1. 程式人生 > >Unity3D學習筆記(十七):IK動畫、粒子系統和塔防

Unity3D學習筆記(十七):IK動畫、粒子系統和塔防

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 () { } private
void 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動畫、粒子系統和塔防