Unity老游戲復(fù)刻計(jì)劃之《雪人兄弟》(2)
未接觸過游戲開發(fā)但又對其感興趣的朋友,只需添加如下聯(lián)系方式(注明B站),便可體驗(yàn)一次激動人心的游戲開發(fā)過程——提出需求、思考原理、實(shí)現(xiàn)功能、定位bug、設(shè)計(jì)關(guān)卡、更換美術(shù)資源......麻雀雖小五臟俱全。更能獲取海量游戲開發(fā)資料:

(本文作者Khalil)
上篇傳送門:

大家好,游戲開發(fā)新人Khalil又來了。

書接上文,我將上次未完成的工程進(jìn)行了完善和優(yōu)化,并在這期間又發(fā)現(xiàn)了更多新的細(xì)節(jié)。
先來說說上篇中曾講到的,游戲角色控制中需要優(yōu)化或?qū)崿F(xiàn)的幾個(gè)操作:
死亡;
從下方通過跳躍頂起雪球;
推動和踢走雪球;
站在雪球上踢走雪球(按下攻擊鍵),或者被滾動中的雪球撞到,可以跟隨雪球移動,在跟隨雪球移動的期間為無敵狀態(tài);
在跟隨雪球移動的期間按下跳躍鍵,即可脫離雪球,并進(jìn)入一段時(shí)間的無敵狀態(tài)。
我發(fā)現(xiàn)這里有一點(diǎn)理解錯(cuò)誤的地方。其實(shí)在boss關(guān)中,角色被雪球撞到,并不會被雪球帶著走,而是直接進(jìn)入閃爍狀態(tài),它不同于吃了綠色藥水的無敵狀態(tài)(無視地形在地圖上飛行,碰撞到的小怪直接死亡),而是一種不可選定,敵人和滾動雪球都不會碰到的狀態(tài)。所以第四種操作應(yīng)該改為:被滾動雪球撞到時(shí),進(jìn)入閃爍狀態(tài)。死亡也不是一種“操作”,而是一個(gè)狀態(tài)。
(1)那么死亡狀態(tài)的實(shí)現(xiàn)非常簡單,只要角色碰撞到小怪和Boss,就立刻去世(播放死亡動畫,并將碰撞體關(guān)掉),在死亡動畫的最后幾幀內(nèi),添加一個(gè)移除gameObject的動畫幀事件,就可以達(dá)到展示角色死亡狀態(tài)的效果。

(2)接著是從下方頂起雪球的操作,這個(gè)操作我目前并未去實(shí)現(xiàn),因?yàn)樵趯?shí)際游玩的過程中,這一關(guān)基本不會用到這一操作。并且我之前將雪球的質(zhì)量設(shè)置得過大了,不管是理論上還是實(shí)際上,角色都無法通過剛體和碰撞體將雪球頂起,只能通過腳本來實(shí)現(xiàn)。感興趣的朋友可以拿工程去試著實(shí)現(xiàn),也歡迎在評論區(qū)進(jìn)行討論~
(3)接下來是推動和踢走雪球的優(yōu)化,上一篇沒有講到踢走雪球的操作,是因?yàn)樯形创_定實(shí)現(xiàn)它的方法。我發(fā)現(xiàn)之前我使用的方法有較大問題——我在角色腳本中寫了PushBall方法,用于控制玩家踢走雪球和推動雪球。我最開始使用了碰撞體去檢測雪球,但如果這樣的話就會出現(xiàn)“就算雪球在角色右方,角色向左移動時(shí)也會進(jìn)入推雪球狀態(tài)”的情況。
在和皮皮關(guān)老師討論過后,我改為了使用向玩家前方發(fā)射的射線去檢測雪球,這樣可以適當(dāng)改變檢測的范圍,在檢測到雪球的范圍內(nèi),角色開始移動時(shí),才會切換到推雪球的動畫,使得只有當(dāng)玩家面向雪球并開始推動雪球時(shí),才會進(jìn)入推雪球的狀態(tài)。

