向量几何在游戏编程中的使用4

<4>2-D物体间的碰撞响应

这次我要分析两个球体之间的碰撞响应,这样我们就可以结合以前的知识来编写一款最基本的2-D台球游戏了,虽然粗糙了点,但却是个很好的开始,对吗?

一、初步分析

中学时候上物理课能够认真听讲的人(我?哦,不包括我)应该很熟悉的记得:当两个球体在一个理想环境下相撞之后,它们的总动量保持不变,它们的总机械能也守恒。但这个理想环境是什么样的呢?理想环境会不会影响游戏的真实性?对于前者我们做出在碰撞过程中理想环境的假设:

1)首先我们要排除两个碰撞球相互作用之外的力,也就是假设没有外力作用于碰撞系统。
2)假设碰撞系统与外界没有能量交换。
3)两个球体相互作用的时间极短,且相互作用的内力很大。

有了这样的假设,我们就可以使用动量守恒和动能守恒定律来处理它们之间的速度关系了,因为1)确保没有外力参与,碰撞系统内部动量守恒,我们就可以使用动量守恒定律。2)保证了我们的碰撞系统的总能量不会改变,我们就可以使用动能守恒定律。3)两球发生完全弹性碰撞,不会粘在一起,没有动量、能量损失。

而对于刚才的第二个问题,我的回答是不会,经验告诉我们,理想环境的模拟看起来也是很真实的。除非你是在进行科学研究,否则完全可以这样理想的去模拟。

现在,我们可以通过方程来观察碰撞前后两球的速度关系。当两球球心移动方向共线(1-D处理)时的速度,或不共线(2-D处理)时共线方向的速度分量满足:

(1)m1 * v1 + m2 * v2 = m1 * v1‘ + m2 * v2‘ (动量守恒定律)
(2)1/2 * m1 * v1^2 + 1/2 * m2 * v2^2 = 1/2 * m1 * v1‘^2 + 1/2 * m2 * v2‘^2 (动能守恒定律)

这里m1和m2是两球的质量,是给定的,v1和v2是两球的初速度也是我们已知的,v1‘和v2‘是两球的末速度,是我们要求的。好,现在我们要推导出v1‘和v2‘的表达式:

由(1),得到v1‘ = (m1 * v1 + m2 * v2 - m2 * v2‘) / m1,代入(2),得
1/2 * m1 * v1^2 + 1/2 * m2 * v2^2 = 1/2 * m1 * (m1 * v1 + m2 * v2 - m2 * v2‘)^2 + 1/2 * m2 * v2‘^2

=> v2‘ = (2 * m2 * v1 + v2 * (m1 - m2)) / (m1 + m2),则
=> v1‘ = (2 * m1 * v2 + v1 * (m1 - m2)) / (m1 + m2)

我们现在得到的公式可以用于处理当两球球心移动方向共线(1-D处理)时的速度关系,或者不共线(2-D处理)时共线方向的速度分量的关系。不管是前者还是后者,我们都需要把它们的速度分解到同一个轴上才能应用上述公式进行处理。

二、深入分析

首先我要说明一件事情:当两球碰撞时,它们的速度可以分解为球心连线方向的分速度和碰撞点切线方向的分速度。而由于它们之间相互作用的力只是在切点上,也就是球心连线方向上,因此我们只用处理这个方向上的力。而在切线方向上,它们不存在相互作用的力,而且在理想环境下也没有外力,因此这个方向上的力在碰撞前后都不变,因此不处理。好,知道了这件事情之后,我们就知道该如何把两球的速度分解到同一个轴上进行处理。

现在看上面的分析图,s和t是我们根据两个相碰球m1和m2的位置建立的辅助轴,我们一会就将把速度投影到它们上面。v1和v2分别是m1和m2的初速度,v1‘和v2‘是它们碰撞后的末速度,也就是我们要求的。s‘是两球球心的位置向量,t‘是它的逆时针正交向量。s1是s‘的单位向量,t1是t‘的单位向量。

我们的思路是这样的:首先我们假设两球已经相碰(在程序中可以通过计算两球球心之间的距离来判断)。接下来我们计算一下s‘和t‘,注意s‘和t‘的方向正反无所谓(一会将解释),现在设m1球心为(m1x, m1y),m2球心为(m2x, m2y),则s‘为(m1x-m2x, m1y-m2y),t‘为(m2y-m1y, m1x-m2x)(第一篇的知识)。

