游戏开发论坛

 找回密码
 立即注册
搜索
查看: 21725|回复: 31

[原创] [数值设计] 分享一个高效的动作类、格斗类游戏碰撞做法

[复制链接]

98

主题

784

帖子

4493

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4493
发表于 2013-7-22 12:13:06 | 显示全部楼层 |阅读模式
问题在跑酷类和动作类游戏中,我们会遇到要求多边形碰撞检测的问题,很多时候我们采取逃避,还是用Tile式的模式,只是添加一些30度45度的角来解决斜坡的需求。但是其实好的跑酷类游戏中,地形的形状应该是任意的,就像索尼克这样的相对来说就比马里奥有了进步,当然索尼克在马里奥之后这么多年也该有了进步。
从策划的角度来说,当我们需要设计一个跑酷类游戏或者动作类游戏或者百战天虫玩法游戏的时候,我们游戏的主系统中有这么一个有趣的数值设计要做,那就是结合多边形地形的碰撞算法。这里分享一下我们在最近一个跑酷类游戏中的应用数学解决这个问题的方法,希望能对大家有所帮助。

思路
看过很多多边形碰撞的算法,优化的做法是先算外框(矩形),如果矩形相交则进一步判断其中多边形是否有共同位置的点。这个做法不错,但并不适合跑酷、格斗、百战天虫这样需要像素级运算的游戏,我们需要从数学的角度出发去想一个办法——数值设计。我们把多边形碰撞先拆解为“一个点是否在多边形内”这样一个问题,毕竟在跑酷游戏中,逻辑上角色完全可以就是一个点。

解决办法
这个算法很简单:
设:点m和多边形p,多边形p由点p1,p2...pn组成。
1,从点引申一条平行于X轴并与X轴同向的射线(计为mx,千万不要“复杂”到向量问题上,向量在我们那时候是高中级别的,单是射线是初中级别的,Keep it "Simple")。
2,判断射线与p的每条线段是否相交,若与奇数条线段相交,则有m与p相交;若与偶数条线段相交,则有m与p不相交。
3,策划设计如果m在p上某条线段上(相切),也算是相交的话,则m为虚点,否则m为实点。
这样一来,问题进一步简化为“一条平行于x轴的射线与线段是否相交”,这个方法很简单:
设:线段ab的两端点(ax,ay) (bx,by),射线ma(y=n),从虚点(m,n)射出。
那么:
1,如果ax和bx都小于等于m,ma与ab不相交。
2,ay,by同时大于或者小于n时,ma与ab不相交。
3,其余情况下,ma与ab相交。
因此我们可以得到伪代码(haxe):
public function SegmentIntersect(m:Int, n:Int, aX:Int, aY:Int, bX:Int, bY:Int):Bool{
  //你当然可以用Float,但我们的目的是像素级别的,而不是Flash自带的向量方式,因此点应该都是Int的。
  return !((aX<=m && bX<=m) || ((aY<n && bY<n)||(aY>n && by>n)));
}
之后我们For循环去对多边形p的每条线段进行判断,看相交次数得到是否点m在p内:
public function PointInPolygon(mX:Int, mY:Int, p:Array<Array<Int>>):Bool{
  //p是一个数组,代表多边形的每一个点,p的每一个单元都是[x,y]坐标,一个点。
  var intersectTimes:Int = 0; //相交了多少次
  for (i in 0...p.length){
     intersectTimes += SegmentIntersect(mX,mY,dasP[0], dasP[1], dasP[(i+1) % p.length][0], dasP[(i + 1)% p.length][1])==true?1:0;
  }
  return ((intersectTimes % 2)==1); //奇数次代表相交。
}

依靠这个判断2个多边形是否相交
有一个性质:假如点m与多边形p相交,那么m所在的多边形pm一定与p相交。注意!pm与p相交时,pm未必有任何一个点m会与p相交,但是,两个多边形p1和p2,就有性质:
1,如果p1中的某一点pm1与p2相交,则p1与p2相交。
2,如果p2中的某一点pm2与p1相交,则p1与p2相交。
3,如果p1中没有这个pm1(能与p2相交),p2中也找不到pm2,那么我们可以认定p1与p2不相交(这个没有实际测试过,边际问题可能我考虑的还不周全,但目前有效),因此有:
function PolygonIntersectPolygon(p1:Array<Array<Int>>, p2:Array<Array<Int>>):Bool{
  for (p in p1){
    if (PointInPolygon(p[0],p[1],p2)==true){
    return true;
    }
  }
  for (p in p2){
    if (PointInPolygon(p[0],p[1], p1)==true){
      return true;
    }
  }
  return false;
}

