动画生硬切换:animation.play();//极少使用,常用融合方法
动画融合淡入:animation.CrossFade(“Idle”, 0.2f);//0.2f为与前一动画的融合百分比为20%
枚举做状态机:
AI系统 - 寻路系统:
关键要素:
1、寻路元件
挂载寻路组件

2、寻路平面(地形)
地形设置成导航静态,进入预备役(以此为基准提取数据,可以修改删减,显示数据)

打开Navigation窗口在Bake栏下点Bake

烘焙数据:蓝色区域就是寻路平面,烘焙数据可以与显示数据分离

设置障碍物:障碍物勾选Navigation Static,重新烘焙,障碍物被添加

设置目标点,引用UnityEngine.AI,引用寻路系统

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;//引用UnityEngine.AI
public enum EnemySta
{
Move,
Idle,
Death
}
public class EnemyControl : MonoBehaviour {
public Animation anim;
public EnemySta enemySta;
//因为我们需要经常用到目标的状态,所以把TransForm改成了PlayerControl
public PlayerControl moveTarget;//设置目标点
public NavMeshAgent navMeshAgent;//引用寻路系统
public MonsterManager manager;//怪物属于那个管理器
private int enemyHealth = ;//设置怪物生命值
// Use this for initialization
void Start () {
enemySta = EnemySta.Move;
} // Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Alpha1))
{
enemySta = EnemySta.Move;
}
if (Input.GetKeyDown(KeyCode.Alpha2))
{
enemySta = EnemySta.Idle;
}
if (Input.GetKeyDown(KeyCode.Alpha3))
{
enemySta = EnemySta.Death;
}
Action();
}
void Action()
{
switch (enemySta)
{
case EnemySta.Move:
Move();
break;
case EnemySta.Idle:
Idle();
break;
case EnemySta.Death:
Death();
break;
}
}
void Move()
{
anim.CrossFade("Move", 0.2f);
navMeshAgent.SetDestination(moveTarget.transform.position);//让对应组件调用一个SetDastination(目标点)方法
//如果怪物的目标死了
if (moveTarget.playSta == PlaySta.Death)
{
//寻路停止
navMeshAgent.isStopped = true;
//状态切换到闲置
enemySta = EnemySta.Idle;
}
}
void Idle()
{
anim.CrossFade("Idle", 0.2f);
}
public void Damage()
{
//受伤减血
enemyHealth -= ;
//Debug.Log("怪物生命"+enemyHealth);
//如果血到了0
if (enemyHealth <= )
{
//状态变成死亡状态
enemySta = EnemySta.Death;//怪物死亡:停止寻路,失效碰撞体(防止实体造成伤害)
navMeshAgent.isStopped = true;
gameObject.GetComponent<MeshCollider>().enabled = false;
//gameObject.tag = "Untagged";
}
}
void Death()
{
anim.CrossFade("Death", 0.2f);
}
public void DeathEvent()
{
//在管理器列表中移除自己
manager.monsterList.Remove(this);
//销毁自己
Destroy(this.gameObject);
}
}

Max Slope:坡度设置
Step Height:高度设置,低于高度可忽略

Speed:移动速度
Angular Speed:转向速度
Acceleration:启动速度,加速度
摄像机跟随
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public Transform target;//目标点
public Vector3 distance;//目标点的距离,和目标点保持一定距离
public Vector3 lookAtOffSet;//看向点与目标点的偏移量
private Vector3 targetPos;
// Use this for initialization
void Start () {
distance = transform.position - target.position;
} // Update is called once per frame
void Update () { }
private void LateUpdate()
{
//目标点加距离 = 摄像机的目标位置
targetPos = target.position + distance;
//向目标位置移动,每次百分之10
transform.position = Vector3.Lerp(transform.position, targetPos, 0.1F);
//看向目标点
transform.LookAt(target.position + lookAtOffSet);
}
}
lookAtOffSet:设置摄像机看向点的偏移量(点),避免人物总是在画面中央
射击功能:
核心功能(射线,碰撞,调用掉血方法)+交互功能(射线闪光特效,音效)
空物体Fire
----音效Audio
----动画
----射线
----粒子特效
--------子物体:Spotlight聚光灯,开闭,range变化