则设
sM = sqrt((m1x-m2x)^2+(m1y-m2y)^2),
tM = sqrt((m2y-m1y)^2+(m1x-m2x)^2),有

s1 = ((m1x-m2x)/sM, (m1y-m2y)/sM) = (s1x, s1y)
t1 = ((m2y-m1y)/tM, (m1x-m2x)/tM) = (t1x, t1y)

现在s和t轴的单位向量已经求出了,我们根据向量点乘的几何意义,计算v1和v2在s1和t1方向上的投影值,然后将s轴上投影值代
入公式来计算s方向碰撞后的速度。注意,根据刚才的说明,t方向的速度不计算,因为没有相互作用的力,因此,t方向的分速度不变。所以我们要做的就是:把v1投影到s和t方向上,再把v2投影到s和t方向上,用公式分别计算v1和v2在s方向上的投影的末速度,然后把得到的末速度在和原来v1和v2在t方向上的投影速度再合成,从而算出v1‘和v2‘。好,我们接着这个思路做下去:

先算v1(v1x, v1y)在s和t轴的投影值,分别设为v1s和v1t:

v1s = v1.s1
=> v1s = v1x * s1x + v1y * s1y

v1t = v1.t1
=> v1t = v1x * t1x + v1y * t1y

再算v2(v2x, v2y)在s和t轴的投影值,分别设为v2s和v2t:

v2s = v2.s1
=> v2s = v2x * s1x + v2y * s1y

v2t = v2.t1
=> v2t = v2x * t1x + v2y * t1y

接下来用公式

v1‘ = (2 * m1 * v2 + v1 * (m1 - m2)) / (m1 + m2) 
v2‘ = (2 * m2 * v1 + v2 * (m1 - m2)) / (m1 + m2)

计算v1s和v2s的末值v1s‘和v2s‘,重申v1t和v2t不改变:

假设m1 = m2 = 1

v1s‘ = (2 * 1 * v2s + v1s * (1 - 1)) / (1 + 1)
v2s‘ = (2 * 1 * v1s + v2s * (1 - 1)) / (1 + 1)

=> v1s‘ = v2s
=> v2s‘ = v1s

好,下一步,将v1s‘和v1t再合成得到v1‘,将v2s‘和v2t再合成得到v2‘,我们用向量和来做:

首先求出v1t和v2t在t轴的向量v1t‘和v2t‘(将数值变为向量)

v1t‘ = v1t * t1 = (v1t * t1x, v1t * t1y)
v2t‘ = v2t * t1 = (v2t * t1x, v2t * t1y)

再求出v1s‘和v2s‘在s轴的向量v1s‘和v2s‘(将数值变为向量)

v1s‘= v1s‘ * s1 = (v1s‘ * s1x, v1s‘ * s1y) 
v2s‘= v2s‘ * s1 = (v2s‘ * s2x, v2s‘ * s2y)

最后,合成,得

v1‘ = v1t‘ + v1s‘ = (v1t * t1x + v1s‘ * s1x, v1t * t1y + v1s‘ * s1y)
v2‘ = v2t‘ + v2s‘ = (v2t * t1x + v2s‘ * s2x, v2t * t1y + v2s‘ * s2y)

从而就求出了v1‘和v2‘。下面解释为什么说s‘和t‘的方向正反无所谓:不论我们在计算s‘时使用m1的球心坐标减去m2的球心坐标还是相反的相减顺序,由于两球的初速度的向量必有一个和s1是夹角大于90度小于270度的,而另外一个与s1的夹角在0度和90度之间或者说在270度到360度之间,则根据向量点积的定义|a|*|b|*cosA,计算的到的两个投影值一个为负另一个为正,也就是说,速度方向相反,这样就可以用上面的公式区求得末速度了。同时,求出的末速度也是方向相反的,从而在转换为v1s‘和v2s‘时也是正确的方向。同样的,求t‘既可以是用s‘逆时针90度得到也可以是顺时针90度得到。

三、编写代码

按照惯例,该编写代码了,其实编写的代码和上面的推导过程极为相似。但为了完整,我还是打算写出来。