总结
这样的碰撞算法,其实适合于你需要得知若干个多边形之间互相是否相交,但不需要知道他们相交面积的时候,比如格斗游戏,再比如跑酷游戏中(角色碰到某个地形就死了,但却要在地形上跑,所以有双重计算多边形碰撞的地方)。
如果你一个策划不想总被程序说这个不能实现,那个没有办法,那你就该把如何实现的逻辑想法按照这样先设计好,毕竟程序说不能实现,大多时候是因为他/她不知道你要实现什么,虽然有时候的确是为了偷懒。一个数值策划存在的意义,就是利用数学知识建立模型来辅助游戏系统的设计,然后进一步提炼出参数用于关卡设定,而不是关起门来重造车轮,去修改别人已经证实可用的公式——那无异于让整个行业原地踏步。

46

主题

1586

帖子

3523

积分

论坛元老

【游戏哲学大师】

Rank: 8Rank: 8

积分
3523
QQ
发表于 2013-7-22 14:33:38 | 显示全部楼层
猴子~不带复制黏贴的~

点评

什么复制黏贴?  发表于 2013-7-22 17:28

0

主题

30

帖子

411

积分

中级会员

Rank: 3Rank: 3

积分
411
发表于 2013-7-22 18:40:43 | 显示全部楼层
线段(1,1)(10,10) 和 射线(6,5)朝x轴正方向,用你的算法
ax bx一个比m大,一个比m小;并且ay by没有同时大于5也没有同时小于5,于是这两个就相交了?

多边形相交那个算法
两个正三角形,一个正着放,一个倒着放,中心重叠起来。每个三角形的每个点都不在另外一个三角形的内部。这两个三角形就不相交了?

这帖子也就 射线法求解点是否在多边形内 这一个有价值的东西,结果子问题(怎么判断射线和线段相交)还搞错了。数值策划就好好搞数值完了,总拿些程序的算法东西来忽悠人。其他策划“学”了,到时候拿着一个不太合理甚至不正确的算法,还振振有词的说这是数值设计,那还怎么沟通?

回到问题本身。点是否在多边形内部,用有向角的方法最简单明了,也好理解,有兴趣的可以baidu下。多边形相交,只有一部分可以转化为 点在多边形内部的问题,还有些转化成线段相交。凹凸多边形要分分清楚。有本书叫算法导论,里面很详细,程序倒是可以去学习下。

最后的大道理说得很漂亮,其实大道理一直都很漂亮,但帖子还是需要有料的,而且是正确的料。

32

主题

782

帖子

1772

积分

金牌会员

吐槽机器

Rank: 6Rank: 6

积分
1772
QQ
发表于 2013-7-22 19:28:41 | 显示全部楼层
一直不觉得lz是所谓的策划...

46

主题

1586

帖子

3523

积分

论坛元老

【游戏哲学大师】

Rank: 8Rank: 8

积分
3523
QQ
发表于 2013-7-22 22:01:15 | 显示全部楼层
terrybiff 发表于 2013-7-22 19:28
一直不觉得lz是所谓的策划...

策划是策划,偏向于程序的策划

2

主题

167

帖子

670

积分

高级会员

Rank: 4

积分
670
发表于 2013-7-22 22:48:34 | 显示全部楼层
现在都3D物理碰撞时代了。。。。     有现成的算法不用,没必要自创算法吧

点评

3D只在渲染层,我们的游戏虽然画面是2D的,但渲染还是3D的算法,逻辑和渲染要区分开,很多项目设计问题在于“所见即所得”这种玩家心态。  发表于 2013-7-22 23:38

98

主题

784

帖子

4493

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4493
 楼主| 发表于 2013-7-22 23:37:32 | 显示全部楼层
daofeng 发表于 2013-7-22 18:40
线段(1,1)(10,10) 和 射线(6,5)朝x轴正方向,用你的算法
ax bx一个比m大,一个比m小;并且ay by没有同时大 ...

嗯,的确这个点与线段的算法不对了,今天也在一些细节上遇到了这个问题了,这个必须修正下,不过如果采用标准的算法,用这个思路算2个多边形碰撞效率就不占优势了,只有点与多边形的算法是一种优化了。
这个射线算法是没错的,之前工作非常完美,并且起到了优化的做用,但是在射线到线段算法中出现的问题,导致了一些原本可以走得地方掉下去了,这个BUG我现在已经修复了。这里的算法实际价值在于优化,你提供的那个算法在一开始就被采用,其效率远低于Flash自带的碰撞,而用上这个算法后极限情况下FPS提高达到1.6,所以推荐这个算法,其实就是核心的射线与多边形边相交算法,这个算法的好处是忽略凸多边形和凹多边形问题,大多时候因为要将凹多边形分为多个凸多边形会产生很多问题,这也是策划不了解程序实现导致在后期效率上放弃多边形做法的核心原因。
策划Coding逻辑代码其实不算稀奇,10年前就流行了……别因为现在的策划大多没这能力就认为不该如此,能力不足的地方要虚心补足,而不是认为毫不重要,并且四处传播说的很不重要,就如我现在在学Flash弄动画等很多东西一样,原来不会的,现在还是得学啊。

