三国群英2吧 关注:46,108贴子:1,017,520

回复:【脚本基础教程】第四章:图形与战场(武将技:大喝)

只看楼主收藏回复

五、缩放、透明度和手动动画
下一个问题是怎么让这个光圈动起来。我们希望它能够在武将技施放后迅速扩大、变透明,完成气圈向外冲击并最终逸散的效果。
我们可以用SetObjectScale函数来设置物件的缩放大小
void SetObjectScale (int objectHandle, int xScale, int yScale);
其中,scale以65536(0x10000)为原大小。因此,32768(0x8000)为二分之一大小,131072(0x20000)为两倍大小。
关于不透明度,我们可以用SetObjectOpacity函数来设置:
void SetObjectOpacity (int objectHandle, int nOpacity);
(该函数曾经的命名为SetObjectBrightness(“亮度”),该命名是注册带来的遗留问题之一。实际上由奥汀钦定的DownBrightness和RaiseBrightness两个函数名可知,“亮度”一般指的是背景亮度;何况,一个物件如果亮度为100%,理应全白才对。目前两个函数名都可以使用,并且具有同等作用。)
不透明度以16为100%(不透明),以0为0%(完全透明)。
知道怎么设置缩放和透明度之后,接下来的问题就是如何创建动画效果。在这里,我们用一种“土办法”来手动创建动画:我们用一个循环,让程序每过1 Tick就放大一次物件,并降低一次不透明度。

这里,每个循环中,我们都改变一次物件的属性:我们让这个物件每Tick放大原图的十六分之三倍,并且不透明度下降100%的十六分之一。Delay(1)使得一次循环的用时为1 Tick,避免程序不间断地把循环直接运行完,这样会让显示效果“一步到位”,直接显示最终的情形——此时不透明度已经归0,什么都显示不出来了。
手动动画是一种很常用的方法,我们之后会频繁地使用这种方法。从原理上说,这种做法类似于制作动画时一帧一帧地作画,改变物件的大小、透明度、位置等属性,只不过我们是使用代码来完成的而已。
最后,我们用以下函数销毁物件
void FreeObject (int object);


