2018年5月31日 星期四

「傘之下」開發記錄—18

發生Boss戰前,通常會段劇情動畫,營造一種Boss要來了Σ(*゚д゚ノ)ノ的感覺
所以接下來幾篇,就是要來說遊戲中的「對話」和「劇情」系統
這兩個系統,是這遊戲裡最複雜,同時也是最不滿意的東西ww
硬來的東西根本多到不能直視

嘛總之,先來看一下遊戲的對話長怎樣:
對話框是分成上下兩個,所以要操控的東西也變成兩倍……
不止啦www
為了避免各種bug,要調整的東西說不定是2.5倍
為甚麼當初要設定這種對話視窗呢?這就要問企劃
……咦,企劃就是我耶ww((自M

要寫成這個對話UI,除了要編寫怎麼控制外,還要建立一個基本的架構,來輸入對話資料:
在對話中,要更改的資料有:
.名字
.人物頭像
.說話內容
.要使用上/下對話框
.對話結束後的行動

這五個列為一個class,再在公開面版中隨時修改
然而,因為遊戲中有時會出現對話分支,因此再以一個class包住這個class "XDD
當出現分支時,選擇哪個class的資料

架構建立起來,再由別的腳本調用後,在面版中大概長這樣:
一個不太人性化的資料輸入版面w
有時亂到自己都不太懂Orz


Anyway,有架構後,就用另一個腳本來讀取資料
在腳本啟動時,會先偵察有沒有分支對話
沒有的話直接讀取對話資料,有的話則由其他腳本控制要讀第幾個分支
然後:
當按下對應按鍵時,會呼叫ClassChange
ClassChange內,則傳送「上/下對話框、名字、頭像、對話後動作」這四筆資料,給予TalkUI腳本(控制UI的腳本,會在下篇文提及)
最後再呼叫SayChange
SayChange內,會傳送對話內容給TalkUI腳本
但在傳送之前會有一個判斷式:有沒有超出對話行數
在腳本內宣告一個 int(SayNo)……SayNumber的簡寫啦不是另一意味上的SayNo  XD
當每讀取對話一次時,這個int就+1。假如SayNo大於對話行數時,就會自動跳到ClassChange,更改其餘四項資料——畢竟超出行數的意思,就是指該名角色暫時說完話
跳到ClassChange的同時SayNo變回零,同時CharacterNo+1。CharacterNo是用來偵察「有多少段對話」用的,和SayNo異曲同工
當CharacterNo超出「對話段數」時,則完結對話,呼叫ResetNumber
ResetNumber裡,除了把SayNo和CharacterNo重置外,一堆和對話(劇情)相關的參數也重置,並關閉對話視窗
因為在進行對話時要限制玩家移動
而且進行對話時可能會出現劇情……這部分也要限制
因此出現了一堆bool參數w

說了這麼多,這部分只是「傳送資料」而已
對話UI裡的更動,還需要另一個腳本協助才能達成
這部分就留在下篇吧ww

2018年5月30日 星期三

「傘之下」開發記錄—17

上一篇結尾是在講判斷Boss動作的bool
這次會貼上那段void,所以應該會更清晰一點
(沒貼在上篇,是因為在這裡的關聯性更大)

在進行判斷之前,要先講到為甚麼Boss會中止行動
當Boss受到玩家一般攻擊時,會進行防禦
在打了第一下之後,為免Boss被攻擊多下,多次觸發程式產生Bug,所以會取消攻擊判定
接著偵察被打的方位,以免防禦錯方向
防禦時會停止其他協程,然後呼叫反擊協程

反擊開始時,會設定攻擊強度(為了把玩家推開),同時更改攻擊範圍
最後則是呼叫void,繼續Boss的行動



除了一般攻擊外,Boss會被掉落的果實砸傷(或者說,Boss只會在受到果實攻擊時才會扣HP,一般攻擊時會完全防禦)
當被果實打中,會優先播放受傷動畫
然後和防禦反擊時一樣,呼叫重新行動的void


最後這個void,其實也不是甚麼厲害的東西www
就只是根據bool的開關,判斷呼叫哪個協程而已


Boss的所有行動大概就是這樣
是有些小細節的東西沒有貼出來啦,因為那些都是沒優化過硬來的東西(黑歷史)

最後再補充一下,上面幾張圖有看到個名為NextSkill的bool
那個……是沒用處的東西"XDD
因為BossAI是整個遊戲中第3個寫的腳本,是超早期的產物
雖然中途有優化過一次,但有些東西忘了刪掉_(:3」
你就知道我當初多亂來

2018年5月21日 星期一

「傘之下」開發記錄—16

小怪AI講完,當然要來個大Boss (`・ω・´)
然後因為Boss的程式太長,還是會分個兩篇就是

首先先說說Boss的攻擊模式
牠的主要攻擊為「打地板」和「高速旋轉」,這兩套動作之間的循環
兩套動作都是用協程計時,不同時間播放不同動作,組合起來才是一整套攻擊

打地板的部分:
.先是重擊地板時(攝影機同時晃動),攻擊判定範圍會增大
.果實從樹上掉下(果實自帶「可擊飛物品」腳本,以及一個控制動畫用腳本)
.接下來準備去下一組動作
(HitFloor和Rolling的bool在文末解說)


高速旋轉的部分:(Part1)
.Boss會在空間裡左右旋轉,為了避免旋轉時超出範圍,因此一開始先宣告好一個位置,用以旋轉後固定座標
.更改攻擊範圍,同時取消旋轉期間的被攻擊判定(以免被打中出Bug)
.把Boss的碰撞器更改為觸發器,重力也改為零。會這麼做,是因為用碰撞器的話,移動途中擊中玩家時會有一個「推擠」,Boss也就不能準確地移動到位置上
.把設定都弄好後,最後就讓Boss進行位移


高速旋轉的部分:(Part2)
.在旋轉途中,Boss會有一個「跌倒」動畫,這時再往前滑行一小段(這都是用時間或數值來調整,有沒有更人性化的調整方法現在還在測試)
.滑行停止後,Boss的位置固定在設置好的座標上
.恢復碰撞器及重力的數值,以及恢復被攻擊判定
.旋轉後要面對玩家,因此會有一個Flip的效果


兩套動作大致這樣,最後來講HitFloor和Rolling的bool
在設定上,Boss被一般攻擊打中時會進行防禦反擊(另一套動作),那時會停止「旋轉」和「打地板」的動作,當反擊後才重新回到這兩套動作循環裡
那這個「重新回到循環」,就是靠bool來決定
Rolling = true的時候,反擊後會切入「旋轉」的動作再次展開攻擊。反之亦然
所以當一套動作已經完成了的時候,就會開關對應的bool,讓Boss繼續行動

2018年5月20日 星期日

「傘之下」開發記錄—15

通用參數之後就是敵方的個別AI
因為地圖上的一般敵人有兩種,所以只挑其中一隻來講
結構大致上是差不多的030

調用通用參數裡的Dis,當進入攻擊範圍時就攻擊,當距離太遠時則待機
為了避免「動作」和「移動」不同步,所以「待機」和「跑步」時都設定一下速度參數

第一張圖是基本的移動,接著第二張圖算是輔助性質的void
當Hurt時:中止其餘動作,優先播放受傷動畫。呼叫StopMove。
(然後我現在才發現圖片中的StopMove多了一個 i 字"XDD)
當StopMove:敵方強制停止移動。假若HP大於0時,呼叫MoveAgain
當MoveAgain:讓敵方重新開始移動,回到第一張圖

基本上敵方AI都會是類似的模式
理論上這些行動都能分割成通用腳本,動作之間計時也能用AnimationEvent來做
但因為這是早期腳本之一,只能強硬地寫成這鬼樣子www
(沒錯雖然這篇文的發文順序較後,但卻是最早期腳本之一XD)

假如將來繼續開發下去,應該至少把「受傷」的部分分割出來
因為說不定會出現有「霸體」的敵人,這時只要把受傷腳本移除就好
不然每只敵方都從程式碼調整的話,開發時間說不定會長個兩三倍(笑

2018年5月16日 星期三

「傘之下」開發記錄—14

除了撿取「暗之花」外,打倒敵方亦會噴出花瓣
算是半延續上一篇,這次主題是敵方AI
……這兩者其實關係不大,只是想讓文章更有連貫性才這樣寫XD ((硬來

敵方AI,主要分為兩類腳本
一個是「通用數值」,另一個是「個別行動」
這篇首先會先講「共用」的部分
每只敵人都有HP,不然打不死,所以明顯地這是個共用數值
除此之外,敵方的動畫器、碰撞器、剛體等參數亦是在這裡宣告,再在其他腳本中調用
在圖片中有看到名為Dis的參數,那是用來計算敵方和玩家的距離。畢竟每只敵人都有索敵範圍,當距離超過數值時,則執行別的動作。


上面是關於敵方自身的參數,而敵方攻擊的參數則另開一個腳本
會分開寫的原因,是因為敵方的攻擊模式不同,腳本掛上的物件亦不同
 (有的掛在攻擊觸發器中,有的掛在敵方本體身上)

攻擊強度,印象中在「玩家受傷」那篇中也輕輕提到。那是影響玩家彈飛距離的參數
這個腳本中較需要說明的是OnEnable和OnDisable的部分

依現在的程式碼,敵方在攻擊時會產生一個觸發器(SetActive),當這個觸發器碰到玩家時就會構成傷害(OnTriggerEnter)
而攻擊完畢後,SetActive = false,觸發器大小變為最小

會這樣設定,是因為自己測試時,不知為何敵方的第一擊會沒有觸發判定(可能是我設定出了問題吧_(:3」)
然後就只好讓觸發器大小重置,強制把它Reset一下


通用腳本大致上就這樣
因為這次是第一次挑戰分割腳本,所以分得很不漂亮ww
很多參數都有點硬來,有些該通用的參數也沒宣告好。總之要優化這腳本是個大工程
不過說實在的,如果沒有硬寫出來,也不懂得要怎樣優化就是XD ((經驗值up

2018年5月15日 星期二

「傘之下」開發記錄—13

現時遊戲中可撿取的物品,除了劇情需要的任務物品外,就只有「暗之花」
當撿取「暗之花」時,會噴出五朵花瓣。這些花瓣就像金幣一樣,主角碰到後會收集起來

收集花瓣的效果

撿取物品的程式在上一篇講過
在那個的基礎上,再設定一個「撿取物品後會噴出花瓣」的機關就好
而要讓花瓣有「噴出來」的感覺,遊戲裡是用AddForce的方式,為每片花瓣加上作用力
加在花瓣上的作用力,往上的力度是固定的,而左右則是Random一個數值,以增加隨機感
花瓣在左右移動時,為了加強動感,亦讓它會隨著左右移動而旋轉
(其實有嘗試過用程式模擬這樣的效果,但功力不足((ry _(:3」)

花瓣噴出來後,會停留在地上,等待玩家收集
這個功能是用OnCollisionEnter來實現
在玩家碰到花瓣後,花瓣會飄向左上方(HP UI 附近的位置)
當初要實現這功能時,碰上的問題為「花瓣與UI的座標系統不同」

左邊是一般GameObject的座標,右邊是UI 的座標

為了避免玩家使用不同解析度開啟遊戲時,花瓣的位置跑掉,需要把UI的座標轉換成世界座標
理論上,座標只需要轉換一次,花瓣位置就不會太偏差
只是在花瓣飄行的過程中,玩家仍會繼續移動,所以UI位置仍會出現差異(雖然不太明顯)
因此,座標轉換的程式碼是寫在while裡面的,讓位置能持續更新
這樣會不會太吃效能,我就不太清楚了_(:3」

在花瓣飄到指定位置後,會播放粒子特效,提示玩家已收集到花瓣
與此同時,花瓣獲得數會+1。因為這數字會跟隨玩家一輩子(?),所以是宣告在共用參數腳本中


功能大致上是這樣,但老實說這腳本我也是很不滿意ww
畢竟現在每朵花瓣都要加上Rigidbody,感覺上就是個土法煉鋼的做法
如果能用腳本做出「噴發」的效果的話,在物理操控上也方便管理一點

只是嘛……這是需要花點時間研究的東西
而所謂的畢製,就是你永遠沒時間去搞研究w

2018年5月12日 星期六

「傘之下」開發記錄—12

地圖上除了有「可擊飛物品」外,也有「可撿取物品」
要講到這個,亦會提及到遊戲的關鍵物品「暗之花」

嘛不過,首先來看看撿取是甚麼東東
當玩家進入觸發範圍後,會出現一個特效提示
這個提示的出現位置,則設定在「可撿取物品」的位置上高一格(如下圖)

這是避免提示和物品的圖示重疊,影響判斷,因而這樣設計
在提示出現的同時,CanGet = true。這狀態下再按「Z」,就能觸發撿取
因為「Z」亦是攻擊按鍵,所以在進入撿取範圍內時,設定成「Z」不會攻擊,只執行撿取

撿取期間,提示特效會變成撿取特效,其位置亦改為與撿取物相同
(從原本的y = 1改成y = 0)
而在0.6秒後(配合動畫),將物品的SetActive改成false
兩者配合下,就能達到撿取的效果
 

而當玩家沒撿取,就離開觸發範圍時,提示特效的z變成-10
假若沒調過攝影機數值的話,在遊戲視窗中不會顯示圖示

沒使用SetActive的原因,是因為聽說「改位置」比較省效能
所以……以後應該嘗試在地圖外設立一個物品區
當東西不需要用的時候,直接傳往該區域,而非使用SetActive
不過也不確定這樣能不能用就是www