隨便寫(xiě)的做耐久小教程——(3)基礎(chǔ)彈幕種類(lèi)制作

本教程是基于umbrella丶2修改果引擎制作的耐久引擎(稍加改動(dòng))的教程,該引擎gm版本為Gamemaker8。
一.單一彈幕Object制作
1.自機(jī)狙
自機(jī)狙的特征是朝向kid飛行,因此需要用到該函數(shù):

因此,要實(shí)現(xiàn)該效果,可以通過(guò)如下方式:
在彈幕obj的create代碼中輸入:
direction=point_direction(x,y,player.x,player.y)
那么這個(gè)彈幕的速度方向就會(huì)朝向kid
?
2.隨機(jī)彈
隨機(jī)彈需要有一些隨機(jī)的參數(shù),因此需要用到以下函數(shù)

這些隨機(jī)函數(shù)的使用方法眾多,最簡(jiǎn)單的方法如:
在彈幕obj的create代碼中輸入:
direction=random(360)//隨機(jī)角度
或者
speed=random_range(5,15)//隨機(jī)速度
等等
?
3.圖形彈幕
大多數(shù)簡(jiǎn)單的圖形彈幕都可以通過(guò)函數(shù)或者函數(shù)的疊加來(lái)生成
A.極坐標(biāo)函數(shù)
通過(guò)極坐標(biāo)函數(shù)創(chuàng)建彈幕時(shí),通常需要以下函數(shù)

其中,dir遵循角度制,逆時(shí)針增大
注:在Gamemaker8中,y坐標(biāo)由上至下增大

使用此函數(shù),我們可以通過(guò)形如
R=……//以dir為變量的函數(shù)
instance_create(X+lengthdir_x(R,dir),Y+lengthdir_y(R,dir),obj)
的代碼來(lái)創(chuàng)建一個(gè)以(X,Y)為中心,形狀與極坐標(biāo)函數(shù)圖像相同的圖形彈幕
例如
①.圓形彈幕
我們知道,圓形在極坐標(biāo)下可以用R(θ)=C的形式表示。因此,創(chuàng)建圓形彈幕,可以通過(guò)如下方式:
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)
}
這段代碼能夠創(chuàng)建一個(gè)以300,300為圓心,半徑為100,平均分布有60個(gè)obj的圓
②.方形彈幕
同樣,正方形在極坐標(biāo)下可以用

的形式表示。

因此,創(chuàng)建方形彈幕,可以通過(guò)如下方式:
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)
}
這段代碼能夠創(chuàng)建一個(gè)以300,300為中心,對(duì)角線長(zhǎng)度為200,每6度方向上有一個(gè)obj,順時(shí)針旋轉(zhuǎn)π/10的正方形
注:在GML中,cos和sin是弧度制,如果要將角度轉(zhuǎn)為弧度,應(yīng)使用degtorad()代碼
B.參數(shù)方程函數(shù)
假設(shè)要?jiǎng)?chuàng)建一個(gè)以參數(shù)方程決定的曲線彈幕,可以通過(guò)如下方式:

例如:
①.直線
for(i=0;i<41;i+=1){
????X=100+i*10
????Y=100+i*10
? ? instance_create(X,Y,obj)
}
②.正弦函數(shù)波
?for(i=0;i<81;i+=1){
????X=i*10
????Y=304+sin(i/10)*30
? ? instance_create(X,Y,obj)
}
具體效果可在游戲中測(cè)試
*C.創(chuàng)建后的行為分化
①.彈幕自主控制
假設(shè),我們要讓這個(gè)圓上的彈幕,一段時(shí)間后,上半部分變成隨機(jī)彈,下半部分變成自機(jī)狙,怎么辦呢?
簡(jiǎn)單來(lái)說(shuō),就是在創(chuàng)建時(shí)根據(jù)循環(huán)變量i為各個(gè)obj賦予一個(gè)特殊的變量,如:
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
}
然后在這個(gè)彈幕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
????}
}
即可實(shí)現(xiàn)所需效果
②.單一obj控制
假設(shè),你想要一個(gè)obj創(chuàng)建出的所有彈幕繼續(xù)保持著圓的形狀,并且以這個(gè)obj為圓的中心旋轉(zhuǎn),可是你又不想要用彈幕來(lái)執(zhí)行代碼怎么辦呢?
用單一obj控制所有彈幕的方式需要讓這個(gè)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)
}
之后,在這個(gè)obj的step中執(zhí)行:
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)
}
那么這個(gè)圓就會(huì)不斷繞著這個(gè)obj旋轉(zhuǎn)?
4.變速?gòu)椖?/strong>
A.通過(guò)重力實(shí)現(xiàn)變速
最簡(jiǎn)單的使彈幕變速的方法是通過(guò)設(shè)定obj的重力值

以kid本身為例,player的gravity=0.4,gravity_direction=270
如果要?jiǎng)?chuàng)建一個(gè)向著左上角不斷加速的彈幕,可以這樣實(shí)現(xiàn):
gravity=0.75
gravity_direction=135
B.通過(guò)step實(shí)現(xiàn)變速
而更多情況下,變速可以通過(guò)step函數(shù)進(jìn)行,如:
①.隨著時(shí)間緩慢減速
speed-=(speed>0)*0.25
if speed<0 speed=0
或通過(guò)阻力實(shí)現(xiàn)