设置灯光动画

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum PlaySta
{
Move,
Idle,
Death
}
public class PlayerControl : MonoBehaviour
{
public Animation anim;
public PlaySta playSta;
// Use this for initialization
void Start()
{
playSta = PlaySta.Move;
}
// Update is called once per frame
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
moveDir.x = h;
moveDir.z = v;
cd += Time.deltaTime;
Action();
}
void Action()
{
switch (playSta)
{
case PlaySta.Move:
Move();
Attack();
Rot();
break;
case PlaySta.Idle:
Idle();
Attack();
Rot();
break;
case PlaySta.Death:
Death();
break;
}
}
Vector3 moveDir;
Vector3 lookPoint;
RaycastHit hit;
public float moveSpeed = ;
void Move()
{
anim.Play("Move");
transform.position += moveDir * moveSpeed * Time.deltaTime;
if (moveDir.magnitude < 0.01f)
{
playSta = PlaySta.Idle;
}
}
//把转向功能提炼出来
void Rot()
{
if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit, , << ))
{
lookPoint = hit.point;
lookPoint.y = transform.position.y;
transform.LookAt(lookPoint);
}
}
void Idle()
{
anim.Play("Idle");
if (moveDir.magnitude >= 0.01f)
{
playSta = PlaySta.Move;
}
}
float cd;
public void Damage()
{
cd = ;//无敌时间,受伤间隔
playSta = PlaySta.Death;
}
void Death()
{
anim.Play("Death");
}
//触发器判定死亡
//public void OnTriggerEnter(Collider other)
//{
// if (other.tag == "Monster")
// {
// if (cd > 0.5f)
// {
// Damage();
// }
// }
//}
//改良版:碰撞器判定死亡
public void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "Monster")
if (cd > 0.5f)
{
Damage();
}
}
public AudioSource fireAudio;
public Animation fireAnim;
public Transform firePos;
public LineRenderer lineRenderer;
private RaycastHit fireHit;
void Attack()
{
if (Input.GetMouseButtonDown())
{
fireAudio.Play();
fireAnim.Stop();//Stop避免前一动画未执行完,后一动画不会执行
fireAnim.Play();
if (Physics.Raycast(new Ray(firePos.position,firePos.forward),out fireHit,))
{
//如果我打中的目标是怪物
if (fireHit.collider.tag == "Monster")
{
//这个目标受伤
fireHit.collider.GetComponent<EnemyControl>().Damage();
}
SetFirePos(fireHit.point); }
else
{
SetFirePos(firePos.transform.position + firePos.forward * );
}
}
}
void SetFirePos(Vector3 hitPos)
{
lineRenderer.SetPosition(, firePos.position);
lineRenderer.SetPosition(, hitPos);
}
//还原射线到枪口位置
public void ReSetFirePos()
{
lineRenderer.SetPosition(, firePos.position);
lineRenderer.SetPosition(, firePos.position);
}
}

----射线

positions默认世界位置
Element 0:枪口位置
Element 1:目标点位置

Materials射线材质:LineRenderMaterial
width射线宽度:
SetPosition方法:0,1参数是element0,element1

射线关联:
枪口位置,绑定在骨骼的武器位上
如果没有,就放在正前方上0.15,0.3,0.7
重置射线:
设置在动画的第10帧,调用消失方法

新建脚本FireEvent,调用父级Player的脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FireEvent : MonoBehaviour {
public PlayerControl player;
// Use this for initialization
void Start () { } // Update is called once per frame
void Update () { }
public void Fire()
{
player.ReSetFirePos();
}
}

射线宽度调整:添加关键帧,调整曲线,效果先细后粗

怪物管理器;
添加空物体和脚本类,生成点

给怪物管理器添加预制体的引用
注意:对象在场景中和类在资源中的区别

怪物属于那个管理器

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MonsterManager : MonoBehaviour {
List<Transform> birthPoint;
public GameObject monsterPreGo;
public List<EnemyControl> monsterList;
public int MaxMonsterCount = ;//最大怪物数
public PlayerControl player;
// Use this for initialization
void Start () {
birthPoint = new List<Transform>();
monsterList = new List<EnemyControl>();
for (int i = ; i < transform.childCount; i++)
{
birthPoint.Add(transform.GetChild(i));
}
} // Update is called once per frame
void Update () {
}
private void FixedUpdate()
{
CheckMonster();
}
void CreateMonster()
{
//实例化一个怪物
GameObject go = Instantiate<GameObject>(monsterPreGo);
//怪物的位置设置任意出生点
go.transform.position = birthPoint[Random.Range(,birthPoint.Count)].position;
//取得怪物脚本
EnemyControl monster = go.GetComponent<EnemyControl>();
//把怪物放到管理器列表里
monsterList.Add(monster);
//指定怪物的目标
monster.moveTarget = player;
//指定怪物的管理者
monster.manager = this;
}
void CheckMonster()
{
if (monsterList.Count < MaxMonsterCount)
{
CreateMonster();
}
}
}
角色穿墙问题:
Drag=1防止被墙弹飞,XZ轴解锁

怪物死亡:移出列表,摧毁游戏物体,放在死亡动画最后一帧调用

public void DeathEvent()
{
//在管理器列表中移除自己
manager.monsterList.Remove(this);
//销毁自己
Destroy(this.gameObject);
}

更换场景,重新烘焙,并添加floor和碰撞体

怪物管理器添加积分系统