在講解踢走雪球的實(shí)現(xiàn)方法前,我先講講在優(yōu)化過后,雪球腳本的變化。
雪球現(xiàn)在有五個(gè)狀態(tài):
三分之一雪球(1)
一半雪球(2)
完整雪球(3)
滾動中的雪球(4)
切換到小怪(5)
前三者狀態(tài)的切換上一篇教程中已經(jīng)簡單講解了,就是遭受到玩家攻擊時(shí)(被玩家子彈打中時(shí))就切換到下一個(gè)狀態(tài)。而在觀察后我發(fā)現(xiàn),其實(shí)并非一受到攻擊就會切換狀態(tài),雪球的hp其實(shí)也是有自己特殊的計(jì)算公式的。
角色在沒有吃到藍(lán)藥水時(shí),普通攻擊有時(shí)需要多次才會使雪球切換狀態(tài),而有時(shí)又只需要一次。因?yàn)闆]有查到精確的hp計(jì)算方式,我姑且直接將雪球的hp設(shè)定在0,1,2之間切換。切換的方式為:
雪球初始狀態(tài)為(1),初始hp為0。當(dāng)受到攻擊,切換到(2)狀態(tài)時(shí),將hp設(shè)定為1,將受到攻擊時(shí)的時(shí)間保存為beFrozonTime;
當(dāng)hp為1時(shí)受到攻擊,就切換到(3)狀態(tài),將hp設(shè)定為2,將受到攻擊時(shí)的時(shí)間保存為beFrozonTime;
當(dāng)未受到攻擊一段時(shí)間后(即Time.time過了beFronzonTime加上雪球需要保持狀態(tài)的時(shí)間后),切換狀態(tài)的順序就變?yōu)槟嫘?,完整雪球會切換到一半雪球,并且每次切換后,beFrozonTime刷新(重新記錄為切換狀態(tài)的時(shí)間,即不管狀態(tài)怎么切換,beFrozonTime都會記錄狀態(tài)切換的時(shí)間);
只有(3)狀態(tài)的雪球被玩家踢了之后,才會進(jìn)入狀態(tài)(4),由于在游戲中,雪球一旦開始滾動,它的結(jié)局就是消失,最終肯定是碰到Boss或是DeadZone,所以雪球一旦進(jìn)入滾動狀態(tài),就不會切換到別的狀態(tài)。
當(dāng)雪球(1)變?yōu)樾」郑?)時(shí),自然是自身消失,然后將小怪釋放(Instantiate)出來,所以進(jìn)入這個(gè)狀態(tài)后也不需要進(jìn)行其他狀態(tài)切換了。
理解了雪球狀態(tài)切換的方式后,先實(shí)現(xiàn)讓雪球滾動。我在雪球腳本中寫了一個(gè)Roll方法,傳入一個(gè)方向值來控制雪球的運(yùn)動方向,改變雪球的標(biāo)簽和圖層,以此實(shí)現(xiàn)一些特殊效果。
并在這個(gè)方法里改變雪球的狀態(tài),給予它運(yùn)動的速度:

一開始自以為這樣就OK了。但是后來發(fā)現(xiàn)有很大的問題:這個(gè)方法還不足以讓雪球保持勻速運(yùn)動,需要在update中給滾動的雪球持續(xù)不斷的速度。所以我在狀態(tài)(4)中也寫了和Roll方法中改變物體速度語句一樣的語句(因?yàn)闋顟B(tài)機(jī)[switch]在update中),這樣的話不難發(fā)現(xiàn)dir就獲取不到了。很簡單,再寫一個(gè)公共的dir1,將dir1始終保持與dir一致即可,這樣,雪球就會不停地勻速運(yùn)動了。有了dir1之后雪球的轉(zhuǎn)向就更簡單了,雪球若是碰到了需要讓其轉(zhuǎn)向的物體,將dir1=-dir1即可。
然后就可以試著讓玩家踢動雪球了。其實(shí)很簡單,只要檢測雪球的射線檢測到了雪球,玩家就可以按下開火鍵將其踢走(調(diào)用雪球的Roll方法)。
另外在游戲中,不僅玩家可以使雪球滾動,滾動中的雪球也可以,若滾動中的雪球撞到了雪球,則被撞到的雪球也會開始滾動并變色,如果玩家使用的角色為Nick(藍(lán)色服裝的雪人)雪球就變?yōu)樗{(lán)色,若是Tom則雪球就變?yōu)榧t色。


