Unity3D学习笔记十七:IK动画、粒子系统和塔防

新动画系统: 反向动力学动画(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

 

原文地址:https://www.cnblogs.com/ciaowoo/p/10363313.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章将为大家详细讲解有关Unity3D中如何通过Animator动画状态机获取任意animation clip的准确播放持续时长,小编觉得挺实用的,因此分享给大家做个参考,
这篇文章主要介绍了Unity3D如何播放游戏视频,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解
这篇文章给大家分享的是有关Unity3D各平台路径是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、Resources路径 Reso...
小编给大家分享一下Unity3D如何实现移动平台上的角色阴影,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!由于目前主流使用Unity3.x在移动平...
如何解析基于Unity3D的平坦四叉树地形与Virtual Texture的分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希
这篇文章主要介绍Unity3D如何实现动态分辨率降低渲染开销,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!之前项目降低分辨率我们都普...
这篇文章主要介绍了unity3d中如何使用屏幕空间改善shadowmap漏光,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编...
这篇文章主要介绍unity3d如何实现基于屏幕空间的描边,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Outline(Based on Image Space)由...
这篇文章给大家分享的是有关unity3d中导入fbx时的Scale是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在Unity中点击GameOb...
这篇文章主要为大家展示了“unity3d中如何实现ttc转ttf及制作字体”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习
这篇文章主要介绍了unity3d中水彩风渲染有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了...
这篇文章将为大家详细讲解有关unity3d中图像压缩原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1 图像可压缩...
这篇文章给大家分享的是有关unity3d中光照公式有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。漫反射、高光、物理渲染(PBR...
小编给大家分享一下unity3d中光照探针的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我...
这篇文章将为大家详细讲解有关Unity3D中Rendering Paths及LightMode的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有
这篇文章将为大家详细讲解有关unity3d中图形学的光照原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。首先,在...
这篇文章给大家分享的是有关unity3d中图片渲染流程是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。相关名词GPU(Graphic Pr...
本篇我们来介绍一下左侧工具栏中基本绘制的应用。 一、墙体绘制直墙 & 矩形墙绘制墙体时,可以看到上方的工具栏中对墙体进行参数的设定。 弧形墙在建筑版的户...
xlua是由腾讯维护的一个开源项目,我们可以在github上下载这个开源项目并查看一些相关文档官网:https://github.com/Tencent/xLua配置文档:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md常见问题解答:https://github.com/Tencent/xLua/blob/master/Assets/
我们都知道,一个三维场景的画面的好坏,百分之四十取决于模型,百分之六十取决于贴图,可见贴图在画面中所占的重要性。在这里我将列举一些贴图,并且初步阐述其概念,理解原理的基础上制作贴图,也就顺手多了。我在这里主要列举几种UNITY3D中常用的贴图,与大家分享,希望对大家有帮助。01 首先