// 用于球体碰撞响应的函数,其中v1a和v2a为两球的初速度向量,
// v1f和v2f是两球的末速度向量。
// m1和m2是两球的位置向量
// s‘的分量为(sx, sy),t‘的分量为(tx, ty)
// s1是s的单位向量,分量为(s1x, s1y)
// t1是t的单位向量,分量为(t1x, t1y)

void Ball_Collision(v1a, v2a, &v1f, &v2f, m1, m2){

// 求出s‘
double sx = m1.x - m2.x ; 
double sy = m1.y - m2.y ;

// 求出s1
double s1x = sx / sqrt(sx*sx + sy*sy) ;
double s1y = sy / sqrt(sx*sx + sy*sy) ;

// 求出t‘
double tx = -sy ;
double ty = sx ;

// 求出t1
double t1x = tx / sqrt(tx*tx + ty*ty) ;
double t1y = ty / sqrt(tx*tx + ty*ty) ;

// 求v1a在s1上的投影v1s
double v1s = v1a.x * s1x + v1a.y * s1y ;

// 求v1a在t1上的投影v1t
double v1t = v1a.x * t1x + v1a.y * t1y ;

// 求v2a在s1上的投影v2s
double v2s = v2a.x * s1x + v2a.y * s1y ;

// 求v2a在t1上的投影v2t
double v2t = v2a.x * t1x + v2a.y * t1y ;

// 用公式求出v1sf和v2sf
double v1sf = v2s ;
double v2sf = v1s ;

// 最后一步,注意这里我们简化一下,直接将v1sf,v1t和v2sf,v2t投影到x,y轴上,也就是v1‘和v2‘在x,y轴上的分量
// 先将v1sf和v1t转化为向量

double nsx = v1sf * s1x ;
double nsy = v1sf * s1y ;
double ntx = v1t * t1x ;
double nty = v1t * t1y ;

// 投影到x轴和y轴
// x轴单位向量为(1,0),y轴为(0,1)
// v1f.x = 1.0 * (nsx * 1.0 + nsy * 0.0) ;
// v1f.y = 1.0 * (nsx * 0.0 + nsy * 1.0) ;
// v1f.x+= 1.0 * (ntx * 1.0 + nty * 0.0) ;
// v1f.y+= 1.0 * (ntx * 0.0 + nty * 1.0) ;

v1f.x = nsx + ntx ;
v1f.y = nsy + nty ;

// 然后将v2sf和v2t转化为向量

nsx = v2sf * s1x ;
nsy = v2sf * s1y ;
ntx = v2t * t1x ;
nty = v2t * t1y ;

// 投影到x轴和y轴
// x轴单位向量为(1,0),y轴为(0,1)
// v2f.x = 1.0 * (nsx * 1.0 + nsy * 0.0) ;
// v2f.y = 1.0 * (nsx * 0.0 + nsy * 1.0) ;
// v2f.x+= 1.0 * (ntx * 1.0 + nty * 0.0) ;
// v2f.y+= 1.0 * (ntx * 0.0 + nty * 1.0) ;

v2f.x = nsx + ntx ;
v2f.y = nsy + nty ;

}// end of function

原文链接

原文地址:https://www.cnblogs.com/ring1992/p/8479576.html

时间: 2024-11-05 19:39:52

向量几何在游戏编程中的使用4的相关文章

向量几何在游戏编程中的使用2

<2>2-D物体任意角度的反弹 一.求与某个向量a正交的向量b 根据向量内积的性质以及正交向量之间的关系,有: 设a=(xa,ya),b=(xb,yb) a.b = 0=> xa*xb + ya*yb = 0=> xa*xb = -ya*yb=> xa/-ya = yb/xb=> xb = -ya , yb = xa 或 xb = ya , yb = -xa 则向量(xa,ya)的正交向量为(xb,yb)=(-ya,xa)比如上图中,向量(2,3)的逆时针旋转90度的正

向量几何在游戏编程中的使用3

<3>2-D边界碰撞检测 一.使用向量进行障碍检测的原理 在游戏中进行障碍碰撞检测,基本思路是这样的:给定一个障碍范围,判断物体在这次移动后会不会进入这个范围,如果会,就发生碰撞,否则不发生碰撞.在实际操作中,是用物体的边界来判断还是其他部位判断完全取决于编程者.这时候,就可以从这个部位沿着速度的方向引出一条速度向量线,判断一下这条线段(从检测部位到速度向量终点)和障碍边界线有没有交点,如果有,这个交点就是碰撞点. 上面物体A,在通过速度向量移动之后将到达B位置.但是,这次移动将不会顺利进行,

