东方吧 关注:660,705贴子:18,042,096
  • 28回复贴,共1

【弹幕程序科普计划】 第11篇 判定逻辑

只看楼主收藏回复


【判定逻辑】
  在弹幕游戏中,有诸多物体需要发生判定关系,自机、敌弹、敌机、Boss、自机子弹、Spell(Bomb)、道具等等,那么这些判定关系在程序里怎么描述,判定代码写在哪里,会牵涉到什么问题,这些就是本次科普的内容。
  早在本系列第二篇的时候,讲到过游戏中物体叠放次序的问题。其实这就已经明确了一件事情,在游戏里这些物体应该分类管理。比如建立单独一个列表来存放子弹,单独一个列表来存放敌机,单独一个列表来存放特效。将所有物体分类存放主要有两个目的,一个是为了控制叠放次序,另一个是为了实现判定逻辑。
首先,先来罗列一下游戏里所有的判定关系:
1. 敌弹与自机
2. 敌机与自机
3. Boss与自机
4. 自机子弹与敌机
5. 自机子弹与Boss
6. Spell与敌弹
7. Spell与敌机
8. Spell与Boss
9. 道具与自机
  以上总共9项是比较常用而且必须要有的判定项目,至于判定了要做什么,应该不用讲吧。。。此外,还有一些特殊情况也需要判定,比如自机接触到符卡名字、Boss血条等UI元素时,UI透明度要降低,这种也需要判定逻辑,不过原理都不复杂,这里就不一一例举了。
  我相信,类似于“两点间距离是否小于指定值”这种逻辑大家肯定都会写,以下重点问题在于这些判定代码写在哪里比较合适。当然,不管写在哪里,肯定是属于数据处理环节(在上两次文章提到过,游戏有输入捕捉、数据处理、画面显示这三个环节)。对于初学者来说,可能会有疑问的地方在于,这个判定方法应该写在全局的Update方法里,或者是建立一个管理器,来通过管理器来判断各种物体碰撞情况,还是说将判定方法和待判定物体封装在一起,在各物体的Update方法中进行判定。
  其实,我们只要了解一下这中间最关键的问题,就差不多该知道这个架构应该是怎样了。这中间最关键的问题其实在于判定形状,对于不同的物体,可能要用到不同的判定形状。举例来说,自机和敌弹判定,通常情况下,敌弹是圆的,自机判定点也是圆的,但是有一种敌弹叫做激光,可能采用椭圆判定,还有一种敌弹叫做曲线激光,判定形状更复杂。判定方法必然要描述物体的判定形状,那么就可想而知,如果将判定方法写在全局的Update方法里,或者是建立一个管理器来统一管理子弹和自机的话,就很难照顾所有的判定形状,而且如果要使用特殊形状的话也不易扩展。因此,最好还是将判定方法和待判定物体封装在一起,这其实也是将判定形状与物体封装在一起,就好比射线激光拥有椭圆形判定这个属性。
  接下来的问题是,当两个物体要判定时,究竟将判定方法和哪个物体封装在一起。举例来说,当敌弹与自机发生判定时,判定方法也该和敌弹封装在一起,还是和自机封装在一起?其实这个原则很简单,和判定形状复杂的东西封装在一起。比如说,自机和敌弹的判定应该和敌弹封装在一起,因为自机判定形状总是圆的,而敌弹则不一定,可能有激光、曲线激光或者更复杂的形状。为了能够便于重写判定形状,因此应该将判定方法和那些需要重写形状的物体封装在一起。以下罗列了所有物体判定逻辑的情况供大家参考:
1. 敌弹与自机:判定方法写在敌弹里,因为自机判定是圆的,而敌弹不一定
2. 敌机与自机:判定方法写在敌机里,因为自机判定是圆的,而敌机不一定
3. Boss与自机:判定方法写在Boss里,因为自机判定是圆的,而Boss可能出现其它形态,比如加个翅膀什么的。
4. 自机子弹与敌机:判定方法写在敌机里,因为自机子弹是圆的,而敌机不一定
5. 自机子弹与Boss:判定方法写在Boss里,因为自机子弹是圆的,而敌机不一定
6. Spell与敌弹:判定方法写在Spell里,因为各种Spell的形状大相径庭
7. Spell与敌机:判定方法写在Spell里,因为各种Spell的形状大相径庭
8. Spell与Boss:判定方法写在Spell里,因为各种Spell的形状大相径庭
9. 道具与自机:判定方法写在道具里,以便兼容不同判定形状的道具
  可以看到,虽然敌弹、敌机、Boss可能会出现不一样的形状,但是相比之下,Spell的形状更加多变,它们发生判定时,只能退而求其次,将判定方法写在Spell里,而将敌机、敌弹、Boss当成圆形判定或者点判定来处理。
  那么本次科普就到这里。下一期会介绍一下各种判定形状及其适用场合,敬请期待。
以下广告时间:
游戏《弹幕音乐绘》登陆steam绿光,各种求支持
http://steamcommunity.com/sharedfiles/filedetails/?id=886253524
本系列过往文章将收录在弹幕音乐绘的哔哩哔哩兴趣圈中,欢迎关注
http://www.im9.com/community.html?community_id=12241


IP属地:上海1楼2017-04-01 15:54回复
    可怜的妖精


    IP属地:湖北来自Android客户端5楼2017-04-01 16:06
    回复
      2025-08-21 04:36:31
      广告
      不感兴趣
      开通SVIP免广告
      支持(


      来自Android客户端7楼2017-04-01 17:06
      回复
        曲线激光。。。我觉得写成一堆点集的并应该还行。。。但还是先避开吧
        别的我觉得把圆和圆算正交,别的算嵌入面积吧,不知道行不行


        来自Android客户端8楼2017-04-01 18:24
        收起回复
          所以为啥把妖精扔出去了


          IP属地:上海9楼2017-04-01 18:26
          收起回复
            请问游戏采用什么语言写,什么平台?


            IP属地:江苏来自Android客户端10楼2017-04-02 16:05
            收起回复
              好可怜的妖精,正式版发布求个这种妖精剑补丁


              IP属地:浙江来自Android客户端11楼2017-04-02 17:16
              回复
                讲道理可以用碰撞函数
                不同的弹使用不同的碰撞箱
                符卡当作一个类对象 其中有一个函数即可


                来自Android客户端12楼2017-04-03 11:01
                回复
                  2025-08-21 04:30:31
                  广告
                  不感兴趣
                  开通SVIP免广告
                  一面小妖精被拖来做苦工


                  IP属地:辽宁13楼2017-04-03 11:28
                  回复
                    难道激光都用的椭圆(两点距离和)公式吗?
                    觉得该是点到直线公式加点到(激光起点)垂线取正负。


                    IP属地:湖北来自Android客户端14楼2017-04-03 13:40
                    收起回复
                      补充两点吧:
                      1、攻击判定可以和受击判定分开,这样就不用纠结应该封装在哪种对象里了
                      2、为了最大的可编程性,所有对象判定应当统一判断,然后再调用各个对象的方法,对象的onhit、onhitby方法传进来的应当是个数组


                      IP属地:北京来自iPhone客户端15楼2017-04-03 14:40
                      收起回复
                        跪求前贴全链接......翻记录只找到6....


                        IP属地:江西16楼2017-04-04 10:26
                        收起回复
                          我猜猜..曲线激光每帧生成一个方形判定区域,长度为激光的速度?宽度与这个区域存在的时间相关,或者是一个固定值?


                          来自Android客户端17楼2017-04-07 08:20
                          回复
                            虎摸~


                            IP属地:江苏来自iPhone客户端18楼2018-05-18 10:28
                            收起回复