98

主题

784

帖子

4493

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4493
 楼主| 发表于 2013-7-23 00:15:19 | 显示全部楼层
本帖最后由 猴与花果山 于 2013-7-23 00:21 编辑
daofeng 发表于 2013-7-22 18:40
线段(1,1)(10,10) 和 射线(6,5)朝x轴正方向,用你的算法
ax bx一个比m大,一个比m小;并且ay by没有同时大 ...

另外关卡内确实没有三角形碰三角形的问题,所以忽略了你这个问题,不过从数学的角度上来说我还是得承认这是个错误,只能说在运用中的偶合导致结果是正确的,因为角色目前每帧都是至少4边形的。
另外高调进行批评的同时,有没有实际一点的料?比如一个不用除法和if 90度的射线与线段相交的算法?不用除法效率会提高5、6倍,现在很大的问题是海量的循环运算,即使对逻辑层使用了卡马克,由于屏幕区域很大(页游),导致多边形数量很多(因为设计需要多边形区域是允许重叠的),并且每帧角色、地形的多边形形状、位置都在变化(移动地形以及移动地形会拖着角色移动等因素),所以效率是眼下最头疼的一块啊。补充一点,这个问题最要命的还是,这是一个像素级的运算,因为我们在地图上很可能会出现一个地区宽度窄的以至于低于角色的移动速度,但他的高度却高过了角色的“爬坡力”因此事实上这个角色是无法穿越的,如果用偷懒的做法仅检查x方向上的终点,就会出现问题。虽然是一些挺简单的几何问题,但是到了要优化的程度上就显得这么麻烦,所以说数值设计不好干,建立一个高效的数值模型真心不容易。

0

主题

30

帖子

411

积分

中级会员

Rank: 3Rank: 3

积分
411
发表于 2013-7-23 00:38:30 | 显示全部楼层
策划写代码见仁见智了,我有时候也写一些,但是谁来优化,谁来改bug?你如果不能负责到底,那就别瞎折腾。写写demo,提提思路就完了。

你这两个算法根本就是错的,不是什么bug不bug的问题。至于效率,都是o(n)和浮点数乘法运算,有啥区别。还我提的一开始被采用。。。我根本就没提具体的怎么解决多边形相交,你采用了我什么算法?凹凸多边形我就随口一说,这是解决多边形问题的最基本的一个边界条件,实际上你的射线法确实可以不区分凹凸,只不过你除了这个名词相关的思路(奇数偶数个交点啥的)正确,其他的都错了



98

主题

784

帖子

4493

积分

版主

Rank: 7Rank: 7Rank: 7

积分
4493
 楼主| 发表于 2013-7-23 00:49:16 | 显示全部楼层
daofeng 发表于 2013-7-23 00:38
策划写代码见仁见智了,我有时候也写一些,但是谁来优化,谁来改bug?你如果不能负责到底,那就别瞎折腾。 ...

这还真不是浮点数算法,浮点数就没这么痛苦了,像素级别不用向量的运算都是Int的……
我说的算法思路是你的那个有向角,之前我其实也不知道,只是听人提了一下,被我们老大否决了,认为是效率问题对优化无好处,所以看你说了这么个名词,就眼前一亮了。
这种所谓的bug,其实就是优化过盛的表现,很多时候写代码很容易为了优化而“特殊处理”一些数学问题,最后在一些边际问题上出了岔子了,虽说数学运算效率不是很大的问题,但是能避免不必要的除法还是很关键的,而且尽量少些if的好,能一次数学运算完成就最好。
所以说还是希望你能提供些思路,我现在很苦闷,FPS始终在28-32浮动,目标是40,这简直要命了,挖空心思想了这么些优化的办法。写代码的问题我们这里现在就是这样的,策划必须完整的完成程序项目(事实上我们的策划包括我在内都是做过程序员的,还有些世界级项目的Coding经验),因此会涉及到这个优化问题。而底层引擎的研发是程序的工作,我们会在适当的机会,把这个haxe的entity system系统公开与大家共享的(需要经历更多的项目考验,目前修修补补挺多)。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-5-2 23:20

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表