- 博客(53)
- 收藏
- 关注
原创 Games104——网络游戏的进阶架构
内插适用于玩家会突然瞬移加速的情况,相对比较稳定(FPS,MOBA)外插适用于整个运动符合物理学规律的情况,预测他的速度是比较准确的游戏内通常会都使用,人物使用内插,载具使用外插。
2025-02-02 23:12:13
1005
原创 Games104——网络游戏的架构基础
帧同步的特点是在客户端可以获取到局内所有的状态,游玩时使用插件就可以获取到这些状态,但现在的游戏会采取一些方法来规避这些问题。每一个玩家提供部分的信息,Server去模拟一个世界,只把与每个用户相同的信息发给他,防作弊的能力好于帧同步。服务器获取到所有客户端的输入,并将所有客户端的输入再发放给每个客户端,但最慢的用户会拖慢所有的进程。客户端把自己的输入发给服务器,服务器把整个游戏世界的状态生成一个快照,然后把快照发给所有的客户端。服务端和客户端之间的帧率不同,快照生成的算力消耗大,所以使用Delta。
2025-02-02 23:11:12
1278
原创 Games104——游戏引擎的Gameplay玩法系统基础
Event Type + Event Argument(配置)Event虽然可以使用基类去继承, 但如果不断加入新的事件类型和对应编辑性,则每次都需要重新编译(与上节课的代码反射相关),这时常见解决方法有:将新事件新编译成的C++代码当成 DLL,加入到系统中(UE)上层采用 C# 语言,方便动态挂接和扩展用脚本语言。
2025-02-01 20:17:04
847
原创 Games104——游戏引擎Gameplay玩法系统:高级AI
优点:HTN 和 BT 非常相似,但是是BT的高阶版本,但HTN更加灵活、符合人的直觉、也更易于设计师进行掌握;可以带着目的预测,任务计划也更长程缺点:由于用户行为不可预测,因此task很容易失败或满足不了precondition;并且world state与任务effect影响对设计师是挑战(比如忘记设置某个条件;或者如果 task 链路过长但是环境变化很快,那么 AI 的行为就会变化很快,看上去振动一样)
2025-02-01 19:55:30
747
原创 Games104——游戏引擎Gameplay玩法系统:基础AI
原理是通过计算一个代价函数:f = g(从原点已经走过的路程的代价,一般累计路程距离) + h(到终点还有多远的代价,一般用欧拉距离或x+y),来逐步寻找最优下一步的路径(按照网格或mesh的划分),原理有些类似梯度下降。从起始点看向下一个三角形,视野卡在三角形两端,如果能全部在视野中,就继续看下一个三角形,更新视野,直到某一个三角形被挡住一部分时,左边被挡沿左视野边走,右边被挡沿右视野边走;结合了宏观和微观方法,把群体分为很多小组,每组分别运动,同时组里的个体也有一点自己的区别。
2025-02-01 14:17:49
1442
原创 Games104——游戏引擎中的粒子和声效系统
三维空间中有很多声源,受位置、距离等因素影响,在游戏制作时需要一个“Listenner”来模拟收音,有位置速度(需要模拟多普勒效应,尤其是有飞机的游戏)朝向的维度,如果是第三人称游戏,一般在人物和相机中间。GPU的并行很适合归并排序,复杂度为nlogn,并且合并的时候应该用类似双指针的方法直接去从合并后的list索引去填充,这样可以避免gpu线程在遍历中跳来跳去影响效率。以前的粒子系统的行为都是预设好的,现代引擎中的粒子都有自己的变化、模拟、扰动等,需要读取、定义;有混音声音才好听,为此有一系列标准。
2025-01-29 14:37:58
768
原创 Games104——游戏引擎中物理系统的基础理论算法和高级应用
因此两个凸包是否有交叠(碰撞)的问题就转换为了计算其闵可夫斯基差是否包含原点,那怎么计算呢,见下边GJK算法?
2025-01-28 18:51:23
2562
1
原创 Games104——高级动画技术:动画树、IK和表情动画
ASM包含“节点node”和“变换transitions”。Animation Blending非常重要,连接了我们的Gameplay和动画系统,FK的核心系统让我们输出了一个基础的人物动作因为人物需要与环境有互动,所以给人物加上一个反向约束让他与环境的互动更加真实(IK)骨骼加Morph target animation能实现人物更精细的表情表达通过重定向让有限的动画在不同人物上都能实现。
2025-01-27 14:50:46
850
原创 Games104——引擎架构分层,游戏引擎的渲染实践
而在引擎中的纹理需要有高效压缩和解压、随机访问、压缩率高质量好的特性,因此一般采用块压缩(Block Compression)的技术,比如bxt格式是把图片分为4X4的小格子,并且只记录像素最大最小值和各个像素在这两个值之间的插值。通过对象的派生和继承可以更方便的制作对象。一个游戏物体的行为可以分为属性(Property)和行为(Behaviour),比如他的外形(Shape)、位置(Position)、(Capacity of Battery)就是属性,而移动(Move)、巡逻(Scout)就是行为。
2025-01-22 23:27:29
906
原创 Games104——游戏引擎的动画技术基础
游戏中的动画是要与很多gameplay、地形、怪物交互,还受用户控制的影响实时是基础,不仅包括计算,还有动画数据的加载定位、内存数据处理等对自然感真实度的要求,角色如何表现得是否生动,是否符合物理,以及表情动画的实现(与肢体动画是2套技术体系)
2025-01-22 23:08:04
723
原创 Game104——游戏中渲染管线、后处理和其他的一切
前言老师课前寄语:很多同学表示课程算法两太大听不懂,老师表示games104定位是一个通识课,因为20节课不可能讲清楚游戏引擎的全部内容,因此本门课程的核心是:帮助大家建立主流方法概念和知识体系,公式看不懂也没关系,重要的是思想,以便于未来举一反三。(比如老师上学时读论文,可能一天只能读一个算法都读不懂,但如果有人能提前指出这篇论文的核心点是123的话,读论文就能效率很多,本门课程就起到一个知识总结的作用)
2025-01-22 23:07:35
973
原创 Games104——游戏中地形大气和云的渲染
并且在摄像机移动时,动态的更新替换其中的一部分。这样一来就极大加快了速度,可以每一帧都进行计算了,那原方法LUT中的高度h参数就没有意义了,同时每帧都算的话,太阳顶角的参数也就不需要了,所以新方法的LUT表中只需要计算出观察方向的天顶角 θ 和一个水平方向环绕360度的夹角 ϕ(对应原来太阳到观察视角水平方向的夹角)即可,化四维为二维,见下图右。后来有了利用地形高度混合的方法,谁高显示谁的纹理,见右图,效果还不错,但是由于2种材质是01切换,在相机移动或者视角很低时,会出现抖动或者分界线sharp的问题。
2025-01-22 23:06:47
1130
1
原创 算法刷题笔记——图论篇
二维坐标中,两点可以连成线,多个点连成的线就构成了图。当然图也可以就一个节点,甚至没有节点(空图)整体上一般分为有向图和无向图。有向图是指图中边是有方向的:无向图是指图中边没有方向:加权有向图,就是图中边是有权值的,例如:加权无向图也是同理。无向图中有几条边连接该节点,该节点就有几度。例如,该无向图中,节点4的度为5,节点6的度为3。在有向图中,每个节点有出度和入度。出度:从该节点出发的边的个数。入度:指向该节点边的个数。例如,该有向图中,节点3的入度为2,出度为1,节
2025-01-19 18:32:57
2030
1
原创 C++八股进阶
修饰局部变量:一般情况下,对于局部变量在程序中是存放在栈区的,并且局部的生命周期在包含语句块执行结束时便结束了。但是如果用static关键词修饰的话,该变量便会存放在静态数据区,其生命周期会一直延续到整个程序执行结束,但是要注意的时,虽然用static对全局变量进行修饰之后,其生命周期以及存储空间发生了变换,但其作用域并没有改变,作用域还是限制在其语句块修饰全局变量:对于一个全局变量,它既可以在本文件中被访问到,也可以在同一个工程中其他源文件被访问。
2024-09-27 19:50:16
1477
1
原创 Unity八股总结
屏幕空间-摄像机模式(Screen Space-Camera),设置成该模式后需要指定一个摄像机游戏物体,指定后UGUI就会自动出现在该摄像机的“投射范围”内,和NGUI的默认UI Root效果一致,如果隐藏掉摄像机,UGUI当然就无法渲染。Shader 是一种程序,用来描述物体表面的外观,影响光照与渲染效果。世界空间模式(WorldSpace),设置成该模式后UGUI就相当于是场景内的一个普通的“Cube 游戏模型”,可以在场景内任意的移动UGUI元素的位置,通常用于怪物血条显示和VR开发。
2024-09-27 19:49:06
1485
原创 C#八股总结
C#装箱是将值类型转换为引用类型;拆箱是将引用类型转换为值类型。牵扯到装箱和拆箱操作比较多的就是在集合中,例如:ArrayList或者HashTable之类。
2024-09-27 19:44:35
699
原创 算法刷题笔记——单调栈篇
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。那么单调栈的原理是什么呢?为什么时间复杂度是O(n)就可以找到每一个元素的右边第一个比它大的元素位置呢?单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
2024-09-18 08:26:36
792
原创 Games101图形学笔记——着色
ShadingZ-buffering(深度缓冲) Shading(着色)画家算法Z-BufferShading(着色)Blinn-Phong Reflectance Model(布林·冯反射模型)漫反射能量守恒着色高光Blinn-Phong Reflection ModelShadingFrequencies 着色频率FlatShading(面着色)GouraudShading(顶点着色)PhongShading(像素着色)如何求逐顶点的法线如何求逐像素的法线图形管线/实时渲染管线ShaderShading
2024-09-17 17:11:17
1058
原创 Games101图形学笔记——光栅化
(这里老师说左边时域进行乘积=右边频域的卷积,和前文说的不一致,我去查了一下,好像两种说法是相互的,都可以,这里不太懂,但是不影响整体的理解)在时域中,信号的变化被直接表示为在时间上的变化,而不是在频率上的变化。在进行了上节课的操作之后,所有物体都处在了[-1,1]³的立方体中,接下来就要把他画在屏幕上,这一步就叫做光栅化。我们知道三角形三个顶点的坐标,有了Xmin,Ymin,Xmax,Ymax就可以得到蓝色的区域。把到达光学元件上的光,产生的信息,离散成了像素,对这些像素采样,形成了照片。
2024-09-14 14:16:12
955
原创 计算机网络八股总结
子网掩码是标志两个IP地址是否同属于一个子网的,也是32位二进制地址,其每一个为1代表该位是网络位,为0代表主机位。它和IP地址一样也是使用点式十进制来表示的。如果两个IP地址在子网掩码的按位与的计算下所得结果相同,即表明它们共属于同一子网中。在计算子网掩码时,我们要注意IP地址中的保留地址,即" 0"地址和广播地址,它们是指主机地址或网络地址全为" 0"或" 1"时的IP地址,它们代表着本网络地址和广播地址,一般是不能被计算在内的。
2024-09-13 21:56:00
8142
10
原创 Games101图形学学习笔记——图形学基础
选一远平面上的点x=0,y=0,即中间点(0,0,f,1)T,经矩阵变化后还是中间点(0,0,f,1)T,同时乘f后得(0,0,f²,f)T。对于近平面上的点(x,y,n,1)T经过矩阵变换后该点还为(x,y,n,1)T,同时乘n后得(nx,ny,n²,n)T。对于正交投影来说,视口是个[l,r][b,t][f,n]的长方体,想让他变成[-1,1]³中的话只需要。通过上面推导出来的两个公式可得,对于任意一点(x,y,z,1)T 可得。即(0,0,A,B)(0,0,f,1)T=(0,0,f²,f)T。
2024-09-11 11:26:26
788
原创 C++八股
define定义宏常量或宏函数。或#ifdef#ifndef用于条件编译,即根据是否定义了某个宏来决定是否编译某段代码。例如:#ifdef DEBUG#endif#if#else#elif也是用于条件编译,根据表达式的值来选择编译哪部分代码。#include引入头文件#undef用于取消之前定义的宏。#undef PI取消对PI的定义。#pragma用于向编译器发送特殊指令,可以控制编译器的某些行为,如警告等级、优化选项等。例如:#pragma once // 防止头文件被多次包含。
2024-09-10 14:58:49
1487
原创 操作系统八股总结
操作系统的四大功能:进程控制,内存管理,设备管理,文件管理进程的定义:并发程序的执行,进程的同步与互斥==进程的状态:创建,终止,就绪,运行,阻塞,挂起,激活以及相互转换关系==进程同步问题:生产者消费者模型,信号量机制进程的调度与死锁,死锁条件==如何避免死锁==存储器管理:只读存储器,随机存储器,相对地址和绝对地址速度问题:CPU>寄存器>缓存>主存>磁盘缓存>硬盘程序的装入和链接(动态装入,静态装入,重定位)内存空间划分算法:首次适应;最佳适应;最坏适应。
2024-09-07 16:51:54
1406
原创 热更新学习——基于xLua的游戏热更新实战案例
首先开发业务代码->在所有可能出现问题的类上打上hotfix的标签,在所有lua调用CSharp的方法上打上LuaCallCSharp,在所有CSharp调用Lua的方法上打上CSharpCallLua->打包发布->修改bug时只需要更新Lua文件,修改资源时(声音,模型,贴图,图片,UI)只需要更新ab包。在 Lua 中,“:”和“.”都是用来调用对象方法的,但它们的使用场景和含义有所不同。用“:”定义的方法可以直接访问对象的属性和其他方法,因为 self 是隐式地传递的。补丁代码应该在最开始执行。
2024-09-05 08:51:16
729
原创 算法刷题笔记——动态规划篇
从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的。这样才是一个完整的思考过程,而不是一旦代码出问题,就毫无头绪的东改改西改改,最后过不了,或者说是稀里糊涂的过了。做动规的题目,写代码之前一定要把状态转移在dp数组的上具体情况模拟一遍,心中有数,确定最后推出的是想要的结果。题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];
2024-07-21 12:30:31
606
原创 算法刷题笔记——回溯算法篇
回溯法也可以叫做回溯搜索法,它是一种搜索的方式。在二叉树系列中,我们已经不止一次,提到了回溯,例如二叉树:以为使用了递归,其实还隐藏着回溯 (opens new window)。回溯是递归的副产品,只要有递归就会有回溯。所以以下讲解中,回溯函数也就是递归函数,指的都是一个函数。
2024-07-01 14:45:08
622
原创 UI Toolkit系统学习
UI Toolkit此文章用于学习UnityUI系统,手头的项目做完会来完善Unity上方菜单栏点击Window->UI Toolkit->Samples可以看UI Toolkit中的很多样例。
2024-06-27 20:38:24
3126
2
原创 侯捷C++及C++ Primer plus(六)
虚指针:其实就是一个地址值,以该地址为起始地址的一片内存单元存放着各虚函数的入口地址,这一片内存单元合起来就称为虚函数表(想象一下:一片内存单元存着许多函数地址,想执行哪个虚函数就来这片内存单元查找该虚函数的入口地址,就像查表一样,故称虚函数表)。子类的构造函数首先执行自己,然后调用拥有对象的析构函数,最后执行父类的(和构造函数的执行顺序完全相反)子类的构造函数首先调用父类的默认构造函数,然后调用拥有对象的构造函数,才执行自己的。子类的构造函数首先调用父类的默认构造函数,然后才执行自己。
2024-06-26 14:53:41
358
原创 侯捷C++及C++ Primer plus(五)
函数模板在使用时不必指明type,函数在调用时会进行实参推导,根据调用时的参数推导出type的类型。在设计class的时候,认为可以把哪种变量或函数抽出来允许使用者任意指定就将其前面加T,将其抽出。如果传入函数模板的类型为stone,而stone中没有重载函数模板中用到的运算符,则此时会报错。箭头符号有一个特殊的行为,作用下去得到结果后箭头符号会继续作用下去。调用智能指针的构造函数,将普通指针传入进去生成一个智能指针。传入构造函数的初值如果是该类的子类所构成的,则可以成功赋值。
2024-06-26 14:53:04
920
原创 算法刷题笔记--二叉树篇
感觉树这一章还是没搞清楚,可能是基础不扎实的缘故,学完C++巩固底层知识后二刷确定递归函数的参数和返回值 :确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。确定终止条件 : 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。确定单层递归的逻辑:确定每一层递归需要处理的信息。
2024-06-26 14:48:27
949
原创 算法刷题笔记--字符串篇
KMP主要应用在字符串匹配上。KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。
2024-06-26 14:47:22
733
原创 算法刷题笔记--栈与队列篇
其实就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。而且优先级队列内部元素是自动依照元素的权值排列。缺省情况下priority_queue利用max-heap(大顶堆)完成对元素的排序,这个大顶堆是以vector为表现形式的complete binary tree(完全二叉树)。
2024-06-25 15:00:27
801
原创 算法刷题笔记--哈希表篇
虽然std::set、std::multiset 的底层实现是红黑树,不是哈希表,std::set、std::multiset 使用红黑树来索引和存储,不过给我们的使用方式,还是哈希法的使用方式,即key和value。std::unordered_set底层实现为哈希表,std::set 和std::multiset 的底层实现是红黑树,红黑树是一种平衡二叉搜索树,所以key值是有序的,但key不可以修改,改动key值会导致整棵树的错乱,所以只能删除和增加。我们需要依靠哈希表中的空位来解决碰撞问题。
2024-06-25 14:58:51
1139
原创 断点调试。
但是有时候断点也变得很不现实,比如下面的情况,我需要遍历100000次,如果我们需要逐语句执行,那我们可以在这里点击一天,但是有可能我们只关心报错时 i是多少。(1)点击附加到Unity,不过要注意,无论你是否在Unity中运行了游戏,都可以断点,也就是说你可以在编辑器环境下打断点。解决方式如下图,使用try包裹可能发生报错的代码,然后断点打在catch内,也可以再此处输出一些信息。(3)去启动游戏,或者做某件你想要Debug的事情,比如你的背包有BUG,那么现在打开背包看看原因。
2024-06-25 14:57:36
601
原创 卡牌肉鸽王国之泪(四)
如果您的转换没有任何条件,那么Unity编辑器只考虑退出时间(Exit Time,英文中没说明一点,如果没有Condition的Transition的话,你想要Exit Time是触发,那HasExitTime一定要勾上,不然就没有效果了),当到达退出时间(Exit Time)时就会发生转换。确认按钮会调用Onconfirme中的方法使CardManger中的UnlockCard将当前选中的卡牌传入卡牌库中,让玩家可在之后的回合中抽取到该卡牌,并通过事件调用函数实现UI面板的关闭。
2024-06-25 14:55:36
775
原创 卡牌肉鸽王国之泪(三)
然后测试方法能用了,但是启动游戏的时候玩家的血条能显示,敌人的显示不出来了,可是明明都是用的同一个脚本同一个血条,为什么一个就行一个就不行啊妈的,神经病。骂完突然想到了一种可能,转换坐标时使用到了摄像机的位置,是不是因为敌人是创建在特殊场景中的,而场景中压根没有摄像机,所有才会显示不出来且报空。代码的执行顺序问题,抽卡代码和回合开始重置能量的代码调用了同一个事件,卡牌的能量判断在前,能量的恢复在后,所以出现了这种问题。创建玩家回合开始,敌人回合开始,敌人回合结束的事件,并创建不同的事件函数对其进行监听。
2024-06-25 14:54:36
954
原创 算法刷题笔记--链表篇
注意要先写cur->next,因为如果先写了cur->next->next,假如此时cur->next==null,cur->next->next会出现空指针报错。因为设计链表中所有的方法都是自己写的,所以有可能出现的问题是,实际问题与所表现出来的问题不一致。例如:插入算法写错了,但是运行报错是在取值算法中体现。在链表第index个节点前面插入一个节点。获取链表第index个节点的数值。删除链表的第index个节点。在链表的最前面插入一个节点。在链表的最后面插入一个节点。
2024-06-25 14:52:13
303
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人