2018年9月2日 星期日

魔物設計那回事02

  上篇講到設計魔物的習性,會方便後面的作業。那習性要怎麼設計好呢?
  第一個方法是用拉霸((咦
  把「質地」、「特性」、「物種」等組合一起,再拉一下就萬事OK (ゝ∀・)
  比方說抽到「塑膠」、「放電」、「蝸牛」的話,可以設定一只「身體由軟膠組成,在大城市內到處遊走幫機械人充電的大蝸牛」,就像我寫的這篇小說一樣 (`・ω・´):
  https://www.novelstar.com.tw/books/849.html
  對我在置入性行銷對不起 ⊂彡☆))д`)


  拉回正題,第二個方法是參考現有的生物。
  如果魔物是條魚,那牠可能生活在水裡。當然也可以完全相反的走在陸地上。畢竟是「魔物」,沒人能夠質疑你的設定w(但玩家可以不喜歡這設計)
  所謂「參考」,就只是讓自己更方便發想的一種工具。就算出來結果和參考對象完全不同,那也有它的價值存在。


  第三個方法,是用魔物的行為來逆推。
  咦?不是說先有「習性」後才推敲出「行為」的嗎?嘛,這大概是「雞與雞蛋」的問題吧w
  在這裡講一下,<傘之下>的魔物設計中,第二和第三種方法都有用過。
  玩家們看到的第一只魔物「小波諾」:

  是在參考兔子,最後成果只有「耳朵長」這點和兔子相像。甚至說,垂下的那兩條(?)在設定上根本不是耳朵,而是「能控制的肢體」而已ww
  PS. 頭上那兩個像角的東西才是耳朵。


  而用第三個方法設計出來的魔物,沒有呈現在螢幕上XDrz
  牠預定是在第二章出現的魔物。因為是第二章了,所以想來一點「遠攻型」的敵人。而第二章設定上是在離島,那用「泥土」來當作攻擊武器好像挺符合世界觀的耶owo
  那,誰來丟泥巴?
  直覺上猴子,但我覺得猴子不可愛((喂
  這麼說來,鹿角有點像鏟子……?好,我喜歡鹿。拍板!
  接下來就是,牠為甚麼要丟泥土?
  與泥土相關的東西……花!鹿角除了鏟起泥土還可以裝水,然後對花朵灌溉ヽ(✿゚▽゚)ノ
  牠們打理的花園等同自身地盤,當有外來者出沒時,會丟泥土驅趕對方。感覺不錯!((自己說
  於是乎,第二章魔物「澆花鹿」就誕生了。

  我們現在是在做遊戲。因關卡設計需求,誕生出新的攻擊模式,再用其發展出魔物的背景設定,這也是一個快速的方法。
  但……既然早已經決定好攻擊模式,那其實不用設定得太詳細,已經可以直接動筆了不是嗎?
  老實說的確可以這樣w
  不,或者說,很多遊戲根本不用設定得這麼詳細。畢竟玩家((ry
  所以說這是自我滿足,個人發廚而已。
  但要知道,做遊戲是件辛苦事,能完成一款遊戲都是耐力賽。如果中途沒有這種「自我滿足」和「成就感」補給一下的話,可做不下去吶 (つд⊂)


  而且啦,有完整的設定,也是美術參考的一個依據。
  我自己亦是個美術。儘管企劃的人已經是自己,對世界觀熟悉無比了,當初要下筆時還是有困難XD
  在要畫魔物時,我就是透過魔物的習性,勾勒出牠們的草圖。再思考牠們的行為,細化出外型。
  當然,我相信有很多美術不用完整設定,也能畫出吸引人的魔物。
  這就只能說每個人的作法不同吶:V

  重點還是那句:我廚得很開心啊ξ( ✿>◡❛)

2018年9月1日 星期六

魔物設計那回事01

  我覺得世界上總會有些企劃,在遊戲設定上有不可退讓的部分。
  不是說「遊戲平衡」、「關卡設計」等遊戲性的考慮(這些是每個遊戲企劃都絕不可退讓的東西XD),而是在說「世界觀」。
  有人可能對武器十分考究;也有人可能對遊戲內的社會結構充滿構想。
  會提到這些,明顯地我就是在某些地方異常偏執的傢伙(゚∀。)


  從標題也看得出來,我「不可退讓」的地方是「魔物設計」。
  <傘之下>雖然只出現三種魔物,但其實後台還有好幾只魔物的設定。沒公開的原因分明就是美術來不及XDrz
  而這些魔物,牠們的設定有時還會比主角們詳細((咦
  嘛或者應該說,「角色」和「魔物」要設定的東西不一樣。


  以「人類」為主要角色時,設定的會是他們的性格、出生背景等等。因為「人類」是我們所熟悉的生物,不用再刻意解釋這是甚麼。
  反過來說,「魔物」通常是一般現實世界不會出現的東西(會出現的話那會稱為「動物」),因此我們(企劃)才需要去「設定」。
   設定些甚麼?這就要看你想要多詳細及有多少時間啦(◔౪◔)


  會做這一行的,可能都有在網絡上看過「怎樣設定吸引人的角色」之類的東東吧?魔物也是角色的一環,當然也可以套用這些知識。
  不過在這之上,除了魔物的外型,「生態」、「習性」才是我特別花時間去設定的部分w


  沒玩過「魔物獵人」,都看過別人貓車。
  以MH  World 來說,玩家在開打前,是在地圖中尋找目標的「足跡」。換言之,目標不是永遠出現在同一個座標,牠會依照AI到處跑。
  到處跑?跑到哪裡?要設定這些東西,就是「習性」發揮威力的時候。
  魔物出沒的地點,可能是「潮濕、溫暖、不被陽光直射」的地方;也可以是「無風、大太陽、旁邊和自身有保護色」的地方。
  .前者可能是只「會走路的蘑菇」。
   因為喜歡陰暗,被光照到後會跑到其他樹蔭下躲一躲。所以要狩獵時,「樹蔭下」是最能發現牠們的地點。
  .至於後者,maybe 是只「躲在沙子下的棕蛇」。
   無風和保護色可以降低牠們被發現的機率,而太陽底下使牠們更容易看見從上空飛過的獵物。因此要找到牠們,最快的方法是一邊走一邊拋荔枝,讓牠們以為獵物出現而自投羅網。
   咦?為甚麼是荔枝?誰知道,或者牠們喜歡吃吧(゚∀。)


  上面兩個寫好玩的例子,帶出了「習性」影響「行為」這件事(應該有吧?((心虛
  企劃出魔物的習性,那魔物的AI也會隨之衍生出來。牠怎麼攻擊、怎麼移動等等,都有利美術進行更完善的動作設計。
  而對玩家而言,也更容易掌握牠們的行為,從而找到攻略法。
  所以設定好魔物的基本習性, 或多或少也方便之後的作業(個人認為)



  好了,接下來就是我更發廚的地方了w:

  好不容易設定好一只魔物,之後呢?當然是設定更多啊((笑
  一個地區不會只有一只生物,企劃可以隨便開坑。但同一地區的生物習性不可以有衝突。
  喜歡「潮濕」的魔物,不會和喜歡「乾爽」的出現在同個地方——這是最簡單的例子。
  稍為複雜(?)一點的例子是:
  魔物的習性都符合地區環境了呀,應該沒問題了吧?之後才發現把「上面提到的棕蛇」和「住在地底的生物」混在一起了。
  假設地區中只存在著「棕蛇」和「五種地底生物」。問題來了,其他生物都出沒在地底,那依靠進食地面上生物的「棕蛇」可以吃甚麼呢?
  沒有,沒得吃。不吃土的話牠會餓死。可是如果要吃土,牠的習性也會相應改變才是。
  所以,這兩系列的生物就起了衝突。而最簡單直接暴力的解決方法,就是改變魔物的習性。又或者額外創造出「地面上的生物」。
  選擇後者的話,創造多少只才好呢?考慮到生物多樣性……打住。因為這裡是遊戲,一只就夠了。不然美術會殺人(((゚Д゚;)))
  又或者說,其實一般玩家也不會注意魔物生態甚麼的,遊戲能玩就好。
  那,為甚麼還要花心思設定這些有的沒的?



  因為,廚啊ξ( ✿>◡❛)

2018年6月7日 星期四

「傘之下」開發記錄—22

程式大致上說完了
會用「大致上」這個詞,是因為還有個BGM腳本未講w
但這個腳本,基本上只要貼張圖:
基本上也不用再補充甚麼了ww
(所以上篇文才說會有個小番外)

 ————分隔線————

那麼,今次主題其實是BGM
遊戲裡的BGM和部分音效也是我自己製作的
雖然我在音樂方面算不上厲害(甚至比我的程式還爛w),但做下來還是有點心得

先來聽聽遊戲中的音樂……
呀,其實音樂現時只是寫好樂譜,還沒混音,所以聽起來會很生硬。
打個比方,就是只畫完線稿還沒上色_(:3」
嘛不過畢竟是開發記錄,不完美的東西也要po就是w:

. Title裡播放的Opening
 
我自己作曲時,通常會先想像一個情景,然後盡量用旋律去描述那個畫面
Opening的情景,是「在草原上踏出腳本,看到豁然開朗的景色。帶出『踏上旅程』的感覺」
然後之後會想玩點花樣:隨著主角的夥伴增加,Opening的樂器就越來越多

在這裡先補充一點,設定上,每個角色都有他的代表樂器。卡尼是鋼琴白鍵;雅蘿是提琴
所以遊戲一開始,都會以鋼琴為主,提琴為副——這是理論上的說法w
Opening現時只有鋼琴,是因為我來不及寫提琴的部分_(:3」
沒其他理由了((結案
嘛不過現在清新一點的風格也不太壞吧((自己說



接著是遊戲關卡裡的音樂:

 .一般場景裡的BGM
遊戲的開頭,是以「熟悉操作」來設計的
除了有「開關雨傘」的教學外,更想讓玩家無意識地熟悉跳躍距離(所以設計了不少平台讓玩家跳過去)
也因此,這裡的BGM加入了一點「彈跳感」
只不過太彈跳的話,和我想給予的感覺不一樣,所以加了支長笛下去中和一下
其實原本是想用小提琴的,但小提琴音色沒調過的話會很恐佈
恐佈到我想砸電腦(((゚д゚)))
所以最後還是長笛好www



最後一首是打Boss的BGM:

.Boss戰
因為Boss戰氣氛較為激昂,這裡套上小提琴比較沒問題owob
這裡整首曲子都是在描述Boss的動作行為
原本Boss的動作配合音樂來移動的,但因為節奏太快,玩家很難打中Boss(尤其不太擅於動作遊戲的玩家)
因此在校內展之後,就把Boss的動作間隔調長,降低難易度。BGM也就沒法配合了
不過說回來,在展場這麼吵的地方,其實很難注意到BGM就是www

現時遊戲內就這三首樂曲
和原本預定的五首還有段距離Orz
畢製的時候就是很容易企劃發太大,東西都來不及做有點遺憾
但這就當作是一個重新審視自己能力的經驗吧/

2018年6月4日 星期一

「傘之下」開發記錄—21

這次可以說是最後一篇關於程式的心得(之後還會有篇番外(?))
所有主要的系統架構都稍為講過一下,剩下的就是「Title」了
遊戲的Title長這樣,主要有三個選項供玩家選擇
當按下「上下方向鍵」後,箭頭位置亦會跟著移動


這裡的寫法,是用一個 int 來記下位置
當按下按鍵後, int 會有一個增減,而箭頭會根據 int 來移動自身座標
為免被玩家重覆按下按鍵,令到 int 亂掉,所以判斷式裡也限制 int 不能超過最大值


當確定位置後,玩家按下Enter時,會因應當前 int 來判斷執行甚麼動作
比如 int = 0(開始遊戲)時,會轉換場景


轉換場景時,因為每個遊戲都會有讀取時間
為免讀取期間畫面一直卡住,通常都會有個「讀取畫面」,讓玩家知道遊戲有在運行
這一段主要就是在顯示讀取進度,以及讓剪影跟著進度條跑


Title其實也是個不太複雜的架構,基本上這樣就講完了ww
然後程式方面的心得也一樣講完了ww ((灑花
沒想到寫著寫著居然寫到21篇 ((抖

2018年6月2日 星期六

「傘之下」開發記錄—20

最複雜的對話系統講完了,接下來是「最硬來」的劇情系統ww
現時的劇情系統,算是依附在對話系統下的
當對話進行到一定程度時,會把UI關掉,然後進入劇情動畫
這個「一定程度」的意思:
就是對話系統中有提到的,「對話後的動作」裡的選項(After Talk)


現時的做法,是先宣告一個 interface
然後 interface 裡再設立一個void (VoidEvent)
每當執行VoidEvent一次,就會自動執行對應動作
直接看上圖的例子,VoidEvent裡其實只有兩行
一個是 int 增加,另一個是呼叫下一個 void(會被 int 影響)
所以每按一次按鍵,就會執行不同的 void,達成一個劇情動畫流程

在每個 void裡,會寫入對應動作
比方說攝影機移動、生成特效之類的
……還有因為當初硬來,甚麼都沒設定好,所以還要控制對應的bool 參數w
大致上整個系統長這樣子,只要和對話配合好的話,台面上還是不太有問題就是##


總而言之,這是個我自己都會寫到亂掉的系統XD
要優化的話,除了把參數都事先設定好外,應該還會把經常會用到的動作寫成一個void
比方說攝影機移動:
void CameraMove(Vector3 _target) {...}
很可能會寫成這樣,到時只要呼叫這個 void,並傳送一個座標過去就行了
作業上會快速方便許多

2018年6月1日 星期五

「傘之下」開發記錄—19


上一篇傳送對話資料後,會來到下面這組腳本
這腳本用來控制整個對話UI,包括UI的淡出淡入、文字和圖像切換等
在啟動對話UI後,會先讀取名字,然後判斷他是出現在上/下對話框
先假設現在使用上對話框。如果對話框沒有顯示,則讓對話框淡入(設定上,還沒有對話出現的對話框,在起始不會出現)
淡入後,會把名字和頭像進行切換。而「對話內容」由另一個void管理(下一張圖)
當上下對話框都已出現時,「沒在說話的角色對話框」會變為暗灰色
最後,在該段對話結束後,會判斷有沒有劇情或UI

更改對話內容的void裡,同樣會先判斷這是上/下對話框,之後才更改對話內容
另一個比較特別的是:Replace \\n , \n
先說一下,\n是用來自動換行的。但輸入這個語法後,Unity好像會自動把 \n 變成 \\n
所以這時需要手動把它調回來"XD(把 \\n 變回 \n)

不過說實在,以我自己的實力不可能知道這種東西的ww
那時在查資料時剛好看到別人的教學,就拿來用一下
可惜的是現在找不回那教學,沒辦法附上連結_(:3」

能切換相關資料,亦要防止對話互相干擾
因為現在的設定是按下相關按鍵(比如Z)後,對話就會跑下去
假如沒設限制,那在「對話一」時按下Z,「對話二」也會跟著跑。到時所有對話都會亂掉

現時遊戲中的防禦機制,會和遊戲物件的Component有關,所以先解說一下:
.控制對話UI用的腳本是掛在UI上的
.每段對話分開成不同GameObject,裡面掛著對話資料(上一篇文的腳本)和觸發對話腳本(等下會講到)

那麼,我是讓所有對話在一開始時都 inactive的。當觸發對話後,對應的物件才變成active
至於怎樣才做到這點,那就是宣告一個陣列來抓取子物件(GetChild)
每當要觸發對話時,腳本都會傳送自身子物件的位置,讓子物件啟動
宣告子物件位置的程式碼,則會在下幾張圖中說到

在那之前先繼續UI操控的部分:
當全部對話結束後,會呼叫ResetImage,把相關參數都重置(為免下次啟動UI時,會有殘留的資料出現)
然後對話框便淡出


UI控制大致上是這樣,然後今天就一氣呵成的「觸發對話」也說完
當玩家碰到觸發器後,會自動開啟對話UI
上圖的最後一句,就是用來傳送子物件位置的程式碼(用Debug.Log測試過,它會回傳一個數字(int))
除此之外,在觸發器腳本上,有設置一個下拉選單,選擇是哪一種觸發方式
現時分別設置成:
.對話完後就不會再重新對話
.同樣對話完就不會再觸發,但若對話裡內含劇情動畫的話,就要選擇這方式
.對話後離開範圍,再次踏進觸發範圍時會被重新觸發

目前主要用到的就這三種模式……其實還有寫一個「按下按鍵後才觸發對話」的模式,但因為美術部分未準備好,於是先把它拿掉_(:3」

最後啦,當在離開觸發範圍後,會回傳一個「-1」給UI的防禦機制
這個「-1」在void裡已設定好,代表讓GameObject inactive
與此同時,對話中的參數也重置,以免出Bug


 ……第一次寫這麼長w
認真來說,這個系統的複雜度應該可以分3、4篇
但那樣的話感覺會變成教學文——我還沒有實力這那種東西
腳本內一堆誤人子弟的程式,被看見就不好了XD
所以我一直以來都只是講講基本架構。一來用於整理自己思緒,二來……也或多或小希望這些邏輯概念刺激到別人啦 ((自肥ww

總之,感謝看到這裡
如無意外,程式架構的東西還有三篇就完了
還在想之後要不要寫美術心得_(:3」

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

2018年5月11日 星期五

「傘之下」開發記錄—11

開收傘是遊戲中較特殊的操作。而除了這個之外,還有一個較特殊的攻擊
 「上挑攻擊」

在前幾篇文中,在講攻擊判定時也有輕輕提到過
這個「上挑攻擊」,設定上是對魔物無效,只能打擊場景上的物品
因此,延伸出一個「可擊飛物品」的腳本

掛上這個腳本後,並增加碰撞器,物品就能被擊飛(預定之後會增加公開參數,設定被擊飛的距離)
設定上,被擊飛的物品,會對敵我雙方都構成傷害
但因為玩家在擊飛的瞬間,就有可能碰到物品而受傷。因此在觸發擊飛的同時,先取消物品與玩家的碰撞
在擊飛的同時,會更改物品的Tag和Layer,希望能減少判定上的錯誤

而在擊飛之後,當沒碰到敵人和玩家時(主要是碰到地面後),變回原來的Tag和Layer
這時才能用「上挑攻擊」繼續擊飛物品


……好了,基本上這次沒甚麼好說的了www ((好短Σ(*゚д゚ノ)ノ
因為是個尚算簡單的東西
那麼為了充一下字數,稍為提一下Physics2D好了
(這東西很難拍照,所以沒圖片抱歉……)

Physics2D,是設定不同Layer的物品,會否進行碰撞
而這文章講到的兩個Layer,SceneItem基本上只會對「地面」和「玩家的攻擊」起反應
至於FlyAway則是對「地面」、「敵方」、「玩家」起反應
其實有想過,如果FlyAway的時候,敵方剛巧在攻擊途中時,物品會被打回來
但這會牽動到更多判定問題,在有限時間內(畢製展出前) 無法完成,所以就這樣算了
假若有機會發展下去的話,應該會把這功能加進去
畢竟……這感覺很好玩d(`・∀・)b

2018年5月10日 星期四

「傘之下」開發記錄—10

延續上篇,這次來講雨傘系統


開關雨傘的判定,是寫在主角的操控腳本中的
當玩家按下左邊的Ctrl鍵時,判斷當下狀態為何,再進行相應動作
eg. 狀態:開傘中 進行動作:收傘
亦即兩者呈相反就對了

然後,當在地上進行動作時,強制停止移動
因為當初繪製動畫時,開收傘的動作是停在原地的
不停止移動的話,會看到主角腳沒在動卻會左右移動(怕

再來就是,現時遊戲設定:開收雨傘的動畫播放時,不會被攻擊到
會這樣設定,是以防動畫出現錯誤
因為在開收雨傘兩種狀態下,跑步、跳躍等動畫都是不一樣的
要實現這種判定,至少有兩種方法
先說我現在在用的:更換動畫器

當開收傘的狀態切換時,動畫器亦跟著轉換

 收傘時的動畫器

開傘時的動畫器

這樣的做法,是減少一個動畫器的複雜程度。要修改個別動畫時,能更方便地找到問題點
但限制是兩個動畫器的參數要一樣(不論參數類型還是命名)
因為是依同一行程式進行控制,稍有差錯便會出現錯誤訊息


而另一個方法是,把動畫都放在同一個動畫器中,然後多加一個布林參數「OpenUmbrella」(舉例)
然後在開傘與收傘兩組別的動畫中,都加上對應的「OpenUmbrella」,這樣也能獲得相同效果……應該說,我一開始的做法就是這樣ww
但之後因為出現各種錯誤,以及管理不方便,於是變成現在的「更換動畫器」


話題拉回來,因為要更換動畫器,如果這時被敵人攻擊到,就有更大機會出Bug
雖然有嘗試過各種方法去解決這問題,但個人功力不足,始終都有Bug
於是索性取消碰撞判定(硬來

最後再說一下更換動畫器的時機
那就是AnimationEvent出場的時候啦~

在開收傘的結尾加入腳本,就能讓兩個動畫器無縫接軌
讓我們讚嘆AnimationEvent ヽ(✿゚▽゚)ノ


話說,最近的篇幅較長,以及多加一些圖片來講述
是因為個人覺得這幾篇有點複雜,單是口頭上說說的話,除了我以外大概沒人懂吧ww
說不定現在也沒人懂就是(心虛

2018年5月9日 星期三

「傘之下」開發記錄—09

除了HP外,遊戲中還設置了「健康值」
這個「健康值」是「當下雨時,沒打開雨傘就會扣減」
所以這是三段有關聯的程式組合而成的系統(「健康值」、「下雨系統」、「雨傘系統)
但因為一次講完的話會太長,所以這次只講「健康值」和「下雨系統」

首先是下雨系統的部分
整個系統都是以協程來計算時間
當日照時間完結,便開始下雨,反之亦然

日照時間開始計算前,主要關掉下雨特效即可
而下雨時間開始前,要關掉原先的BGM,改播放下雨音效,同時開啟下雨特效

如果單單只有下雨特效,整體氛圍會略有不足
因此在兩個協程之間,加了陰天的協程
主要控制一塊陰天的畫布,來增加視覺效果

當然這個陰天畫布,也可以直接寫在「日照/下雨」的協程裡
但因為下雨前和下雨後的陰天時間,亦是氣氛渲染的一部分
獨立成一個協程的話,可以有更為彈性的變化


當現正身處下雨時間的話,名為Raining的布林值變為true
Raining = true的時候,若果沒打開雨傘,每3秒扣減一點健康值……
……好吧,其實是扣0.005的健康值www
為甚麼是這個數字,和我所使用的圖像有關係
健康值的圖示,原圖是一個圓環,但因為只需顯示1/4,所以FillAmount的上限為0.25
(測試過原圖直接用1/4,但Filled會出現問題,因此只能調小數值)
健康值原本設定上限是50,每次扣減1。在經過換算之後,就變成現在的0.005

總而言之,健康值每次會扣減相應數值
當數值跌至一定程度時,圓環顏色會更改,以提示玩家
與HP一樣,健康值是讀取共用腳本的數值,來修改圖像自身的顯示
這樣在管理及調整方面更為方便

2018年5月7日 星期一

「傘之下」開發記錄—08

受傷後自然會有HP扣減
而這遊戲中不是以血條的方式呈現HP,而是用花朵來表示(共五朵花)


當受到傷害後,花會消失
相反HP恢復後,花朵會重新出現
要實現此效果,這裡使用的方法是「開/關HP圖片的顯示」
花朵(HP)的位置是事先固定好的,HP有所更動時,才開關Image
因此程式碼需要做的,就只是那個開關


HP這東西,它的上限很多時會因一些道具、升級之類的而提升
因此一開始宣告HP的圖片時,是用GetChild的方式來宣告,以便日後增加HP時,不用重新宣告
至於MaxHP的數值,可以用transform.childCount來獲得

HP圖片宣告後之後,用兩個數值來偵察HP有沒有更動
一個是GameManager裡的HP(受到傷害時即時扣減)
而另一個是LastHP,當LastHP不等於PlayerHP時,就會呼叫HPChange來更動花朵數目
呼叫完之後,LastHP的數值亦相等於PlayerHP


在HPChange裡,宣告一個參數,計算PlayerHP - LastHP的結果
假設原先HP為5,亦即LastHP = 5。這時若受到一點傷害,PlayerHP變為4
那麼得出來的結果是-1,表示這是受到傷害
因而執行「花朵消失」的程式裡(扣HP)
反之,則執行「花朵出現」的程式(恢復HP)
而這兩套程式,結構基本上一樣,只是參數上的不同

在程式裡設立一個for loop,偵察扣減了多少HP
然後在loop裡面的a數值,其實等同PlayerHP的數值
要特意分開的原因,是為免HP的顯示出現問題
因為受到傷害時,可能不只扣減1 HP
當受到超過2或以上的傷害時,直接使用PlayerHP的話會產生錯誤

左邊是使用PlayerHP計算的結果,而右邊是使用 i 值
因此,假若每次傷害固定只有1點的話,PlayerHP會較方便
但若多點傷害時,使用loop來計算才避免顯示錯誤


最後,通常HP這類數值,都有可能一次「扣減/恢復」超過「下/上」限
因此當超過時,要把數值拉回來,不然可能出現些錯誤訊息

至於HP歸零時,因為這遊戲的死亡動畫,不是更改玩家的動作,而是獨立一套動畫
所以寫在PlayerHP的腳本裡,以方便管理