Unity3D学习笔记(十五):寻路系统的更多相关文章

  1. python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)

    python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...

  2. (转载)西门子PLC学习笔记十五-(数据块及数据访问方式)

    一.数据块 数据块是在S7 CPU的存储器中定义的,用户可以定义多了数据块,但是CPU对数据块数量及数据总量是有限制的. 数据块与临时数据不同,当逻辑块执行结束或数据块关闭,数据块中的数据是会保留住的 ...

  3. (C/C++学习笔记) 十五. 构造数据类型

    十五. 构造数据类型 ● 构造数据类型概念 Structured data types 构造数据类型 结构体(structure), 联合体/共用体 (union), 枚举类型(enumeration ...

  4. MySQL学习笔记十五:优化(2)

    一.数据库性能评测关键指标 1.IOPS:每秒处理的IO请求次数,这跟磁盘硬件相关,DBA不能左右,但推荐使用SSD. 2.QPS:每秒查询次数,可以使用show status或mysqladmin ...

  5. MYSQL进阶学习笔记十五:MySQL 的账号权限赋予!(视频序号:进阶_33,34)

    知识点十六:MySQL的账号权限赋予(33) 一.MySQL权限简介 关于mysql的权限简单的理解就是mysql允许你做你全力以内的事情,不可以越界.比如只允许你执行select操作,那么你就不能执 ...

  6. python 学习笔记十五 django基础

    Python的WEB框架有Django.Tornado.Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM.模型绑定.模板引擎.缓存.Session等诸多功能. ...

  7. Java基础学习笔记十五 集合、迭代器、泛型

    Collection 集合,集合是java中提供的一种容器,可以用来存储多个数据. 在前面的学习中,我们知道数据多了,可以使用数组存放或者使用ArrayList集合进行存放数据.那么,集合和数组既然都 ...

  8. Python3学习笔记十五

    ---恢复内容开始--- 1.  jquery的属性操作  $().attr(属性名)    取值 $().attr(属性名,属性值)      赋值 <!DOCTYPE html> &l ...

  9. angular学习笔记(十五)-module里的'服务'

    本篇介绍angular中的模块:module 在笔记(二)http://www.cnblogs.com/liulangmao/p/3711047.html里已经讲到过模块,这篇主要讲模块的 '服务' ...

  10. Java学习笔记十五:Java中的成员变量和局部变量

    Java中的成员变量和局部变量 一:成员变量: 成员变量在类中定义,用来描述对象将要有什么 成员变量可以被本类的方法使用,也可以被其他类的方法使用,成员变量的作用域在整个类内部都是可见的 二:局部变量 ...

随机推荐

  1. nginx 11个处理阶段 && nginx lua 8个处理阶段

    1. nginx 11 个处理阶段 nginx实际把请求处理流程划分为了11个阶段,这样划分的原因是将请求的执行逻辑细分,各阶段按照处理时机定义了清晰的执行语义,开发者可以很容易分辨自己需要开发的模块 ...

  2. Spark与Spring集成做web接口

    需要实现的功能: 写访问spark的接口,也就是从web上输入网址就能把我们需要的信息通过提交一个job然后返回给我们json数据. 成果展示: 通过url请求,然后的到一个wordcount的jso ...

  3. 实习培训——Java基础(2)

    实习培训——Java基础(2) 1  Java 变量类型 在Java语言中,所有的变量在使用前必须声明.声明变量的基本格式如下: type identifier [ = value][, identi ...

  4. Linux中Readlink命令

    原文地址:http://blog.csdn.net/liangxiaozhang/article/details/7356829 readlink是Linux系统中一个常用工具,主要用来找出符号链接所 ...

  5. logstash采集tomcat日志、mysql错误日志

    input{ file { path => "/opt/Tomcat7.0.28/logs/*.txt" start_position => "beginni ...

  6. Centos上执行Shell的四种方式

    注意:我这里说的shell脚本是Bash Shell,其他类型的shell脚本不保证有效 1,方式一:进入shell文件所在目录 ./my.sh执行 ./my.sh ./的意思是说在当前的工作目录下执 ...

  7. 谷歌浏览器:audio如何隐藏下载按钮

    当我们使用原生的audio标签时,可以看到如下的效果. 那么如何让下载按钮隐藏掉呢? 1. controlsList="nodownload" // 这个方法只支持 Chrome ...

  8. pyrhon3与mysql:查、更、删49

    import pymysql conn = pymysql.connect(host=',db='jodb1',port=3307,charset='utf8') # 172.31.10.225 # ...

  9. R语言学习笔记:基础知识

    1.数据分析金字塔 2.[文件]-[改变工作目录] 3.[程序包]-[设定CRAN镜像] [程序包]-[安装程序包] 4.向量 c() 例:x=c(2,5,8,3,5,9) 例:x=c(1:100) ...

  10. servlet07

    1.session验证 可以防止非登录的用户,通过在地址栏中输入地址,访问受保护的页面 step1.在用户登录成功之后,将用户的信息保存到session中 step2.在访问受保护的页面时,校验ses ...