三国群英2吧 关注:46,262贴子:1,019,117

回复:【脚本基础教程】第七章:物理引擎(地火 / 地焰涌 / 地焰星燃)

只看楼主收藏回复

楼主能力很强 但是如果想把知识推广的话感觉还是很难 只能照抄一些武将技 我有一个不成熟的小建议 楼主可以把群2里的所有武将技的源码转译成教程里的风格的代码 让吧友自己去琢磨 我看了magic structured点cpp那个文件 真的看不懂


IP属地:日本19楼2020-03-29 14:39
收起回复
    更进一步地,群2中的重力是任意z轴方向上的加速度的一般形式;这是因为我们可以手动指定重力的大小和方向。我们使用SetObjectGravity函数来设置重力的大小:
    void SetObjectGravity (int object, int gravity);
    其中,gravity指定了重力的大小,gravity为正时重力竖直向下,为负时重力竖直向上。
    默认情况下,重力的大小为40960。读者可能已经看出,它的单位和位置、速度的单位都不一样;事实上,重力的大小是比较特殊的,它是每32768等于1点重力加速度(即1像素每Tick平方,或每Tick速度变化1点),也就是65536(0x10000)等于2点重力加速度。因此,默认情况下,重力加速度的大小为1.25。
    我们来实际操作一下调整重力的方法。我们先来看OF_NOGRAVITY标记的效果。在ThrowLava函数中,我们使用SetObjectHasGravity函数,指定火球没有重力:
    //创建熔岩弹
    int lavaSplit = CreateObjectRaw(centerX, centerY, 0, 0, 43004);
    //按照给定的三维方向和初速度掷出
    SetObjectSpeed_Sphere(lavaSplit, dir, phi, initSpeed);
    // 设置熔岩弹没有重力
    SetObjectHasGravity (lavaSplit, 0);


    从结果上看,毫不意外地放起了烟花:

    接着,我们恢复OF_NOGRAVITY标记,但是将重力的值调为一个比较小的数:
    //创建熔岩弹
    int lavaSplit = CreateObjectRaw(centerX, centerY, 0, 0, 43004);
    //按照给定的三维方向和初速度掷出
    SetObjectSpeed_Sphere(lavaSplit, dir, phi, initSpeed);
    // 设置熔岩弹的重力
    SetObjectHasGravity (lavaSplit, 1);
    SetObjectGravity(lavaSplit, 5000);
    得到了另一种形式的烟花:这一次它们都在远处落了下来。

    最后,我们将重力值稳定下来,设置为0x10000的十分之三(等价于0.6像素每Tick平方):
    //创建熔岩弹
    int lavaSplit = CreateObjectRaw(centerX, centerY, 0, 0, 43004);
    //按照给定的三维方向和初速度掷出
    SetObjectSpeed_Sphere(lavaSplit, dir, phi, initSpeed);
    // 设置熔岩弹的重力
    SetObjectHasGravity (lavaSplit, 1);
    SetObjectGravity (lavaSplit, 0x10000* 3 / 10);


    (细心的读者可能已经注意到,加速度的大小可以是小数,这意味着速度的大小也可以是小数。事实上,底层上,物件的x/y/z速度确实可以为小数,它和屏幕x/y/z坐标有着类似的逻辑:它是一个int型变量,以高2位为整数部分,以低2位为小数部分,因此在内存中1点速度会被储存为0x10000.)


    IP属地:美国本楼含有高级字体20楼2020-03-29 14:40
    回复
      2026-05-06 18:45:49
      广告
      不感兴趣
      开通SVIP免广告
      六、阻力
      除重力外,另一个加速度维度是阻力。当阻力加速度为正数时阻力加速度的方向永远与当前速度的方向反向。在三国2脚本中,我们使用SetObjectFriction和SetObjectFriction1两个函数指定物件受到的阻力加速度大小:
      void SetObjectFriction (int object, int friction);
      void SetObjectFriction1 (int object, int frictionTimes0x10000);
      阻力的单位是正常的单位:1点阻力就等于1点加速度,也即1 Tick中速度减小1点。不过,和重力加速度一样,1点阻力实在是太大了,只能设置整数的阻力是很不方便的;因此,三国2脚本提供了另一个函数SetObjectFriction1,它的参数中0x10000(65536)等价于1点阻力加速度,这使得我们可以设置非整数的阻力大小。例如,当设置为0x10000 / 2时,即为0.5点阻力。
      我们的武将技中不会涉及阻力。不过,为了演示阻力的作用,我们仍然会利用目前的代码,并且,这一部分代码中的一部分将会保留下来。
      我们希望当火球落地,开始向四面八方滚动时,火球会慢慢受到地面摩擦力的作用而停下来。为了实现这一点,我们另外编写一个函数监测每个火球的z坐标,并在火球落地后,设置火球的阻力为三分之一:

      这里的do...while是有意为之。因为在刚抛出火球时,火球的z坐标刚好是0,因此需要等1 Tick,等到火球飞起来之后再检查z坐标。
      在ThrowLava函数中,每抛出一个火球,我们就异步调用调用一次TraceLavaSplit函数,这样就确保了每个火球都有一个函数正在监测:

      编译运行。可以看到,地面上的火球在滚动中迅速放慢,最后停下来了。

      阻力加速度也可以被设置为负数,此时表现为加速。


      IP属地:美国本楼含有高级字体21楼2020-03-29 14:46
      回复
        度娘又开始吞帖了。暂缓更新,明天再贴完。


        IP属地:美国23楼2020-03-29 14:54
        回复
          3级地火清兵杠杠的


          IP属地:江苏来自手机贴吧24楼2020-03-29 15:01
          回复
            七、OF_BOMB和OF_TARGET标记



            IP属地:美国本楼含有高级字体25楼2020-03-30 05:19
            收起回复
              八、实例推进:爆卝炸和熔岩池
              下一步是让火球落地时产生爆卝炸效果,并产生一个岩浆池。我们直接改写第六节中侦听火球落地的代码。
              当火球落地时,我们总共需要做四件事:
              1. 销毁火球物件;
              2. 当第一颗火球落地时,制造一个“岩浆池”,并给岩浆池加上打击目标;
              3. 当最后一颗火球落地时,制造一个“爆卝炸效果”物件,并给该物件加上打击目标;
              4. 一段时间后,销毁爆卝炸效果和岩浆池。
              我们将用到以下物件:
              1. 爆卝炸效果物件,复制自龙炮系,但删除了其中播放声音的部分:
              [OBJECT]
              Name = 爆卝炸
              Sequence= 11540
              Type = %TYPE_FORCE
              Space = 0,0,0,0
              Flags = OF_NOGRAVITY,OF_WHITELIGHT
              Process = %MagicObjectProcess
              Directory = \magic\033
              Wait = #2, m033bomb01a,m033bomb01a, #10, m033bomb01b, m033bomb01c, #9999
              2. 岩浆池物件,它和地裂效果一样是一组2个物件,总共6组,编号为11521-11526和11531-11536:
              [OBJECT]
              Name =池01
              Sequence= 11521
              Type = %TYPE_FORCE
              Space = 0,0,0,0
              Flags = OF_DARKLIGHT
              Process = %MagicObjectProcess
              Directory = \magic\115
              Wait = #9999, pool01
              [OBJECT]
              Name =池內岩漿01
              Sequence= 11531
              Type = %TYPE_FORCE
              Space = 0,0,0,0
              Flags = OF_WHITELIGHT
              Process = %MagicObjectProcess
              Directory = \magic\115
              Wait = #9999, poollava01
              3. 覆盖在岩浆池上的“火苗”,使用了很多原版武将技都带有的火苗物件:
              [OBJECT]
              Name = 地板火
              Sequence= 11541
              Type = %TYPE_FORCE
              Space = 0,0,0,0
              Flags = OF_WHITELIGHT,OF_NOGRAVITY
              Process = %MagicObjectProcess
              Directory = \magic\018
              Wait = #5, M018ManFire1,M018ManFire2, M018ManFire3, M018ManFire2


              IP属地:美国本楼含有高级字体26楼2020-03-30 05:23
              回复
                我们将TraceLavaSplit函数改写为如下所示。除了开头的等待火球落地部分外,剩下的部分都是新增的代码。

                代码看上去比较多,但实际上逻辑很清晰。当第一颗火球落地时,制造地板火,并制造地板火的杀伤;从这一刻开始,制造地面上的岩浆池,并让其在6 Tick内从零放大到原始大小的一半;6 Tick后,正好最后一颗火球落地,此时直接产生爆卝炸效果。爆卝炸效果在26 Tick后淡出,熔岩池和地板火则在66 Tick后淡出。为爆卝炸效果物件和地板火物件指定杀伤目标后,使用和地裂喷发处的主火焰同样的GroundFireCallback回调函数,指定调用代码11501.


                IP属地:美国27楼2020-03-30 05:29
                回复
                  2026-05-06 18:39:49
                  广告
                  不感兴趣
                  开通SVIP免广告
                  编译运行。可以看到火球落地时形成的岩浆池效果、岩浆池上的火苗和爆炸效果。


                  IP属地:美国28楼2020-03-30 05:33
                  回复
                    九、全局变量


                    IP属地:美国本楼含有高级字体30楼2020-03-30 05:46
                    回复
                      扛不住了,发一条吞一条。 继续让度娘冷静一会儿再说。


                      IP属地:美国33楼2020-03-30 06:03
                      回复
                        很有创意的技能,太极门+龙炮的结合体


                        34楼2020-03-30 10:30
                        回复
                          十、多级武将技的打击目标
                          我们还没有设计多级武将技。目前,主函数中level这个参数从来没有用到过,不管使用的是R115、R116还是R117,都只有一个地裂喷发点。我们来着手增加多个地裂喷发点。
                          首先,由于我们希望多个喷发点同时喷出熔岩弹火球,因此每一个喷发点抛射火球的循环都是独立异步运行的。于是,我们将创造地裂和抛射火球的部分,移到一个专门的函数CreateVolcano中:


                          IP属地:美国本楼含有高级字体35楼2020-03-31 03:56
                          回复


                            IP属地:美国37楼2020-03-31 04:05
                            回复
                              2026-05-06 18:33:49
                              广告
                              不感兴趣
                              开通SVIP免广告
                              紧接着是主函数。之前我们提到过,为了使问题简化,我们直接连续多次将武将技的打击目标点对准人堆;因此,这部分代码的修改就非常简单了,后续跟着的第2次和第3次地裂,获取打击目标点的方法和第1次完全相同。我们将仍然留在主函数内的寻找打击目标、平移摄像机相关代码用一个for循环套起来,并增加对CreateVolcano函数的异步调用:

                              为什么是68?因为MoveCamera移动摄像机用时12 Tick,加上68就是80 Tick。80 Tick等于下文中地震音效循环一次的时间——这样正好契合。
                              我们将主函数中一直留着的Delay(200)删除,也改为使用Wait语句等待所有火球落地和岩浆池消失:
                              // 等待所有地火落地,岩浆池消失
                              Wait("TrаceLаνаSplit");
                              Delay(20);


                              这样就完成了。


                              IP属地:美国本楼含有高级字体38楼2020-03-31 04:09
                              收起回复