欢迎光临散文网 会员登陆 & 注册

随便写的做耐久小教程——(3)基础弹幕种类制作

2023-04-08 08:00 作者:_KomeijiKoishi  | 我要投稿

本教程是基于umbrella丶2修改果引擎制作的耐久引擎(稍加改动)的教程,该引擎gm版本为Gamemaker8。


一.单一弹幕Object制作

1.自机狙

自机狙的特征是朝向kid飞行,因此需要用到该函数:

因此,要实现该效果,可以通过如下方式:

在弹幕obj的create代码中输入:

direction=point_direction(x,y,player.x,player.y)

那么这个弹幕的速度方向就会朝向kid

 

2.随机弹

随机弹需要有一些随机的参数,因此需要用到以下函数

一些生成随机数的函数

这些随机函数的使用方法众多,最简单的方法如:

在弹幕obj的create代码中输入:

direction=random(360)//随机角度

或者

speed=random_range(5,15)//随机速度

等等

 

3.图形弹幕

大多数简单的图形弹幕都可以通过函数或者函数的叠加来生成

A.极坐标函数

通过极坐标函数创建弹幕时,通常需要以下函数

其中,dir遵循角度制,逆时针增大

注:在Gamemaker8中,y坐标由上至下增大

投影数值的表示

使用此函数,我们可以通过形如

R=……//以dir为变量的函数

instance_create(X+lengthdir_x(R,dir),Y+lengthdir_y(R,dir),obj)

的代码来创建一个以(X,Y)为中心,形状与极坐标函数图像相同的图形弹幕

例如

①.圆形弹幕

我们知道,圆形在极坐标下可以用R(θ)=C的形式表示。因此,创建圆形弹幕,可以通过如下方式:

for(i=0;i<60;i+=1){

    dir=i*6

    R=100

    instance_create(300+lengthdir_x(R,dir),300+lengthdir_y(R,dir),obj)

}

这段代码能够创建一个以300,300为圆心,半径为100,平均分布有60个obj的圆

②.方形弹幕

同样,正方形在极坐标下可以用

C1代表对角线长度的一半,C2代表顺时针旋转的角度

的形式表示。

极坐标函数的图像

因此,创建方形弹幕,可以通过如下方式:

for(i=0;i<60;i+=1){

    dir=i*6

    R=100/sqrt(1+abs(cos(2*(degtorad(dir)+pi/10)))

    instance_create(300+lengthdir_x(R,dir),300+lengthdir_y(R,dir),obj)

}

这段代码能够创建一个以300,300为中心,对角线长度为200,每6度方向上有一个obj,顺时针旋转π/10的正方形

注:在GML中,cos和sin是弧度制,如果要将角度转为弧度,应使用degtorad()代码


B.参数方程函数

假设要创建一个以参数方程决定的曲线弹幕,可以通过如下方式:

参数方程的形式

例如:

.直线

for(i=0;i<41;i+=1){

    X=100+i*10

    Y=100+i*10

    instance_create(X,Y,obj)

}

②.正弦函数波

 for(i=0;i<81;i+=1){

    X=i*10

    Y=304+sin(i/10)*30

    instance_create(X,Y,obj)

}

具体效果可在游戏中测试


*C.创建后的行为分化

①.弹幕自主控制

假设,我们要让这个圆上的弹幕,一段时间后,上半部分变成随机弹,下半部分变成自机狙,怎么办呢?

简单来说,就是在创建时根据循环变量i为各个obj赋予一个特殊的变量,如:

for(i=0;i<60;i+=1){

    dir=i*6+3

    R=100

    inst=instance_create(300+lengthdir_x(R,dir),300+lengthdir_y(R,dir),obj)

    if i<30 inst.Num=1

    else inst.Num=2

}

然后在这个弹幕obj的step代码中输入:

Time+=1

if Time=100{

    if Num=1{

        direction=random(360)

        speed=random_range(5,10)

    }

    else{

        direction=point_direction(x,y,player.x,player.y)

        speed=15

    }

}

即可实现所需效果


②.单一obj控制

假设,你想要一个obj创建出的所有弹幕继续保持着圆的形状,并且以这个obj为圆的中心旋转,可是你又不想要用弹幕来执行代码怎么办呢?

用单一obj控制所有弹幕的方式需要让这个obj记录下所有obj的id,以上述圆形弹幕为例,将其更改为:

for(i=0;i<60;i+=1){

    dir=i*6

    R=100

    inst[i]=instance_create(x+lengthdir_x(R,dir),y+lengthdir_y(R,dir),obj)

}

之后,在这个obj的step中执行:

Time+=1

for(i=0;i<60;i+=1){

    dir=i*6+Time

    R=100

    inst[i].x=x+lengthdir_x(R,dir)

    inst[i].y=y+lengthdir_y(R,dir)

}

那么这个圆就会不断绕着这个obj旋转 


4.变速弹幕

A.通过重力实现变速

最简单的使弹幕变速的方法是通过设定obj的重力值

以kid本身为例,player的gravity=0.4,gravity_direction=270

如果要创建一个向着左上角不断加速的弹幕,可以这样实现:

gravity=0.75

gravity_direction=135

B.通过step实现变速

而更多情况下,变速可以通过step函数进行,如:

①.随着时间缓慢减速

speed-=(speed>0)*0.25

if speed<0 speed=0

或通过阻力实现

阻力参数:每秒速度减去其值,最小为0

friction=0.25

②.在某一时刻突然变速

Time+=1

if Time=10 speed=20

③.抛物线(效果相当于gravity)

hspeed+=xgrav

vspeed+=ygrav

 其中xgrav、ygrav是每秒x、y方向上的速度增量

*④e^(-x)型缓动

e^(-x+C1)+C2的图像

有时候,我们希望让弹幕先快后慢的靠近空间中的某一个点,于是我们发现,如果将t作为自变量,e^(-t)+C作为因变量,那么这一函数正好具有此良好的性质,最终它的值会逐渐趋近于C。

我们知道,s=e^(-kt)+C的微分形式是ds=-ke^(-kt)dt,令dt为1,将s代入微分式,我们能够得到:

ds=-k(s-C)

也就是说,如果我们要让某个值逐渐靠近C,可以通过在step事件中添加如下代码实现:

s-=k(s-C)

其中,k代表收敛的速度(k的取值为0~1,否则会导致s超出C而产生bug)

于是,我们可以通过如下形式实现弹幕的变速:

speed-=0.1*(speed-1)

此时弹幕的速度会逐渐趋近于1


5.变角度弹幕

①角度增减

GML中没有类似于重力的特定的改变角度的函数,一般情况下,改变角度的方式和speed类似,如:

         在step中输入:

                   direction+=3

*②角度趋近

在GML中,实现类似于缓动的角度趋近是困难的,因为角度的范围只能是0~360,当角度超过360后,它会自动减去360。因此,如果用与上述缓动形式相同的代码,当角度要从359变为0时,它不会选择最快速的顺时针旋转,而是会额外旋转将近一圈。

于是,如果要进行角度旋转,需要进行额外的分类讨论,以下是一种实现该效果的方式:

为图方便,首先,创建一个名为directionapproach的Script,输入以下代码:

//directionapproach(dirfrom,dirto,sca)

//example:dir-=directionapproach(dir,dirto,0.1)

if abs(argument0-argument1)<=180{

  return argument2*(argument0-argument1)

}

if abs(argument0-argument1)>180{

  return argument2*(sign(argument1-argument0)*(360-abs(argument0-argument1)))

}

然后,在需要进行角度趋近的弹幕的step事件中输入:

direction-=directionapproach(direction,dirto,sca)

其中,dirto表示要趋近于的角度值,sca相当于上文的k,表示趋近的速度


6.弹幕源

多数情况下,在时间轴中过多的创建时间节点较为麻烦,有时每步间隔又较长,不能满足密弹幕的需求,此时需要独立创建一个弹幕源,例如:创建一个obj并在step中输入以下代码:

Time+=1

if Time<100{

   instance_create(200,304,Bullet)

}

这样就能创建一个100帧内每帧在(200,304)创建一个Bullet的弹幕源,并且在100帧时销毁


二.基础组合弹幕示例

例一

上图为i wanna be the locus的弹幕,截图于2:06处

首先,我们对其行为进行分析,将其转化为几种基础弹幕的组合

我们可以将其行为分成

①.生成一个不断创建竖向自机狙的弹幕源

②.直线自机狙形状为圆形,同时是自机狙的图形弹幕,并且自身销毁

③.圆形弹幕离开房间后删除

在分析完行为之后,我们逐个实现它的行为

首先,创建一个obj,此处名为ObjCreator,将其作为弹幕源,并在时间轴中选择一个时刻创建该obj,然后,还需要两种弹幕obj,一种作为直线自机狙,一种作为圆形图形弹幕,此处将其命名为Bullet1和Bullet2

第一个行为要求该弹幕源一段时间创建一个竖向自机狙,因此,可以在ObjCreator的step事件中输入:

Time+=1

if (Time mod 100=0){

    inst=instance_create(player.x,-50,Bullet1)

    inst.direction=90

    inst.speed=10

}

if (Time mod 100=50){

    inst=instance_create(player.x,658,Bullet1)

    inst.direction=270

    inst.speed=10

}

然后,这个直线自机狙将在一段时间后销毁并创建图形自机狙弹幕,可以在Bullet1的step中输入:

Time+=1

if Time=30{

    instance_destroy()

    for(i=0;i<10;i+=1){

        inst=instance_create(x,y,Bullet2)

        inst.direction=i*36+point_direction(x,y,player.x,player.y)

    }

}

最后,Bullet2要在离开房间后销毁以释放空间,因此可在其step中输入:

if bbox_right<0 or bbox_left>800 or bbox_bottom<0 or bbox_top>608{

    instance_destroy()

}

if x<-20 or x>820 or y<-20 or y>628{

    instance_destroy()

}



例二

上图为被 ☆耐久の神☆「狗日的拉德」 薄纱的马云牧师的弹幕,截图于0:15处

同样,我们对其行为进行分析,将其转化为几种基础弹幕的组合

我们可以将其行为分成

①.创建单个苹果在kid的坐标

②.该苹果透明度增大至1

③.该苹果作为弹幕源创建圆形变速弹幕

④.圆形弹幕在回到中心的时刻删除

该项留作习题,代码可见显然,读者自撰不难

下一章将介绍如何进行debug操作

随便写的做耐久小教程——(3)基础弹幕种类制作的评论 (共 条)

分享到微博请遵守国家法律