friction=0.25
②.在某一時(shí)刻突然變速
Time+=1
if Time=10 speed=20
③.拋物線(效果相當(dāng)于gravity)
hspeed+=xgrav
vspeed+=ygrav
?其中xgrav、ygrav是每秒x、y方向上的速度增量
*④e^(-x)型緩動(dòng)

有時(shí)候,我們希望讓彈幕先快后慢的靠近空間中的某一個(gè)點(diǎn),于是我們發(fā)現(xiàn),如果將t作為自變量,e^(-t)+C作為因變量,那么這一函數(shù)正好具有此良好的性質(zhì),最終它的值會(huì)逐漸趨近于C。
我們知道,s=e^(-kt)+C的微分形式是ds=-ke^(-kt)dt,令dt為1,將s代入微分式,我們能夠得到:
ds=-k(s-C)
也就是說(shuō),如果我們要讓某個(gè)值逐漸靠近C,可以通過(guò)在step事件中添加如下代碼實(shí)現(xiàn):
s-=k(s-C)
其中,k代表收斂的速度(k的取值為0~1,否則會(huì)導(dǎo)致s超出C而產(chǎn)生bug)
于是,我們可以通過(guò)如下形式實(shí)現(xiàn)彈幕的變速:
speed-=0.1*(speed-1)
此時(shí)彈幕的速度會(huì)逐漸趨近于1
5.變角度彈幕
①角度增減
GML中沒(méi)有類(lèi)似于重力的特定的改變角度的函數(shù),一般情況下,改變角度的方式和speed類(lèi)似,如:
???????? 在step中輸入:
?????????????????? direction+=3
*②角度趨近
在GML中,實(shí)現(xiàn)類(lèi)似于緩動(dòng)的角度趨近是困難的,因?yàn)榻嵌鹊姆秶荒苁?~360,當(dāng)角度超過(guò)360后,它會(huì)自動(dòng)減去360。因此,如果用與上述緩動(dòng)形式相同的代碼,當(dāng)角度要從359變?yōu)?時(shí),它不會(huì)選擇最快速的順時(shí)針旋轉(zhuǎn),而是會(huì)額外旋轉(zhuǎn)將近一圈。
于是,如果要進(jìn)行角度旋轉(zhuǎn),需要進(jìn)行額外的分類(lèi)討論,以下是一種實(shí)現(xiàn)該效果的方式:
為圖方便,首先,創(chuàng)建一個(gè)名為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)))
}
然后,在需要進(jìn)行角度趨近的彈幕的step事件中輸入:
direction-=directionapproach(direction,dirto,sca)
其中,dirto表示要趨近于的角度值,sca相當(dāng)于上文的k,表示趨近的速度
6.彈幕源
多數(shù)情況下,在時(shí)間軸中過(guò)多的創(chuàng)建時(shí)間節(jié)點(diǎn)較為麻煩,有時(shí)每步間隔又較長(zhǎng),不能滿(mǎn)足密彈幕的需求,此時(shí)需要獨(dú)立創(chuàng)建一個(gè)彈幕源,例如:創(chuàng)建一個(gè)obj并在step中輸入以下代碼:
Time+=1
if Time<100{
? ?instance_create(200,304,Bullet)
}
這樣就能創(chuàng)建一個(gè)100幀內(nèi)每幀在(200,304)創(chuàng)建一個(gè)Bullet的彈幕源,并且在100幀時(shí)銷(xiāo)毀
二.基礎(chǔ)組合彈幕示例

上圖為i wanna be the locus的彈幕,截圖于2:06處
首先,我們對(duì)其行為進(jìn)行分析,將其轉(zhuǎn)化為幾種基礎(chǔ)彈幕的組合
我們可以將其行為分成
①.生成一個(gè)不斷創(chuàng)建豎向自機(jī)狙的彈幕源
②.直線自機(jī)狙形狀為圓形,同時(shí)是自機(jī)狙的圖形彈幕,并且自身銷(xiāo)毀
③.圓形彈幕離開(kāi)房間后刪除
在分析完行為之后,我們逐個(gè)實(shí)現(xiàn)它的行為
首先,創(chuàng)建一個(gè)obj,此處名為ObjCreator,將其作為彈幕源,并在時(shí)間軸中選擇一個(gè)時(shí)刻創(chuàng)建該obj,然后,還需要兩種彈幕obj,一種作為直線自機(jī)狙,一種作為圓形圖形彈幕,此處將其命名為Bullet1和Bullet2
第一個(gè)行為要求該彈幕源一段時(shí)間創(chuàng)建一個(gè)豎向自機(jī)狙,因此,可以在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
}
然后,這個(gè)直線自機(jī)狙將在一段時(shí)間后銷(xiāo)毀并創(chuàng)建圖形自機(jī)狙彈幕,可以在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要在離開(kāi)房間后銷(xiāo)毀以釋放空間,因此可在其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處
同樣,我們對(duì)其行為進(jìn)行分析,將其轉(zhuǎn)化為幾種基礎(chǔ)彈幕的組合
我們可以將其行為分成
①.創(chuàng)建單個(gè)蘋(píng)果在kid的坐標(biāo)
②.該蘋(píng)果透明度增大至1
③.該蘋(píng)果作為彈幕源創(chuàng)建圓形變速?gòu)椖?/p>
④.圓形彈幕在回到中心的時(shí)刻刪除
該項(xiàng)留作習(xí)題,代碼可見(jiàn)顯然,讀者自撰不難
下一章將介紹如何進(jìn)行debug操作