【转】游戏编程中的人工智能技术--神经网络

原文:http://blog.csdn.net/ecitnet/article/details/1799444 游戏编程中的人工智能技术. > .  (连载之一) 用平常语言介绍神经网络(Neural Networks in Plain English) 因为我们没有很好了解大脑,我们经常试图用最新的技术作为一种模型来解释它.在我童年的时候,我们都坚信大脑是一部电话交换机.(否 则它还能是什么呢?)我当时还看到英国著名神经学家谢林顿把大脑的工作挺有趣地比作一部电报机.更早些时候,弗罗伊德经常把大

游戏编程系列[1]--游戏编程中RPC协议的使用

RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据.在OSI网络通信模型中,RPC跨越了传输层和应用层.RPC使得开发包括网络分布式多程序在内的应用程序更加容易.RPC采用客户机/服务器模式.请求程序就是一个客户机,而服务提供程序就是一个服务器. 首先,客户机调用进程发送一个有进程参数的调用信息到服务进

7_DoubleBuffer 游戏编程中的双缓存模式

### double buffer 双缓存 简单说: 当一个缓存被读取的时候,往另一个缓存里写入, 如此交替 #### the pattern 有两个缓存实例,一个是 current buffer, 一个是next buffer 从current buffer读取信息, 往next buffer里写入信息. swap操作,进行两种buff的身份切换 #### 何时使用 1 需要增量修改的状态 2 在修改的过程中需要进行访问 3 当访问数据的时候,不会发现数据正在被写入 4 读操作不用等待写的操作

《逐梦旅程 WINDOWS游戏编程之从零开始》笔记6——Direct3D中的顶点缓存和索引缓存

第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物体模型的基本单元,而一个三角形有3个顶点,为了能够使用大量三角形组成三角形网格来描述物体,需要首先定义号三角形的顶点(Vertex),3个顶点确定一个三角形,顶点除了定义每个顶点的坐标位置外,还还含有颜色等其他属性. 在Direct3D中,顶点的具体表现形式是顶点缓存,顶点缓存保存了顶点数据的内存空

游戏编程精粹系列书籍目录一览

游戏编程精粹1 第1章 通用编程技术 1.0 神奇的数据驱动设计(Steve Rabin) 3 1.0.1 点子1--基础 3 1.0.2 点子2--最低标准 3 1.0.3 点子3--杜绝硬编码 3 1.0.4 点子4--将控制流写成脚本 4 1.0.5 点子5--什么时候不适合使用脚本? 5 1.0.6 点子6--避免重复数据 5 1.0.7 点子7--开发工具来生成数据 6 1.0.8 结论 6 1.1 面向对象的编程与设计技术(James Boer) 7 1.1.1 代码风格 7 1.1

游戏编程技巧

看了<3D游戏编程大师技巧>的1.3节内容,感觉本科学的好多知识突然找到了价值.比如汇编.寻址等等. 这些东西也可以用到游戏编程中去~摘记部分要点如下 视频游戏是一种超高性能计算机程序.这意味着您将不能在时间关键代码部分和内存关键代码部分使用高级API. 下面是进行游戏编程时需要记住的一些技巧: 1.对您所做的工作进行备份 2.开始游戏项目时,需要进行良好的组织 3.使用内嵌函数 4.尽可能使用32位变量而不是8位或16位变量 5.不要害怕使用全局变量 6.以RISC方式进行编程 7.对于整数

GPU编程中的常用几何函数、纹理映射函数、偏导数函数

在GPU编程中,函数一般分为以下几种类型:数学函数.几何函数.纹理映射函数.偏导数函数.调试函数等.熟练利用好GPU自带函数,可以在一定程度上提高并行编程速度与效率. 在上一部分已经介绍了数学函数, 数学函数用于执行数学上常用计算,比如:三角函数.幂函数.向量和矩阵函数,这些函数一般都被重载,用来支持标量数据和不同长度的向量作为输入参数.本部分介绍几何函数.纹理映射函数.偏导数函数.调试函数. 几何函数(Geometric Functions) 几何函数,如表所示,用于执行和解析几何相关的计算,