三国群英2吧 关注:43,245贴子:994,349
  • 14回复贴,共1

【脚本基础教程】第八章:数组(武将技:升天)

只看楼主收藏回复

视频来自:百度贴吧


IP属地:美国1楼2020-04-12 07:07回复
    生死门?


    IP属地:天津来自Android客户端2楼2020-04-12 07:15
    回复
      挺好看的😄,加油加油加油加油


      IP属地:重庆来自Android客户端3楼2020-04-12 07:16
      回复
        本章我们介绍数组。底层上,三国2脚本支持局部、全局甚至预设变量的数组,但是到目前为止,由于全局变量和预设变量都可以按编号访问,这一部分没有实装到三国2脚本的语言特性中。因此我们只介绍局部数组。
        本章的武将技“升天”是生死门的简化版。我们直接跳过生死门的所有额外动画效果,并利用将士兵“托举”到空中的方法对敌方造成减员。“升天”和生死门相同的是,在确定了打击目标集合后,士兵死亡的顺序是随机的,并且是一个一个完成的;这意味着我们需要得到这些士兵的一个随机排列,而这是需要依赖数组这样的数据结构实现的。
        在正文开始之前,我们先配置好magic ini:
        [MAGIC]
        SEQUENCE = 118
        NAME =升天
        MP =31
        POWER =100
        ATTACK =0
        SCRIPT =807
        ATTRIB =全體
        TITLE =
        NOTE =升天,L1
        ACTIVE =敵方士兵


        IP属地:美国4楼2020-04-12 07:17
        回复
          一、定义数组
          在三国2脚本中,我们采用以下方式定义数组:
          类型 数组名[数组长度];
          其中,数组名的命名规则和变量名、函数名完全相同,并且数组名不可和局部变量重名。与C语言和Java一样,三国2脚本数组有固定的类型,数组中的每个元素都必须为相同类型。
          例如,下面的代码定义了一个长度为10的int数组,数组名为arr:
          int arr[10];
          和较古老的C语言标准类似,在三国2脚本中,数组长度必须为确定的正整数立即数,而不能以变量的值或表达式的值来指定数组长度。例如下面的做法会导致编译错误:
          int N = 10;
          int arr[N]; // 错误 – 此处应有常整数(不能使用变量指定数组长度)
          数组无法被初始化。例如,下面的写法是不支持的:
          int arr[5] = {1, 2, 3, 4, 5}; // 错误 – 不支持定义时初始化数组
          和C语言相同,数组在定义时,长度总是被附在数组名之后,而不是类型名的一部分。同样和C语言相同,可以在一行语句中定义多个同类型的变量和数组。例如,下面的代码定义了a、c两个string型变量和b、d两个string型数组:
          string a, b[10], c, d[20];


          IP属地:美国本楼含有高级字体5楼2020-04-12 07:20
          回复
            二、数组内容的访问
            定义了数组后就可以使用和修改数组中的元素了。作为多个元素组合成的一个有序的序列,数组中的元素均使用数组和变量在数组中的位置表示;这一位置通常被称为编号或下标。
            在三国2脚本中,数组下标从0开始,按0, 1, 2, ...计数。一个长度为N的数组,其下标分别为0, 1, 2, ..., N-1. 我们使用方括号来访问和修改数组的元素:
            int arr[5];
            arr[0] = 1; // 将arr数组下标为0的元素赋值为1
            数组的元素可以完全像变量那样使用;它可以作为表达式的一部分。例如:
            arr[3] = arr[0] + 2; // 将arr[3]赋值为表达式arr[0] + 2的结果
            和定义数组时指定数组长度的情况不同,数组的下标可以为表达式,并不仅仅局限于立即数(否则数组就没有存在的意义了)。例如,下面的代码制造了一个长度为10的斐波那契数列{1, 1, 2,3, 5, 8, 13, 21, 34, 55},其中我们用表达式 i - 1 和 i - 2 作为数组的下标:

            注意:和C语言一样,三国2脚本在编译时和运行时都不会检查数组越界,亦即指定的下标值超出数组长度允许的范围之情形。当数组发生越界时,可能会影响到其它不相关的局部变量,甚至发生难以预料的后果,因此请务必小心。
            (此外,如果您对指针操作感兴趣,有一点需要注意:三国2脚本中的“指针”指向的是EXE运行时的内存地址,通常而言,它无法(也不该)被用来指向任何当前代码中的局部变量、数组或全局变量。因此不存在把数组名当成指针使用的做法。)


            IP属地:美国本楼含有高级字体6楼2020-04-12 07:23
            回复
              三、将武将技打击目标储存在数组中
              读者可能已经知道,生死门武将技有一个特点:它总是倾向于打击敌方最靠前的士兵。在magic点cpp中,奥汀提供了专门的函数用来获取此类打击目标:
              int GetSoldierMaxX (int isLeft);
              int GetSoldierMaxX2 (int isLeft);
              这两个函数都是用来获取isLeft指定的敌对方最靠前的士兵的屏幕X坐标的(亦即,当指定isLeft为1时,获取的实际上是玩家方最靠前的士兵的X坐标)。唯一的区别是,GetSoldierMaxX在获取不到士兵时会返回敌方主将的屏幕X坐标,而GetSoldierMaxX2在这种情况下会返回-1.
              需要注意的是:由于奥汀自己没有提供遍历全场士兵的系统函数,该函数的实现是通过在战场上随机抽取N/2 + 1次士兵,取其中最靠前者的方法(N为敌对方士兵总数)。因此,它们并不能保证总是返回最靠前的士兵;它只是大概率返回靠前的士兵而已。
              我们也可以照章办理。在我们的武将技中,首先判断对方有没有士兵,如果有,就获取最靠前的士兵的屏幕X坐标,并转换为战场坐标:

              紧接着,我们使用上一章介绍的GetForceCountInRect函数,得到以该坐标为中心,两侧各9格以内的所有各列中的敌方士兵和主将总人数:

              下一步,我们将使用GetNthForceInRect函数,一个一个地获取作为目标的所有士兵。我们将所有这些士兵储存在一个名为targets的数组内:

              在上面的代码中,我们通过循环指定i,获取矩形范围内所有敌方士兵和主将。我们将得到的物件和预设变量intvDefenderMajor比较,如果不是主将则放进数组中;我们用变量j指定当前targets数组中第一个空余的位置,每次有新的士兵,我们都将士兵物件放在j下标的位置,然后令j自增1。
              最后,我们重新利用了targetCount变量,令其等于区域内的总士兵数,而不是士兵和主将的总人数。由于j是最后一个空位,之前恰好有j个士兵(下标为0到j-1),因此我们直接令targetCount = j.
              我们暂时结束这个大的if分支,即对方场上仍有士兵的情况。当对方场上没有士兵时,我们使用CastFail函数,在给定的主将头顶召唤一口铁锅(dir指定了铁锅的方向,通常情况下,和主将的方向相同):
              void CastFail (int majorHandle, int dir);
              具体代码如下:


              IP属地:美国本楼含有高级字体7楼2020-04-12 07:30
              回复
                目前的整体代码如下:


                IP属地:美国8楼2020-04-12 07:36
                回复
                  四、随机排列和手动调整速度
                  为了生成随机的排列,我们应用一个被称为费雪-耶兹洗牌算法(Fisher-Yates shuffle)的方法。这个算法很简单:对于从0到N-2的各个元素,我们都从其后的所有元素中随机挑一个,将其和该元素交换位置。
                  我们接着上面的代码,在“未完待续”处,继续写下:

                  这段逻辑很简单。对于每个给定的i,下标j的随机取值范围在[i+1, N-1]范围内,即i之后的所有可能的下标;紧接着,我们借用temp变量,将targets数组中i下标位置的士兵和j下标位置的士兵交换。如此对i从0到N-1循环一次,我们就生成了一个随机的排列。
                  紧接着,我们将摄像机平移到一个随机的目标士兵身上,下标在[0, N-1]之间随机取值,然后播放生死门的音效:

                  摄像机对准目标后,对于这个士兵的随机排列顺序,我们从头到尾逐个将士兵减员(升天),减员的时间间隔也是随机的:

                  这样我们的主函数就完成了。


                  IP属地:美国本楼含有高级字体9楼2020-04-12 07:43
                  回复
                    升天函数看上去很简单。但是,有一个坑的地方:士兵死亡后,EXE会对士兵进行抛出动作,此时会设置物件的重力和阻力,不能通过设置重力/阻力的方法一次搞定。因此,我们通过循环的方式,手动调整物件的速度进行“加速”。
                    此外,在无重力的情况下,士兵阴影淡出的用时要更长,因此,需要手动调整透明度进行淡出动作。
                    具体代码如下:


                    IP属地:美国10楼2020-04-12 07:49
                    回复


                      IP属地:广东11楼2020-04-12 07:54
                      回复
                        武将技“升天”的完整代码



                        IP属地:美国本楼含有高级字体12楼2020-04-12 07:55
                        回复

                          本章引入的系统函数和官方函数
                          // 获得对方靠前的士兵的屏幕坐标;参数为我方的所属方(magic点cpp)
                          // 当没有兵时MaxX返回对方主将,MaxX2返回-1
                          int GetSoldierMaxX (int isLeft);
                          int GetSoldierMaxX2 (int isLeft);
                          // 对指定主将天降铁锅(magic点cpp)
                          void CastFail (int majorHandle, int nDir);


                          IP属地:美国本楼含有高级字体13楼2020-04-12 07:58
                          回复
                            这个效果能做成,天上一个星空黑洞,或者太极图,把士兵吸进去吗,


                            IP属地:重庆来自Android客户端14楼2020-04-23 09:03
                            收起回复