i_wanna_be_the_guy吧 关注:62,597贴子:1,118,575
  • 19回复贴,共1

开个帖子写点关于做耐久的东西

只看楼主收藏回复

大概是看到wym的帖子受到了一点启发.
确实国内的耐久作者太少了,就我了解还是有不少人想做耐久不会做的,希望这点东西能帮到忙吧.


1楼2020-11-01 00:23回复
    就目前想法来说,应该只会写些跟代码相关的东西.
    首先是最终要的,所有作者都应该了解的东西,就是脚本的返回值 return xxxxx; 的作用.
    举个例子,在房间里面创建一个新的instance的时候,会用到instance_create()函数,而当你需要给创建的实例赋值的时候,就会使用 a = instance_create();然后a.xxx = xxx.这种函数.为什么a=instance_create之后就能给a.xxx赋值,就是因为instance_create 返回了创建实例的id,储存在变量a里面.而返回这个动作就是由 return 这个关键词触发的.而且很重要的一点就是,在脚本中如果触发了return这个关键词之后,后面的动作是不会执行的.因此要慎重使用return,确定你需要的效果达成之后再返回.gm还有个关键词quit,跟return的作用相近但是不会有返回值.


    2楼2020-11-01 00:28
    收起回复
      了解了return这个关键词之后就可以讲一点东西了.但是先要声明的是,gm8的return关键词还不太行,不能返回数组(很难受).如果需要的返回值是一串数值,在gm8中一般是使用list返回,跟返回数组效果是一样的,只不过gm8没有访问器要对list等数据结构进行操作的话要多写点函数而已.


      3楼2020-11-01 00:33
      回复

        然后就是第二关键的东西,事件执行顺序,刚入门的作者可以暂时不用了解,遇到自己解决不了的问题的时候可以想想是不是事件顺序问题.


        4楼2020-11-01 00:39
        回复
          这几天有空应该会更点东西,这几天有点忙.有啥不太会做的也可以问问题(如果我会的话.其实我很菜的)


          5楼2020-11-01 00:40
          回复
            睡前想到一个东西,虽然没大用吧.gm在给数组赋值的时候建议从尾端开始赋值,比如你要创建一个长度为10的数组a[0~9];建议用for(var i=9;i>=0;i-=1) a[i] = xxx;因为如果从a[0]开始赋值的话,gm会多次分配内存,a[0]的时候分配一次,a[1]的时候再分配一次来保证存储数组的内存是连续的.因此建议从尾端开始赋值,直接赋值a[9]gm会知道数组长度为10,因此直接会分配10(或者11,我不知道gm会不会分配\0这个东西)个size的内存长度,避免多次分配造成的额外开销.(就现在电脑的性能来说一般没人会感受到差异,所以这段相当于废话)


            6楼2020-11-01 00:47
            回复
              支持


              IP属地:江苏来自Android客户端7楼2020-11-01 01:28
              回复
                如何做耐久?找到一个耐久作者告诉他脑补的弹幕画面,然后让他做


                IP属地:江苏来自手机贴吧8楼2020-11-01 12:34
                回复
                  先讲讲耐久常用到的几个内置量
                  1.h/vspeed,分别表示水平和竖直速度,向右和向下为正.
                  2.speed,direction,image_angle.speed为速度,无方向性,而direction为speed指明运动方向,在实际运动中会分解成h/vspeed来进行运动,同时也能获取h/vspeed的值,反之只赋予h/vspeed的值的时候可以得到speed的值.image_angle则表示实例贴图的角度,如果实例贴图以向右为0度,那么代码image_angle = direction能够做出瞄准移动方向的效果.
                  3.gravity/gravity_direction/friction.gravity和gravity_direction表示物体重力和重力方向,friction表示物体的阻力.这里要重点说明一下friction.friction的方向是你物体当前运动合方向的反向,任何时刻都是.因此当friction为正的时候,只要你的实例有速度,速度就会因为friction慢慢减小,最后速度减为0停止运动,达到平滑运动的作用,当速度为0的时候不会起效.实际效果跟wym帖子里面使用的x+=(tx-x)/xs的效果是一样的.但是要注意的是,friction是可以取负值的,这时候friction的方向就变为了当前实例移动的合方向,从减速变为了加速.于是配合重力就能有很多种组合,比如减速慢加速快,加速快减速慢等等效果.


                  9楼2020-11-01 22:31
                  回复
                    接下来是另一个关键词with
                    用法为with(xxx){do something},让所有名为xxx的对象(包括他的字对象)执行一串代码.同时要注意另外两个关键词other与self.在with的作用域中,self指的是被with的对象.比如我在world的某一处写了with(player){self.x = xxx}.意思是将player的x变为xxx,而不是将world的x变为xxx.而other在with的作用域中的作用与self相反.比如我给world定义了一个变量pause,我想把pause变量的值赋予给player,那么可以写with(player){self.onpause = other.pause}.此时,就将world的pause这个变量的值传递给了player.虽然在with语句中一般很少用到这两个关键词,但是还是要了解一下.


                    10楼2020-11-01 23:04
                    收起回复
                      关键词:成员访问运算符: . (就是半角的句号,可能要仔细看才能看到)用法 player.x = 1;(注意player和x之间有个点)
                      成员访问运算符 . ,就跟汉语中的"的",英文中的" 's "意思一样.就是用来读取某个实例的变量的值的,当然也可以改变这个值.但是要注意的是,与with不同,成员访问运算符只能对一个实例进行操作,而with是对象的所有实例(除非你使用id).
                      比如此时屏幕里面有个子弹叫bullet1,另一个子弹叫bullet2,你想让他们的速度变成与player的速度相同,并且让他转向,你可以在一个控制所有子弹的obj的某个事件的某处写:
                      bullet1.speed = player.speed;
                      bullet1.direction+= 180;
                      bullet2.speed = player.speed;
                      bullet2.direction+= 180;
                      如果说有多个bullet1与bullet2,而你想同时改变他们的速度和方向,就要用with语句了.
                      with(bullet1)
                      {
                      self.speed = player.speed;
                      self.direction += 180;
                      }
                      如果bullet1与bullet2同时都为对象bullet的子对象的时候,就可以简写为
                      with(bullet)
                      {
                      self.speed = player.speed;
                      self.direction += 180;
                      }
                      在通常情况下,self都是可以不写的,这里写self只是加深理解.


                      11楼2020-11-01 23:18
                      收起回复


                        IP属地:湖北来自Android客户端12楼2020-11-03 06:26
                        回复
                          接下来应该可以讲一些特效的做法了(偶尔可能会想起来有什么重要的东西没讲)
                          第一个先讲讲渐变色

                          这种渐变应该在不少耐久里面见过了,初次见可能以为会是使用一个多帧的spr来制作的,实际上是只需要一个纯白色的spr就可以了.用代码来给他染色.仔细看就能看出来,颜色是慢慢过渡的,使用多帧的spr来制作的话,颜色是突变的而不是平滑过渡.(虽然说如果耐心足够使用大量的spr来进行渐变特效的话也能做出一样的效果).
                          用代码与用spr各有优势,没有绝对的谁好谁坏.
                          首先说原理:gm在绘制精灵的时候,是可以给精灵混上一定的颜色的.使用 image_blend这个变量来对精灵进行混色.
                          并且在gm里面,纯白色混上任意颜色就会变成任意颜色,纯黑色是不能混上别的颜色的.因此我们只需要用纯白色精灵来混上渐变的颜色就能做出渐变色的精灵了.

                          从gm提供的色带可以看出,颜色渐变只需要从最左端开始,水平移到最右端结束就能完成一次颜色渐变,那么想法很简单,用make_color系列函数就能完成,提供3个颜色分量,让分量慢慢变化就能完成颜色变化.那么备选的方案就有make_color_rgb 与 make_color_hsv.在色带上左右平移的时候,观察rgb与hsv值的变化,就能看到,平移的时候rgb三个值都是明显有变化的,并且三者的联系性并不强,但是hsv三个参数,在绝对的平移情况下,只有h这个参数是变化的,sv两个参数是不变的,因此可以确定使用make_color_hsv是最简单的.
                          那么代码就好写了.
                          在create事件中定义好h这个变量,比如说c_hspd = 0;然后设置image_blend = make_color_hsv(c_hspd,255,255);
                          在step事件中慢慢变化c_hspd这个变量,比如c_hspd += 1;(gm8不支持++运算),然后给c_hspd限制范围,因为make_color_hsv这个函数的3个参数实际取值范围为0~255.
                          比如这么限定
                          if(c_hspd > 255)
                          c_hspd = -255;
                          随后来计算当前颜色
                          image_blend = make_color_hsv(abs(c_hspd),255,255);
                          abs(x)为取x的绝对值.因为当c_hspd大于255的时候会变成-255,而c_hspd在每一帧都是会加1的,这样就将c_hspd的范围限制在了0~255之间,纯白色的精灵也就染色成了彩色渐变的精灵.


                          13楼2020-11-03 23:31
                          回复
                            这次讲3个常见的混合模式的应用.
                            上面讲的image_blend的应用是在不调整混合模式的情况下做出来的,如果改变了绘制混合模式,绘制出来的东西就会有所偏差.
                            混合模式是一个不算复杂,但是需要深入理解的东西,我在这里不展开讲,只会讲一下成品效果的代码,有兴趣的可以去找一下gamemaker studio的F1帮助文件,里面对这些东西讲的比较详细,gm8的F1是真的过于简单了.
                            首先,在常见的黑背景耐久中经常使用的bm_add模式.


                            两张图对比能看到,本来是一个个单独的子弹,中心发亮,外围被一圈绿色包围,但是在他们重叠的时候,重叠部分的绿色消失了,取而代之的是高亮的白色,本来分散的弹幕融为了一个整体,整个的观感提升了很多.
                            为了达到这样的效果,就需要调整绘制的混合模式了.
                            绘制的混合模式是在进行绘制的时候决定以怎样的方式进行绘制的.
                            上述的效果只需要将混合模式调整为bm_add即可.
                            具体代码需要写在子弹的绘制事件里面.
                            draw_set_blend_mode(bm_normal);
                            draw_sprite(sprite_index,image_index,x,y);//在这里绘制你想绘制的东西.
                            draw_set_blend_mode(bm_normal);
                            这样就能做到自带高亮并且重叠的时候会变成一个整体.
                            很重要的一点,在设置完混合模式并且绘制完想要绘制的东西之后,必须要初始化混合模式,不然会影响到其余的东西的绘制的.


                            14楼2020-11-04 21:55
                            回复
                              第二个效果,反色.这个就要讲到表面的应用.
                              表面(surface),与PS的图层相似,是一层画布,你可以在上面画任何东西,然后将画布画到屏幕上,就能输出你刚才所画的东西.
                              有些人可能会奇怪,既然是要画到屏幕上的东西为什么要多弄一步画到画布上然后再画出来.在通常情况下,确实没必要.但是如果涉及到了混合模式的改变,表面可以说是99%会出席.
                              首先讲一下混合模式需要调成那种.
                              draw_set_blend_mode_ext(bm_inv_dest_color,bm_zero)
                              draw_set_blend_mode_ext这个函数有两个参数,在实际绘制的时候是将绘制的源图像的颜色参数与第一个参数所代表的混合参数相乘的结果,和目标图像的颜色参数与第二个参数所代表的混合参数相乘的结果相加,,所得的最终结果所代表的图像画到屏幕上.读起来可能会有点拗口,在讲完surface之后我会简单讲一下.
                              上面讲了surface是一层画布,而且画布是有大小的,那么肯定就需要自己创建.
                              新建一个obj,在创建事件中写上
                              surf = surface_create(width,height);//宽度和高度随意,看你需要的效果的大小
                              surface_set_target(surf);//将当前绘制的目标变为刚才创建的表面.
                              draw_clear_alpha(c_white,0)//将表面用透明度为0的白色填充满,为什么要这么做下面会讲到
                              surface_reset_target();//将绘制目标变回为屏幕
                              然后在这个obj的draw事件中写上
                              draw_set_blend_mode_ext(bm_inv_dest_color,bm_inv_src_color);
                              if(surface_exist(surf))//必须判定surf是否存在,因为表面是存在内存(显存)中的,很多情况下表面是会消失的如果消失的话你还需要重复一次创建事件中的动作
                              draw_surface(surf,x,y);//x,y位置由你自己决定
                              draw_set_blend_mode(bm_normal);
                              然后将obj放到房间里面就能看到反色的效果了,比如
                              那么现在就来讲讲上面为什么会有一些迷惑操作.
                              首先,混合模式里面的颜色分量区间与之前讲的make_color系列函数不一样,混合模式里面的颜色区间是0~1,透明度也是0~1,那么,用透明度为0的白色将表面填充满之后,表面上每一个点的颜色参数都是(1,1,1,0).
                              改变混合模式之后,bm_inv_dest_color代表的参数是(1–Rd, 1–Gd, 1–Bd, 1–Ad),放到第一个参数,那它就会和源图像也就是表面)的颜色参数相乘.小d(destination)表示绘制的目标,这里就是屏幕上所显示的图案.R表示红色分量,Rd就表示屏幕上的某个点的红色分量,其余同理.这4个参数与表面颜色参数相乘,就得到了(1-Rd,1-Gd,1-Bd,0),然后第二个参数bm_inv_src_color代表的参数为(1-Rs, 1-Gs, 1-Bs, 1-As),与底色相乘得到(0,0,0,Ad),因为Rs=Gs=Bs=1,As=0.然后两个结果相加,就得到了(1-Rd,1-Gd,1-Bd,Ad),翻译过来就是颜色反色,但是透明度不变.
                              最后,在特效使用完之后,删除obj的时候一定要记得清理到表面,不然他会占用内存不干事的
                              清理用surface_free(surfID)


                              15楼2020-11-04 22:28
                              回复