三国群英2吧 关注:46,380贴子:1,020,250

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

取消只看楼主收藏回复

五、缩放、透明度和手动动画
下一个问题是怎么让这个光圈动起来。我们希望它能够在武将技施放后迅速扩大、变透明,完成气圈向外冲击并最终逸散的效果。
我们可以用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
回复
    完整代码现在如下(红色表示新增部分):


    IP属地:美国20楼2020-03-14 13:23
    回复
      2026-06-25 12:23:07
      广告
      不感兴趣
      开通SVIP免广告
      编译运行结果如下图。读者实际运行时,可以观察到动画效果。


      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
              回复

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


                IP属地:美国本楼含有高级字体27楼2020-03-14 13:52
                回复
                  2026-06-25 12:17:07
                  广告
                  不感兴趣
                  开通SVIP免广告


                  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
                      回复