- 博客(149)
- 资源 (16)
- 收藏
- 关注
原创 从零到屎山系列-游戏开发(Day3 Pre)
思考了一下,暂时还不能脱离控制台游戏,那么就来俄罗斯方块吧,这次希望让游戏具有基本的菜单选项,计分板,关卡概念。
2024-05-05 23:43:57
127
原创 从零到屎山系列-游戏开发(Day2)
游戏元素有三种,蛇、障碍物、食物,这三种元素对于游戏来说都是普通的物件,可以被绘制,也可以有处理逻辑,所以需要一类概念来表示这些物件,这里称之为GameObject,如下代码片段。因为三个物件都是可以被绘制的,所以定义了RenderObject来表示绘制信息,这样就可以在绘制不同物件的时候只需要关注每个物件中的RenderObject中的内容,拿了数据就可以无脑绘制了。
2024-05-04 22:53:59
456
原创 从零到屎山系列-游戏开发(序章)
整个系列目前没有计划,但是有目标,可能会有几十篇,几百篇,几千篇.....,但绝对不会只有一篇。目标是从一个极其简陋的开始到五脏俱全的游戏,如果读者只想看最后五脏俱焚的游戏,那么可以忽略中间欢声笑语的挑粪过程。希望此分享带来的不只是知识,还有思想和心情。也不算是一时兴起才想做这么一个系列的博客,学技术之初就是为了好玩,但是当这些都变成了让你烦恼的任务时,慢慢你会变得讨厌它。所以这次我们放下烦恼,放下节操,来一次说走就走的旅行,堆一个想堆就堆的屎山!
2024-05-01 00:49:46
214
1
原创 我的博客公告
由于本人工作比较忙,所以博客一直没有时间更新,喜欢探讨与我博客相关内容的可以直接添加本人QQ号码1487653332,我会找时间开启新的栏目并更新博客。
2022-03-09 23:51:03
350
原创 389找不同---位运算
题目:给定两个字符串 s 和 t,它们只包含小写字母。 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。 请找出在 t中被添加的字母。 示例 1: 输入:s = "abcd", t = "abcde" 输出:"e" 解释:'e' 是那个被添加的字母。 示例 2: 输入:s = "", t = "y" 输出:"y" 示例 3: 输入:s = "a", t = "aa" 输出:"a" 示例 4: 输入:s = "ae", t = "aea" 输出:"a" 提示: 0 <..
2020-12-18 08:35:31
320
原创 自己动手写2D物理引擎-初级篇(1)
第一章 框架设计总体的类如下图所表示。Shape作为形状基类。存储了与形状有关的物理量class Shape{public: float I = 0.0f, invI = 0.0f;//转动惯量和逆};Rectangle和Circle派生于Shape,存储了实际的形状信息。class Rectangle :public Shape{public: //存储矩形的长宽 agl::vec2f r;};class Circle :public Shape{public:
2020-11-26 00:43:43
2784
原创 自己动手写2D物理引擎-初级篇(0)
序言本系列文章主要讲的的是2D物理引擎设计,从简单开始,引擎中主要完成简单形状的碰撞计算,物理冲量计算,抖动处理,运动计算。主要受到Box2D-Lite启发,亲自动手学习一下。设计过程从框架到细节,涉及到数学原理我会详细讨论并说明。同时,这里只会介绍用到的技术,不用的技术一般不提及或讲解。章节第一章 框架设计第二章 碰撞检测第三章 冲量处理第四章 运动处理...
2020-11-25 17:01:23
1441
原创 Box2D-Lite源码阅读笔记(12)
简介这次讲解动理学的最后一部分,动量计算后更新速度。正文下面这段代码,主要流程就是分别计算分离轴方向的动量和垂直分离轴方向的动量。void Arbiter::ApplyImpulse(){ Body* b1 = body1; Body* b2 = body2; for (int i = 0; i < numContacts; ++i) { Contact* c = contacts + i; c->r1 = c->position - b1->posi.
2020-11-24 22:43:28
581
1
原创 Box2D-Lite源码阅读笔记(11)
简介这次我来看详细的运动处理函数。计算准备工作看下面的这个函数里的实现。void World::Step(float dt){ ... for (ArbIter arb = arbiters.begin(); arb != arbiters.end(); ++arb) { arb->second.PreStep(inv_dt); } ...}代码如下,注释和后面都会有说明void Arbiter::PreStep(float inv_dt){ //补偿系数参数.
2020-11-24 22:26:56
527
原创 Box2D-Lite源码阅读笔记(10)
简介这次我来探究一下step剩下的部分。动量计算,位移计算void World::Step(float dt){ float inv_dt = dt > 0.0f ? 1.0f / dt : 0.0f; //碰撞检测并获取碰撞信息 BroadPhase(); // Integrate forces. for (int i = 0; i < (int)bodies.size(); ++i) { Body* b = bodies[i]; //质量无穷大作为固定的物体.
2020-11-24 17:46:28
421
原创 Box2D-Lite源码阅读笔记(9)
简介到这里就是碰撞检测的最后一个阶段,在前面已经获取了粗略位置点的时候,这里要获取精确的碰撞点。碰撞点筛选目前位置,待定的碰撞点已经处于A的宽度范围内了,但是是否与A碰撞,或者是否在A内还需要判断。int numContacts = 0; for (int i = 0; i < 2; ++i) { //计算出相交深度 float separation = Dot(frontNormal, clipPoints2[i].v) - front; //深度小于等于0的点说明点相交.
2020-11-24 09:27:50
439
原创 Box2D-Lite源码阅读笔记(8)
简介上一篇完成了碰撞点的初步获取,这回阅读的是碰撞点的第二步获取。碰撞点截取因为有一定可能使得取得的B上的碰撞点在A的宽度范围之外,这样一来,范围之外的点属于没有意义的点,所以需要根据A的宽度将点截断在A的宽度范围内。代码/*参数列表:vOut[2]输出结果,vIn[2]输入的碰撞点候选点,normal侧方向上的向量(假设以矩形A坐标系为主)offset侧方向上的坐标值。这假设前面是以A坐标系为主,vIn[2]是获取自矩形B上的顶点且已经转换到世界坐标*/int ClipSegment.
2020-11-24 08:56:58
492
原创 一个个人学习的小游戏demo开源
简介之前在学习游戏相关只是的时候,由于学习的比较杂乱,这个过程中写了一个游戏框架,其实就是个小demo,决定开源了,和喜欢游戏开发的人交流学习。代码的资料注释不多,以下是一些效果,其中,游戏元素管理,动画加载,物理等一切都是自己写的,不依赖任何库,只有图像显示需要opengl,本打算写个马造的,奈何功力不够。效果图源码链接demo源代码和资源...
2020-11-23 16:04:19
679
原创 Box2D-Lite源码阅读笔记(7)
简介上一篇阅读了碰撞点计算框架和碰撞深度获取的代码,这次阅读碰撞点计算的具体步骤之一,计算候选点。选择候选点候选点说明现在计算的并不是具体的碰撞点,而是一些可能的碰撞点,或者与碰撞点相关的点,或者是需要加工一个才能成为碰撞点。/*参数列表:返回结果(预测相交点),另一个矩形的半径大小,另一个矩形的位置 另一个矩形的旋转矩阵,调用这个函数的矩形的正面方向*/static void ComputeIncidentEdge(ClipVertex c[2], const Vec2& h, .
2020-11-23 15:27:32
473
原创 Box2D-Lite源码阅读笔记(6)
0.简介上一篇介绍了碰撞检测部分,这次阅读后面的碰撞点计算和最小碰撞深度计算的代码。1.获取碰撞点和碰撞深度碰撞后要计算出碰撞点,因为在计算运动方向,转动惯量等数据的时候需要碰撞点信息,碰撞深度是为了分离两个物体用的信息,因为物体碰撞时刻,不能正好点边接触,两个物体可能会有一些交叉,这个交叉导致碰撞点会落在形状内部,而不是边界,并且两个物体分离,运动状态信息也需要这个交叉深度来进行各种视觉效果上的平衡。 // Find best axis Axis axis;//选定的轴 float
2020-11-23 13:38:06
539
原创 Box2D-Lite源码阅读笔记(5)
0.简介前一篇对碰撞检测的准备工作做了阅读,这回我们看第一步,分离轴定理检测矩形是否相交。1.分离轴定理这里面简单对分离轴定理做一个说明,这个里面有详细说明分离轴定理详细说明大概就是比如两个凸多边形,这两个多边形分别向每条边的垂直方向做投影,如果有一个方向上的投影不相交,则两个多边形不相交,反之则相交。具体就看上面的链接吧。2.代码阅读int Collide(Contact* contacts, Body* bodyA, Body* bodyB){ ...
2020-11-22 20:39:26
825
4
原创 Box2D-Lite源码阅读笔记(4)
0.简介前面我们发现了物体碰撞检测的函数,这回我将来读物体碰撞检测函数的代码。1.碰撞检测这个碰撞检测主要是针对矩形与矩形的碰撞检测,以为例子中只给了矩形的物理碰撞。这里先对开始部分做一个阅读和注释。这段代码是一些准备工作,主要目的是获取物体在空间中的姿态和基本位置信息。int Collide(Contact* contacts, Body* bodyA, Body* bodyB){ // Setup //取A B两个物体的半径,width中存储的是边长 //这里获取到的是一半
2020-11-21 14:23:16
622
1
原创 Box2D-Lite源码阅读笔记(3)
0.简介这次来看step函数。1.step开始step函数里看起来如下的样子,当然我们只关注一块。void World::Step(float dt){ float inv_dt = dt > 0.0f ? 1.0f / dt : 0.0f; // 碰撞检测 BroadPhase(); ...}BroadPhase函数是碰撞碰撞检测函数。具体讲解在代码注释void World::BroadPhase(){ //这是一个O(n^2)的循环 for
2020-11-21 13:52:27
690
原创 Box2D-Lite源码阅读笔记(2)
0.初始化函数static void InitDemo(int index){ world.Clear(); numBodies = 0; numJoints = 0; bomb = NULL; demoIndex = index; demos[index](bodies, joints);}在这个初始化函数中,一般会默认执行index=0的函数,这个函数就是一个示例,因为示例比较简单,所以也便于研究,示例效果如下。就是一个方块。进入第一个示例函数。(忽略我加的注释)
2020-11-20 22:16:19
724
原创 Box2D-Lite源码阅读笔记(1)
0.简介先从工程配置开始。1.环境配置下载好源码后,我在源码包里发现了build.bat,我的电脑里有VS2019,于是我运行了一下,生成了一个VS工程,之后看代码就用VS来看了,打开工程后,直接就编译ALL_BUILD那个项目,编译好后,我们选择sample这个项目 ,之后的源码阅读都从这里开始。2.起点找到了main函数,大概在下面这个位置,我们开始进入源码探究。int main(int, char**){ ... InitDemo(0); ... world.
2020-11-20 21:55:58
703
原创 Box2D-Lite源码阅读笔记(0)
0.简介一直对物理引擎比较感兴趣,始终想找一些比较好的教程来学一学,但是资料太少,所以通过阅读源码来学习吧,我将我阅读Box2D-Lite的笔记和新的会记录在这里,是Box2D-Lite,不是Box2D,从简单的读起。1.记录流程记录过程也没什么顺序可以确定,我就是根据我调试代码的顺序来进行阅读,调到哪里就看到哪里。box2d-lite源码相关文档阅读源码的时候,必要时刻可以看看相关文档。...
2020-11-20 10:54:43
509
原创 数据结构---中缀转后缀计算表达式计算结果(支持括号)
0.简介有了上一篇的基础,我直接在上面修改支持括号,主要就是将括号里面的式子单独拿出来,在递归计算结果。1.实现#include<iostream>#include<string>#include<vector>#include<unordered_map>#include<stack>#include<functional>using namespace std;unordered_map<strin
2020-11-17 21:34:39
315
2
原创 数据结构---中缀转后缀计算表达式计算结果
0.简介在计算基本是加减乘除表达式的时候,比较好的方法就是把中缀式转换到后缀式来计算,正好最近用上类似的知识了,就复习一下。1.中缀转换后缀并计算结果实现是说话,这类知识点书上,网上到处都有,我就不写了,直接贴代码了。#include<vector>#include<unordered_map>#include<stack>#include<functional>using namespace std;int main(){
2020-11-17 21:28:41
399
2
原创 计算机与代数---函数导数表达式计算
0.简介经过前面两篇的铺垫,这里可以请出关键了,根据写好的函数表达式,计算其导数的表达式。1.导数表达式计算直接看这个问题,其实比较难解决,因为导数表达式直接来算还是需要不少处理过程的,但是前面我通过计算图能求得导数的数值结果,那么,我将计算导数数值结果函数中计算数值的步骤全部都换成对应的字符串输出就可以了,这样就能看见表达式结果了,有了前面的计算图,这里就不是难题。2.实现例举class AddNode : public OpNode{public: AddNode(share
2020-11-16 17:54:35
1207
原创 计算机与代数---函数导数数值结果计算
0.简介有了前一篇的计算图铺垫,这次我可以计算出函数导数的结果。1.计算导数一般来说,计算导数的时候,我们利用导数公式可以计算,根据前一篇最开始说的,如果程序中的方程或者函数直接计算,那么这个函数的导数也需要再重写一个才可以,但是利用计算图则可以不必针对某个方程专门计算的导数,而是利用计算图的特性来计算。例如,设,,然后,计算,,对于计算图来说,计算到图的叶子节点就停止计算。实际效果如下图。所以,利用最基本的导数运算规则,对每个结点做求导操作,最后得到的值就是导数,图会自动的根据构建方式来
2020-11-16 17:37:35
1305
原创 计算机与代数---函数数值结果计算
0.简介函数或者说方程,在编程语言中,直接就能通过指定变量和系数进行计算,这里主要是利用编程语言来实现这个计算。1.方程的表示一般来说,一个方程如,在计算机中可以表示成,实际的代码如下y = x*x当计算y的时候,给x指定值即可,如float x = 0, y = 0;for (int i = 0; i < 10; i++){ y = x * x; cout << y << endl;}当方程更加复杂的时候。float x = 0
2020-11-16 16:48:23
826
1
原创 C++函数指针写法和类型声明
0.简介函数指针大多数用的不多,我觉得啊,但是实际上函数指针很有用,且用起来特别灵活优美。1.函数指针声明函数指针声明方式有点怪,一般就是如下。void print(){ cout << "hello" << endl;}int main(){ void(*fun_ptr)() = print;//void为返回类型,第二个括号为参数列表,第一个括号是变量名 fun_ptr(); return 0;}在实际赋值的时候和普通数值指针没区别,使用的
2020-11-12 21:56:34
2237
原创 计算机与代数---如何计算sqrt---优化
0.简介根据上一篇的内容,今天又看到了比较的好的一个优化方法,在这里记录一下。1.判断条件优化之前的二分法和牛顿迭代法的判断条件都有乘法,今天发现一个比较的好的判断方法。二分法long double l = 0, r = (n>=1 ? n:1), mid=0;while (fabs(l-r)>1e-8){ mid = (l + r) / 2; if (mid * mid > n) r = mid; else l = mid;}牛顿迭代法long
2020-11-12 19:47:54
590
原创 计算机与代数---如何计算sqrt---方法和实现
0.简介开根号可以用之前的pow方法计算,当然,还有一些更便捷的方法。1.二分法最常见的开根号方法就是二分法,计算,另,当n的值大于1的时候,可以让l = 0,r = n,当n<1的时候另l=0,r=1,然后利用如下代码计算出结果。long double l = 0, r = (n>=1 ? n:1), mid=0;while (fabs(mid * mid - n)>1e-8){ mid = (l + r) / 2; if (mid * mid > n)
2020-11-12 01:59:36
3276
12
原创 计算机与代数---如何计算pow---方法和实现
0.简介前面实现了log2,我就顺势用这个函数来构造求a^x的结果。1.方法推导我们通过关系式子的变换可以得到等式,这样一来我们只需要针对2的n次幂来求解。将2^x泰勒展开,ln2我们可以预先求出。对于幂大于1的情况,例如,变换成,因为比较容易计算,利用泰勒展开式计算,这里要处理一下幂是负数的时候,然后将所有小数的幂次都直接带入泰勒展开式,大于1的部分直接计算就可以。2.实现double baselog2(double n){ n-=1; double x = -1,resu
2020-11-10 15:25:28
1536
原创 计算机与代数---如何计算ln---方法和实现
0.简介在有了前面log2的基础上,现在可以算任意的的log了,这里我们计算ln1.ln表达式根据换底公式可以得到这个式子。2.实现double myln(double n){ return mylog2(n) / 1.4426950408889634;}
2020-11-10 11:11:50
2931
原创 计算机与代数---如何计算log---实现[2]
0.简介上一篇文章介绍了原理,这里介绍如何实现。1.泰勒展开因为拟合的项数比较多,所以用循环可以解决。用下面的代码解决。#define LN2 0.6931471805599453double baselog2(double n){ n-=1; double x = 1,result = 0; for (int i = 1; i < 20; i++) { result += (n/i);//累加结果 n *= (x * (-1));//累乘
2020-11-10 10:10:42
1444
8
原创 计算机与代数---如何计算log---方法推理[1]
0.简介最近在复习一些数学知识,对计算机如何log,sin,cos等有了些疑问,并且通过查阅资料(其实没找到什么),和设计方法,大概将其实现出来。1.泰勒展开对于如何计算log这个问题,我能想到的就是去计算泰勒展开式,将在0点展开,但是发现0点没法展开,那就变换一下,展开。经过推到,其泰勒展开式为,有了这个展开式,我们就可以计算的结果。2.实际问题,大于1的数字上面虽然得到了泰勒展开,但是展开只能拟合到(-1,1]这个范围内,超出这个范围,尤其是大于1的时候,会随着值得增大而越发的不
2020-11-10 09:43:44
4028
1
原创 C++ 类与对象探秘---结构体实现类
0.简介在C++中,class和struct几乎没有区别,非要说有区别,就是默认访问权限的区别,class默认私有,struct默认公有,这回主要通过C语言的结构体来了解一下C++类和对象的一些原理。1.struct与class的普通成员函数结构体中,可以放变量,还有函数声明,这里设定不将函数声明写在结构体中。//演示类1struct Animal{ //名字 string name;};void print(Animal* THIS){ cout << THI
2020-11-05 21:32:15
520
原创 C++模板可变参数(2)---tuple
0.简介前一篇介绍了模板的可变参数在函数的用法,这次来研究一下在类中的用法。1.tuple在STL中有tuple,其可以包含多种不同类型的变量用法如下。tuple<int> a;tuple<int,float> b;tuple<int,float,double> c;上面的用法和上一篇的print函数中的参数很类似,所以我分析tuple里面也用到了类似的原理,所以我们自己简要实现一下。2.mytuple显然下面的代码是不能达到目的的。
2020-11-05 20:30:56
547
原创 C++ 模板可变参数(1)---函数
0.简介模板可变参数是一种可以变化模板中类型参数个数并且令类或者函数支持多种不同类型参数,和不定参数个数的神奇玩法。1.print函数设计一个print函数,希望可以有如下效果。print(1);print(1,3.2);print(1,9.9,"abc");同一个函数可以接收可变个数目和不同类型的参数,需要模板和可变参数同时配合。下面这段代码中,arg...就是可变参数的一个"包",其实里面有多个参数捏在一起,先可以这么理解,当调用print(1,2,3,4,5)的时候,1会
2020-10-26 21:30:45
337
1
原创 数据结构---KMP算法(2)
0.简介KMP中有个next数组,我们从这里逐渐引出KMP算法原理。1.最长公共前后缀我们先看最长公共前后缀问题,给定一个字符串s,s为abcdabcd,问这个字符串的最长公共前后最是什么,我们能一眼就看出是abcd,因为abcd.....,和.....abcd,这样一来,就找到了。现在好好理解一下这个找最长公共前后缀问题。首先,这是一个动态规划问题。假如当前字符串长度为n,那么当长度为n的时候,最长公共前后缀m是什么,取决于长度是n-1时候最长公共前后缀k是多少和第n个字符是否与第k+1个
2020-07-02 21:07:35
432
原创 C++ 知识点零碎补充 位域
0.简介本篇介绍位域和一些不容易注意到的特性。1.位域一般在结构体的变量声明中用位域,例如struct A{ int a : 5, b : 3, c : 6, x : 5;};这时候,a,b,c,x冒号后面数字的意义是这个变量占用几个位,分别是5,3,6,5。因为声明的时候是int类型,这四个变量的位的总和不超过一个int的宽度,那么他们就共同占用一个int的位置,实验为32位程序,那么这个结构体的大小为4字节。并且如下操作也是不允许的。sizeof(A::a);abc
2020-07-02 12:38:19
227
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人