實(shí)現(xiàn)這個(gè)效果其實(shí)也很簡單。在雪球腳本中,如果滾動雪球撞到了其他的雪球,則調(diào)用被撞到的雪球的Roll方法即可,前進(jìn)的方向dir就是撞到它的雪球移動的方向,而撞擊其他雪球的那個(gè)雪球的移動方向又會改為反方向(dir1=-dir1)。
變色的流程也是一樣的,只不過要多寫一個(gè)玩家2的角色腳本。因?yàn)檫@個(gè)游戲本身就可以兩個(gè)玩家游玩。在角色腳本1的PushBall方法中給雪球傳入PlayerNum(玩家編號),編號為1,這個(gè)雪球撞擊到的雪球都會變?yōu)樗{(lán)色;在角色腳本2中傳入雪球的玩家編號為2,這個(gè)雪球撞擊到的雪球就都會變?yōu)榧t色。
站在雪球上推動雪球,只要在腳底也添加一條射線,用于檢測雪球即可,沒有難度。并且在Boss關(guān)卡中,玩家不會被滾動中的雪球帶著走,而且是改為直接進(jìn)入閃爍狀態(tài),所以第五個(gè)操作也就不存在了。
現(xiàn)在是無敵(閃爍)狀態(tài)的實(shí)現(xiàn)方法。本質(zhì)也是改變圖層,先設(shè)定一個(gè)bool變量isInvinsibility,控制玩家閃爍狀態(tài)和普通狀態(tài)的切換。如果角色站在雪球上踢走雪球或是被滾動中的雪球撞到,則它為true。再編寫一個(gè)改變狀態(tài)的方法,如果isInvinsibility為true則啟用,記錄啟用時(shí)的時(shí)間invinsibilityTime,將角色的圖層改變?yōu)樾」?、Boss以及滾動中的雪球都不會與其發(fā)生碰撞的層級,并讓角色閃爍(進(jìn)行Renderer顏色的切換)。在update中編寫:若過了閃爍的時(shí)間則變?yōu)槠胀顟B(tài),層級也改回普通狀態(tài)下的“Player”。


這里顏色切換出了一個(gè)問題:閃爍狀態(tài)結(jié)束時(shí),有時(shí)顏色不會改回白色。雖不是啥大問題不過有點(diǎn)funny,有點(diǎn)老游戲bug內(nèi)味兒了。

上篇提到但是沒有做完的功能就講完了,那么就到一些新的功能和優(yōu)化了。
子彈優(yōu)化
道具掉落
道具效果及加分條件
死亡后復(fù)活
計(jì)分板上展示玩家分?jǐn)?shù)、玩家生命數(shù)、玩家游戲幣數(shù)
到這個(gè)時(shí)間點(diǎn)我又回去游玩了原版游戲,想著有沒有忽略的東西,果不其然,發(fā)現(xiàn)了不少細(xì)節(jié):
首先,1p在推動雪球時(shí),2p是碰不到1p在推動的雪球的,就好像1p和雪球融為一體了,作為上世紀(jì)90年代初的一款動作游戲,細(xì)節(jié)真的多到令人發(fā)指。不過現(xiàn)在我已經(jīng)設(shè)定好了物體之間的圖層和它們的切換方式,這點(diǎn)細(xì)節(jié)我就偷懶不實(shí)現(xiàn)了。真要做的話,例如可以讓兩個(gè)角色分為不同的圖層,在玩家推動雪球時(shí),再給雪球暫時(shí)改成另外一個(gè)玩家碰不到的圖層。當(dāng)然也可以有更高明的做法,歡迎討論。
接著,角色子彈并不是一開始就會掉落,而是直線運(yùn)動到一定距離后,才會下落,所以一開始先將其設(shè)定為Kinematic,在子彈腳本中編寫,在子彈誕生后過段時(shí)間,剛體的isKinematic為false。
還有,雪球下落的時(shí)滾動出地面時(shí),“飛行”的距離一般不會很長(在原版游戲中仿佛都是設(shè)定好的),所以雪球所受的重力要增加一些(可以在剛體中改變)。
雪球撞到不完整的雪球或者怪物時(shí)有概率掉落道具(加成道具“藥水”或者加分道具):

