Unity-FSM有限状态机
Unity-FSM有限状态机什么是有限状态机? 在编写一些需要判断多个条件的程序时,我们常常会用到 if-else 语句,这样能够很好的帮我们解决多数问题。但在游戏开发过程中,一个角色的行为不是一成不变的,需要实时的进行修改,此时如果我们使用的是 if-else 来判断角色所处状态,就需要修改整个代码体,十分麻烦。而有限状态机很好的解决了这一些问题。
有限状态机实现的方式是,将判断条件、角色状态、状态机分别封装成一个类,这样当我们需要增加或者减少角色的状态时,直接将对应的状态与相对应的条件删除即可,不会影响到所有的代码,极大的减少了开发时间。
下面将介绍有限状态机该如何编写。
有限状态机简单实现 一般的状态机代码,会先有一个抽象的状态父类,其中包含两个抽象函数,一个是需要在进入状态的一开始就执行,一个是需要在程序执行的时候每一帧都执行,并由子类继承这个抽象父类,实现对应的两个函数。切换条件需要写在每一帧都调用的函数中。
状态类:
1234567891011121314151617181920212223242526272829public abs ...
Unity-敌人(Enemy)
Unity-敌人(Enemy)引言 敌人是每个游戏中不可缺少的部分,设计得好的敌人可以给游戏增添很多乐趣,设计得差的则会非常影响我们的游戏体验。
经过这段时间的学习,我们已经接触了非常多的敌人代码的写法,但是就是没有系统的归类,导致每次写敌人,都要从头开始。现在是时候将他们进行一个系统性的整理了。
逻辑思考基本框架 我们首先来想一想,敌人需要执行什么操作,方便我们进行后面的构思。
首先,我们的敌人需要移动、攻击、受伤这些基本的操作,有些敌人还会跳跃。
为了实现敌人的移动,我们可能需要两个固定的目标点、一个发现目标时 记录目标的点,还可能需要 转向 的函数,还有 切换目标 的函数,以实现我们 巡逻移动、或朝向目标移动的目的。
为了实现敌人的攻击,我们需要 动画器组件,播放对应的攻击动画,同时还需要一些 参数,记录敌人自己的 攻击距离、攻击速度。因为我们使用了状态机,所以只需要写好攻击函数,使敌人进入攻击状态后每帧调用攻击函数就可以了。
为了实现敌人的受伤,我们需要创建一个 接口,里面包含一个抽象的受伤(GetHit)函数, ...
Unity-射线
Unity-射线前言 在游戏开发的过程中,许多功能的实现都需要物理检测,而 发射射线 是Unity中物理检测的通用方法。例如,我们需要检测玩家(Player)脚下是否是 地面(图层为 Ground),只需要从脚底发射一条射线,检测Player脚下GameObject的图层是否为Ground即可。
射线和物理检测何其重要,因此使用单独一篇笔记进行记录,防止自己忘记。
射线 在Unity2D中,发射一条射线需要用到 Physics2D.Raycast 函数,它将返回一个RaycastHit2D 变量,因此射线写法如下:
123RaycastHit2D (变量名) = Physics2D.Raycast(起始位置, 方向, 距离, 图层);if((变量名)) //该变量为bool变量,可用于判断 {.......}
上述代码的意思是,再 指定位置 朝向 指定方向 创建一个 指定长度 的射线,当射线碰撞到 指定图层 时,返回 true。
让我们举一个实际的例子,来看看代码是如何运作的。
123456...public flo ...
Unity-协程
Unity-协程协程的简单实现 一般的程序执行都是线性的,也就是必须一行一行的执行代码。
使用Unity提供的协程,就可以类似于开辟另一条线程,调整根据你所写的代码,调整下一行代码执行的时间。
项目示例 下面的例子是一个 U3D Demo 中的代码,实现最简单的 Enemy 追击 Player 的功能。
1234567891011121314151617181920IEnumerator MoveToAttackTarget(){ agent.isStopped = false; // agent is NavMeshComponent transform.LookAt(attackTarget.transform); while(Vector3.Distance(attackTarget.transform.position,transform.position)>2) { agent.destination = attackTarget.transform.position; //Move t ...
Lambda表达式和匿名函数
C#-Lambda表达式和匿名函数表达式lambda表达式位于 => 运算符右侧的 lambda 表达式称为“表达式 lambda”。 表达式 lambda 会返回表达式的结果,并采用以下基本形式:
1(input-parameters) => expression
举个例子,我想写一个可计算参数平方值的委托,那么使用 lambda 表达式实现如下。
1234Func<int, int> func = x => x * x;Console.WriteLine(func(4));// Output:// 8
可以发现func中只有一个语句,如果需要更多语句,可以使用到 语句lambda。
语句lambada语句 lambda 与表达式 lambda 类似,只是语句括在大括号中:
1(input-parameters) => { <sequence-of-statements> }
语句 lambda 的主体可以包含任意数量的语句;但是,实际上通常不会多于两个或三个。
12345678Action<string> ...
Unity-观察者模式(observer)
Unity-观察者模式(observer)引言 了解完委托(delegate)与事件(event)之后,我们来讨论一个问题。
假设我们有一个热水器,我们给他同上电,当水温超过95度的时候:1、扬声器会开始发出语音,告诉你温度;2、液晶屏也会改变水温的显示,来提示水已经烧开了
现在我们需要写一个程序来模拟这个烧水的过程,我们将定义一个类来代表热水器,我们管他叫:Heater,他有代表水温的字段,叫做temperature;当然还有必不可少的给水加热的方法MakeAlert(),一个显示水温的方法ShowMsg()。
123456789101112131415161718192021222324252627282930313233namespace Delegate { class Heater { private int temperature; // 水温 // 烧水 public void BoilWater() { for (int i = 0; i & ...
Unity-单例模式
Unity-单例模式前言 对于某些特殊的类,我们希望 在整个程序的生命周期只创建一个该类的对象 ,或是希望 在其他类没有持有该类的引用,就可以调用该类中的函数,我们就需要将这个类写成 单例模式
单例的简单实现1234567891011121314public class Test(){ pubic abstract Test Instance;//创建程序中该类的唯一一个对象 private void Awake()//在程序启动时,直接创建一个该类的对象 { if(Instance!=null)//如果已经创建了一个变量,便将该变量删除 { Destroy(gameObject); } Instance = this; }}
泛型单例为什么需要泛型单例 在通常的游戏制作中,我们会创建许多的 Manager 来管理我们的游戏,如果每创建一个 Manager 都要重新写一遍单例会非常麻烦,因此就需要 泛型单例。 ...
Unity-Light(含Unity2021-2d项目升级Urp渲染管线)
Unity-Light(含Unity2021-2d项目升级Urp渲染管线)普通渲染管线(比较老旧的光效升级方式,已舍弃) 要使场景和角色拥有光效,那就得让他们先暗下来,给他们添加相应的材质
场景材质的添加 选中需要添加材质的场景,在右侧框内的“材质”菜单中,选中Default-Diffuse材质
人物材质的添加 在任意文件夹创建一个材质,在shader菜单中选中Sprites下拉菜单中的Diffuse
场景光效的添加 可以直接在右侧菜单创建各种光源,光源既可以是固定的,又可以作为其他 GameObject 的子对象,跟随父对象移动。
通用渲染管线(Universal RP)前言 为了得到更好的光线效果,我们需要将Untiy的渲染管线升级到 Urp. Untiy2020 以前的的版本,网上的教程已经十分详尽,再次不过多赘述,有需要直接进行百度即可。这里重点讲的是 Unity2020 以上版本的升级步骤(在中文互联网上没有找到相关教程,于是在此记录我在其他渠道的学习经历)
组件的添加 在 PackageManager 中搜索 Universa ...