IP属地:美国本楼含有高级字体18楼2020-03-14 13:18
回复
    类似虎咆,虎咆开局还有点用,等级出来基本不用了,不如这个作用直接做在武将对砍中有意思,和群3一样,强将在对砍中几率会大喝什么的,有攻击加成。


    IP属地:江苏19楼2020-03-14 13:23
    收起回复
      2026-03-17 20:39:05
      广告
      不感兴趣
      开通SVIP免广告
      完整代码现在如下(红色表示新增部分):


      IP属地:美国20楼2020-03-14 13:23
      回复
        编译运行结果如下图。读者实际运行时,可以观察到动画效果。


        IP属地:美国21楼2020-03-14 13:27
        回复
          六、根据战场坐标获取士兵和主将
          有了显示效果,下一步就是造成实际的武将技杀伤效果了。在这里我们用一个简单的办法,即总是杀伤周围一圈的8个士兵。
          我们用KillForce函数杀死指定的士兵或主将:
          void KillForce(int forceHandle);
          为了获取相应战场坐标的士兵,我们用GetForceHandleByXY函数:
          int GetForceHandleByXY(int battleX, int battleY);
          因此,我们只需先得到主将的战场X/Y坐标,然后遍历周围一圈的战场坐标,将各个坐标位置的士兵杀死即可。不过,有两个例外:
          (1) 不能杀死自己人;
          (2) 不能直接杀死正在单挑中的敌方主将,需要改为对主将造成伤害。
          为了避免杀死自己人,我们用GetForceSide系统函数得到士兵物件或主将物件的所属方;和intvIsLeft预设变量一样,以0为右方,1为左方。我们只需将该所属方和intvIsLeft比较即可。
          为了检查是否是对方主将,我们直接将物件和intvDefenderMajor预设变量进行比较,该变量是武将技施放方的对方武将;然后,我们用DoHarmToMajor函数打出伤害。武将技伤害的值可以被Magic点ini指定,它存储在intvMagicAttackValue预设变量中。
          (是的,您可能已经猜到为什么神鬼乱舞的伤害如此“固定”,很难通过改INI改变:这是因为奥汀的程序员把很多伤害数值写死在代码里了。)
          用到的这两个函数的定义如下:
          int GetForceSide (int forceHandle);
          void DoHarmToMajor (int defenderHandle, int attackerHandle, int harm);


          IP属地:美国本楼含有高级字体23楼2020-03-14 13:35
          回复
            于是我们得到如下代码。我们用一个双重for循环遍历主将周围(-1, -1)到(1, 1)区域内的所有格子;这个过程会扫过主将自身,但是主将也算自己人,所以不会造成杀伤。


            IP属地:美国24楼2020-03-14 13:39
            回复
              最后,出于“美观”的目的,我们希望能听到武将的“大喝”一声。读者可以在本教程的源代码和素材文件(见目录贴)中,src/sound文件夹下,找到相应的素材ROAR01点wav和ROAR02点wav。这是从群7获取的音效,分男女声。将它们放入游戏目录下的SOUND文件夹。
              我们可以用PlaySound函数“有源”地播放声音:
              void PlaySound (int sourceHandle, stringsoundFileName, int volume);
              其中第一个参数指定了声音的源头物件,第二个参数指定了声音文件的文件名(不包括.wav扩展名,也不包括SOUND路径名;声音文件应总是在SOUND文件夹下),第三个参数以255为最大声,0为无声。
              我们还可以用PlaySound1函数“无源”地播放声音,此时没有声音源头的参数:
              void PlaySound1 (string soundFileName, intvolume);
              有源和无源的区别是,有源的声音只有当镜头对准声音源的物件时才最大,而无源的声音无论镜头对准哪里都一样大。
              在这里,由于武将技施放时镜头总是对准主将,因此有源无源没有什么差别。因此我们只需要调用PlaySound1函数即可(暂时忽略男女声问题):
              PlaySound1("Roar01", 255);


              IP属地:美国本楼含有高级字体25楼2020-03-14 13:43
              回复
                武将技“大喝”的完整代码


                IP属地:美国本楼含有高级字体26楼2020-03-14 13:49
                回复
                  2026-03-17 20:33:05
                  广告
                  不感兴趣
                  开通SVIP免广告

                  成功!我们制造出了第一个“像样”的武将技。
                  在下一章中,我们将介绍摄像机和显示标记(Flags)。本章中我们已经介绍过直接设置摄像机的方法,下一章我们将完整介绍所有与摄像机有关的内容。此外,我们将介绍标记的相关内容;不过,事实上,由于不同的标记有不同的功效,下一章将主要介绍显示类标记,其余标记将在后续章节中介绍。


                  IP属地:美国本楼含有高级字体27楼2020-03-14 13:52
                  回复


                    IP属地:美国29楼2020-03-14 14:01
                    回复
                      本章引入的系统函数和官方函数
                      // 战场与屏幕坐标转换函数
                      int BattleXToScreenX (int battleX); //战场X转屏幕X
                      int BattleYToScreenY (int battleY); //战场Y转屏幕Y
                      int ScreenXToBattleX (int screenX); //屏幕X转战场X
                      int ScreenYToBattleY (int screenY); //屏幕Y转战场Y
                      // 战场长宽
                      int GetBattleWidthInScreenX (); // 返回6816
                      int GetBattleHeightInScreenY (); // 返回1008
                      int GetBattleWidth (); // 返回71
                      int GetBattleHeight (); // 返回14
                      // 创建图形物件(直接指定坐标)
                      int CreateObjectRaw (int x, int y, intz, int nDir, int dwSequence);
                      // 创建图形物件(根据参照物坐标)
                      int CreateObjectByReference (intreferenceObjectHandle, int dwSequence, int nDir, int zOffset);
                      // 销毁物件
                      void FreeObject (int object);
                      // 得到物件屏幕坐标
                      int GetObjectScreenX (int object);
                      int GetObjectScreenY (int object);
                      int GetObjectScreenZ (int object);
                      // 设置物件屏幕坐标
                      int SetObjectCoordinate (int object, int x, int y, int z);
                      // 得到物件战场坐标
                      int GetObjectBattleX (int object);
                      int GetObjectBattleY (int object);
                      // 获得指定战场坐标处的士兵或主将
                      int GetForceHandleByXY(int battleX, int battleY);
                      //==============================================================
                      // 设置物件的动画序列
                      void SetObjectAnimate (int objectHandle, int nAnimationSequence);
                      // 设置物件缩放大小
                      void SetObjectScale (int objectHandle, int xScale, int yScale);
                      // 设置物件不透明度
                      void SetObjectOpacity (int objectHandle, int nOpacity);
                      //==============================================================
                      // 禁止和允许双方进行操作和施放武将技
                      void DisablePlayMagic ();
                      void EnablePlayMagic ();
                      // 设置或取消主将的无敌状态(只对主将有效)
                      void SetOverwhelming (int majorHandle, int isOverwhelming);
                      // 让士兵或主将定身;1点interval等于40 Tick
                      void AddAttackCounter (intforceHandle, int interval);
                      // 获得士兵或主将的所属方
                      int GetForceSide (int forceHandle);
                      // 杀死士兵或主将
                      void KillForce(int forceHandle);
                      // 对主将造成伤害
                      void DoHarmToMajor (int defenderHandle, int attackerHandle, int harm);
                      //==============================================================
                      // 设置摄像机的位置
                      void SetViewCamera (int x, int y);
                      // 播放声音(有源和无源)
                      voidPlaySound (int sourceHandle, string soundFileName, int volume);
                      voidPlaySound1 (string soundFileName, int volume);
                      //==============================================================
                      // 天空变黑和变亮(magic点cpp)
                      void DownBrightness (int targetBrightness, int timePerUnit);
                      void RaiseBrightness (int targetBrightness, int timePerUnit);


                      IP属地:美国本楼含有高级字体30楼2020-03-14 14:04
                      回复


                        IP属地:美国31楼2020-03-14 14:21
                        回复
                          远帆提个意见好吗?你这个放一个帖子好一点,大家也方便找。


                          IP属地:广东来自Android客户端32楼2020-03-14 14:37
                          收起回复
                            你是不是在学校里学过这类课程,好深奥,快赶上程序猿了


                            33楼2020-03-14 15:17
                            收起回复
                              2026-03-17 20:27:05
                              广告
                              不感兴趣
                              开通SVIP免广告
                              请问大佬,现在这种自创武将技或者组合武将技的方法能压技吗?


                              IP属地:加拿大来自Android客户端34楼2020-03-14 16:45
                              收起回复