并且撞到的越多,掉落的道具是藥水和高分的道具的幾率就會越高。這塊屬于戰(zhàn)斗設(shè)計(jì)的細(xì)節(jié),我尚未實(shí)現(xiàn),只是簡單的實(shí)現(xiàn)了道具的掉落,不過只要道具掉落實(shí)現(xiàn)了,改變概率啥的就是分分鐘的事情(那你為什么不做?。?/p>
道具的掉落很簡單,先在雪球或者小怪的腳本中(其實(shí)只要在雪球中寫就行了)定義一個(gè)int變量,在Start中取隨機(jī)值,在未完成的雪球或者小怪被滾動中雪球撞到并消失時(shí),如果這個(gè)變量的值在糖果區(qū)域內(nèi)(比如0~60),就掉落糖果,在什么道具的取值區(qū)域內(nèi)就掉落什么道具(其實(shí)只要在滾動中的雪球里面寫就好了,如果撞到未完成的雪球或者小怪就掉道具,并且還可以記錄撞到的是第幾個(gè),方便更改概率)。
雖然在實(shí)際攻略這個(gè)Boss關(guān)卡時(shí),為了盡快通關(guān),場景中往往不會累積多個(gè)怪物來讓玩家獲取道具,boss送出一個(gè)小怪后,玩家就會盡快將其變?yōu)檠┣騺砉鬮oss。但是為了盡量還原,我還是寫出了撿到某些道具會出現(xiàn)的增益效果(糖果,黃紅藍(lán)藥水)。首先創(chuàng)建所有道具的預(yù)制體,給它們賦予剛體和碰撞體,設(shè)置一個(gè)道具圖層,使得所有角色內(nèi)只有玩家角色可以接觸到道具,并將其設(shè)置為觸發(fā)器。不嫌麻煩的做法是,給每一個(gè)道具創(chuàng)建一個(gè)腳本,但其實(shí)沒有必要,直接在角色腳本里就可以呈現(xiàn)出所有的效果,創(chuàng)建三個(gè)bool變量,用于控制角色是否加速(speedUp),力量是否提升(powerUp),攻擊范圍是否增加(rangeUp)。在OnTriggerEnter2D中寫到:玩家接觸到道具時(shí),道具消失,并根據(jù)碰到的道具給玩家添加增益效果,比如“撿到”紅藥水,則speedUp為true,玩家切換到加速狀態(tài):

?撿到加分道具,就會飄起來加分?jǐn)?shù),并在計(jì)分板上加上:

藍(lán)藥水的效果,就是讓吃了藍(lán)藥水后改變子彈的預(yù)制體,使其變?yōu)榇笞訌椉纯桑ㄓ捎趥σ婚_始就沒正確進(jìn)行計(jì)算,所以這里的實(shí)現(xiàn)實(shí)際上也只是讓子彈變大,并沒有實(shí)際增加攻擊力。不過這一塊好改)。
黃藥水的效果,就是延長子彈飛行和延后消失的時(shí)間,但是其實(shí)原版游戲中這個(gè)藥水就沒什么作用,它的效果我就懶得寫了(懶狗)。
若玩家已經(jīng)吃過了藥水,下次撿到同種顏色的藥水時(shí),狀態(tài)也不會進(jìn)一步提升了,而是會加上2000分。若玩家使用普通攻擊攻擊了怪物、尚未完整的雪球或者是Boss,就會加10分,并且推動雪球會加500分,若是雪球撞到了怪物或是尚未完整的雪球,也會加500分,貌似雪球下落也會加10分,切換運(yùn)動方向也會加10分。
上面是我觀察到的游戲中的得分變動情況,不過我只寫了攻擊時(shí)的加分(懶狗*2),即在子彈腳本也添加playerNum中判斷是誰發(fā)出的子彈,譬如屬于玩家1的子彈碰到了可加分的角色,則玩家1加10分。
不過既然在說得分,那么也順便說說計(jì)分板。計(jì)分板的實(shí)現(xiàn)那就灰常簡單了,可以在很多游戲中通用。先在場景中創(chuàng)建畫布,畫布下創(chuàng)建Image,并設(shè)為黑色,做個(gè)黑板。在黑板下創(chuàng)建各個(gè)需要顯示的內(nèi)容:

從左至右分別是:
表示出下方這是1P的分?jǐn)?shù)的1P字樣,下面的0為1P目前的分?jǐn)?shù),我將它命名為1PScore;
代表下方是1P生命數(shù)的笑臉圖片,下方的2為1P目前剩余的生命數(shù);
中間的是最高分,誰的分?jǐn)?shù)高中間就顯示誰的分?jǐn)?shù)(方便玩家們進(jìn)行攀比,那會兒有街機(jī)血統(tǒng)的游戲,即使后來移植到家用機(jī)等其他平臺了,往往也會保留有“Hiscore”這么個(gè)沒什么卵用的系統(tǒng));
2P字樣和2P分?jǐn)?shù);
沒有2P的生命數(shù),因?yàn)槲覒械米?P的復(fù)活效果了(想做的朋友直接在工程里復(fù)制粘貼1P復(fù)活方法的編寫語句就行)
在名為1PScore和2PScore文本物體上,分別掛上Score1和Score2腳本,分別用于計(jì)算1p和2p的分?jǐn)?shù)。兩個(gè)腳本寫的東西是一樣的,只不過計(jì)算的分?jǐn)?shù)是不同角色的分?jǐn)?shù)罷了。先添加上using UnityEngine.UI,需要使用它里面的:Text,
通過改變Text的text的值,就可以改變UI展示的內(nèi)容,再給它定義一個(gè)靜態(tài)的int變量(score1P 或者是 score2P),用于表示玩家分?jǐn)?shù)。在游戲開始時(shí)(即start中)將這個(gè)變量歸零,

加分的實(shí)現(xiàn)之前就講到了,若是分?jǐn)?shù)變化,就改變score1P or score2P的值即可。
玩家生命數(shù)和游戲幣數(shù)記錄在WorldManager腳本中,先創(chuàng)建WorldManager空物體,掛上腳本。與玩家生命有關(guān)的邏輯如下:
玩家死亡后,生命數(shù)會減1,若生命數(shù)沒有降到0以下,則玩家會直接復(fù)活;若生命值降到0之后,玩家死亡且剩余游戲幣數(shù)不為0時(shí),顯示生命數(shù)的數(shù)字就會在0和剩余游戲幣數(shù)之間閃爍,玩家按下A鍵(或者B鍵,忘記了)后,生命數(shù)就會變?yōu)?,并讓玩家復(fù)活。
明白了邏輯就很簡單了,創(chuàng)建分別代表玩家游戲幣數(shù)、玩家生命數(shù)的變量,并將玩家生命數(shù)設(shè)為static,方便其他腳本調(diào)用(若玩家觸發(fā)了死亡條件,則生命數(shù)-1)。創(chuàng)建玩家預(yù)制體,在此腳本中,若玩家死亡后可以復(fù)活,則在固定位置復(fù)活(Instantiate)玩家即可,記得復(fù)活的時(shí)候有段時(shí)間的無敵狀態(tài)。這一部分沒什么難度就不細(xì)說了,有疑問的朋友下載工程來看源碼就萬事OK啦。
到這里,《雪人兄弟》制作之旅暫時(shí)就告一段落了。雖然還是有很多細(xì)節(jié)沒有實(shí)現(xiàn)(跳躍時(shí),因?yàn)榭梢源怪睆南路降牡孛嫣S到上方的地面,所以在跳躍期間CheckGround有時(shí)會檢測到地板,造成玩家明明尚未落地卻又可以跳躍了的情況),但至少在我看來,已經(jīng)與原版十分相似了。
這次的制作耗費(fèi)了很多時(shí)間,因?yàn)樽约旱募夹g(shù)尚不成熟,沒有制定詳盡的計(jì)劃,而是想到什么做什么,并且在制作前沒有把游戲游玩和觀察透徹,導(dǎo)致了總是在修修補(bǔ)補(bǔ),新功能的制作總是停滯不前,在下一次游戲的制作中,我會進(jìn)行仔細(xì)地游玩與觀察、指定詳盡的計(jì)劃后再開始行動,敬大家期待我進(jìn)化后的作品~

工程鏈接:https://pan.baidu.com/s/1RPI5gV8vTzEMH-TXYfBK8g
提取碼:bros
歡迎加入游戲開發(fā)群歡樂攪基:1082025059