Unity官方教程:Roll A Ball(PM版)

這篇文章默認大家已經對Unity3D和PlayMaker有一定的了解,所以沒有把所有操作步驟都寫的非常詳細,不太看得明白的同學可以先行閱讀:

視頻教程已經上傳YouTube:[教程]使用PlayMaker重制Unity官方“滾動小球”教程
視頻文件及素材資源下載地址在:百度網盤


Unity3D官方教程是非常非常優秀的新手入門學習資源,將其PlayMaker化是一個挺有趣的體驗。

本教程是Unity官方教程第一篇,原教程地址:Roll-a-ball tutorial


準備場景

scene_setup_01.png

Roll-a-ball的場景很簡單,一塊2×1×2的藍色Plane做地面(命名為Ground),四個0.5×1×20.5的Cube做墻壁(放在Walls空物體之中),墻壁物體距離坐標原點10單位長度,一個1×1×1的Sphere作為玩家操控的小球(命名為Player)。

scene_setup_camera_01.png
scene_setup_light_01.png

設置Main Camera的位置和旋轉,修改Directional Light的位置與旋轉,得到合適的攝影機位置以及光照效果。

scene_setup_02.png

添加小球運動

給Player添加一個Rigidbody組件。

player_01.png

Rigidbody將游戲物體變成一個“主動剛體”,使其可以受到力的作用而改變其位置和旋轉,并且會根據其碰撞體(Collider)組件的設置而與其他物體相互作用。

Unity中的剛體動力學是這樣劃分的:

  • 沒有添加Collider組件的游戲物體不參與動力學計算;
  • 只有Collider組件且沒有勾選Is Trigger選項的游戲物體被認為是“被動剛體”,不會被動力學改變其運動狀態,也就是說不會被撞開;
  • 勾選了Is Trigger選項的Collider不會起到阻擋其他Collider的作用,也就是不會發生碰撞現象,但依然能夠感知到其與其他Collider之間發生的交互作用,比如有其他Collider進入、停留或離開該Collider范圍時,該Collider是能夠感知到的;
  • 有Collider組件也有Rigidbody組件的游戲物體被認為是“主動剛體”,主動剛體會受到動力學作用而改變運動狀態,我們可以給主動剛體施加作用力或設置運動速度,也可以用其他剛體去撞擊主動剛體;
  • 勾選了Use Gravity(使用重力)選項的Rigidbody會持續受到重力作用而向-Y方向運動,除非被其他剛體阻擋;
  • 勾選了Is Kinematic(運動學)選項的Rigidbody將忽略外力作用,也就是說重力和剛體撞擊都不會使其產生運動,但我們直接設置其速度(velocity)來讓其運動起來,算是一種特殊的“主動剛體”吧。

為Player添加Fsm,在State 1中添加Get Axis Vector以獲得輸入向量,添加Add Force為Player施加作用力。

player_fsm_01.png

與控制角色運動不同,控制小球運動我們不僅希望改變其位置,還希望小球能夠“滾動”起來,這時候使用“施加作用力”的方式就比“設定運動速度”的方式要合適一些。并且,通過“施加作用力”來控制物體(尤其是球形物體)并不能非常精確的控制對象的運動(因為有慣性作用),所以用在這里反而能給游戲添加一些難度和樂趣。

這里我指定了兩個變量,一個speed變量用來設置小球的運動速度,一個input axis變量用來儲存輸入向量值。speed變量勾選了Inspector選項,使其可以在Inspector中可見。

player_fsm_02.png

添加可拾取的小方塊(Pickup)

在場景中新建一個Cube(改名為Pickup),修改其位移屬性為<<0, 1, 0>>,修改其旋轉屬性為<<45, 45, 45>>,修改其縮放屬性為<<0.5, 0.5, 0.5>>,添加一個黃色材質給Pickup。

為Pickup添加一個Fsm,在State 1添加一個Rotate:

pickup_fsm_01.png

勾選了Every Frame選項之后,Rotate行為可以按照Vector參數中所設定的旋轉速度,持續旋轉指定游戲物體。為了獲得平滑的旋轉效果,可以勾選Per Second選項和Fixed Update選項,讓其按照“每秒多少度”的方式來進行旋轉。

這里我沒有直接輸入旋轉速度,而是通過新建一個名稱為rotate speed的變量來控制,rotate speed變量的初始值設置為<<15, 30, 45>>,并在Inspector中可見。

將設置好的Pickup物體轉換成prefab,然后在場景中復制擺放。新建一個名為Pickups的空物體來放置所有的Pickup物體,以保持場景整潔。

place_pickups_01.png

小球“拾取”黃色方塊

Roll A Ball小游戲的基本交互邏輯是:玩家控制小球在場景中“拾取”所有的黃色小方塊。為了達成這個目的,我們需要進行“碰撞”判定:當小球的碰撞體與黃色方塊的碰撞體相交時,黃色方塊消失。

由于小球和黃色方塊上都具有Collider組件,所以這個判定工作可以被放在小球上,也可以被放在黃色小方塊上。在這個范例中我們選擇將判定工作放在小球上,是因為這個判定是每幀執行的,如果放在小方塊上,則所有的小方塊都會每幀執行判定操作,顯然執行效率不如將判定放在小球這一個物體上。

為Player添加一個Trigger Event,設定其當有其他Trigger進入小球的碰撞體范圍時,將這個Trigger物體儲存在一個叫做pickup object的變量中,并觸發hit a pickup事件。

為了避免別的trigger物體的干擾,我們設定這個Trigger Event行為僅針對那些被Tag為Pickup的Trigger物體起效果。因此,我們需要添加一個名為Pickup的Tag,并將所有的Trigger物體標記上這個Tag。

當hit a pickup事件被觸發時,Player的Fsm狀態從State 1跳轉為State 2。

payer_fsm_02.png

在State 2中,我們添加一個Activate Game Object,設置pickup object變量中所儲存的游戲物體(也就是進入了Player碰撞體的Trigger物體)的Activate屬性進行取消操作。

Activate實際上就是游戲物體Inspector面板中名稱前面的小勾選框,如果取消勾選,這個游戲物體就“隱藏”了,或者說“失效”了,雖然依然存在于游戲場景中,卻不會起到任何作用。

payer_fsm_03.png

同時,我們還需要將Pickup物體(黃色小方塊)的碰撞體設置為Trigger類型(勾選Box Collider組件中的Is Trigger選項),并設置其為Kinematic(勾選Rigidbody組件中的Is Kinematic選項)。

將小方塊設置為Trigger類型是因為我們不希望小球和方塊發生實際碰撞,只希望檢測到雙方相互觸碰而已;將小方塊設置為Kinematic是因為我們不希望小球在添加了Rigidbody之后受到重力作用而改變其“浮空自動旋轉”的運動狀態設置。

注意,如果是在場景中對Pickup物體進行的修改,需要點擊Apply按鈕將其修改應用到其他所有Pickup物體上,或者直接對prefab物體進行修改。

pickup_inspector_01.png

運行測試,我們現在可以用小球“吃掉”所有的黃色小方塊了。


添加UI

我們希望每“吃掉”一個小方塊,就能夠得到1分,“吃完”所有的小方塊,就可以贏得游戲!

在場景中添加兩個UI Text物體:Score Text和Win Text:

UI_01.png
UI_02.png

可以看到,系統自動創建了一個Canvas,并將UI Text物體放置在Canvas中。同時,系統還創建了一個EventSystem,這兩個自動創建的節點都不要隨便刪掉。

修改兩個UI Text物體的參數,獲得如下UI顯示:

UI_03.png
UI_04.png
UI_05.png

注意,這時候我們在Inspector中輸入的UI文字內容只是一個預設值,我們后面會用PlayMaker控制其中文字內容的。


在Fsm中控制UI顯示內容

這時候需要對Player的Fsm進行一些較大的修改了。

payer_fsm_04.png

首先,State 2中需要加入“計分”的功能,并判斷是否所有的Pickup物體都被“吃掉”了。如果是,則跳轉到State 4(游戲獲勝狀態),如果否,則跳轉回State 1繼續游戲。同時,State 2中還需要進行UI文字內容更新操作,使其顯示最新的分數。

其次,需要制作游戲獲勝狀態State 4,這里需要顯示Win Text。

最后,需要在State 1之前添加一個State 3,在State 3中做一些必要的預設工作。

State 3

在State 3中:

  1. 用Set Int Value設置一個score變量,并將其數值初始化為0;
  2. 用Set Game Object設置一個score text變量,并指定Score Text物體給score text變量;
  3. 用Set Game Object設置一個win text變量,并指定Win Text物體給win text變量;
  4. 用Convert Int To String將score變量值轉換成一個字符串變量score string,以便指定為UI文字的內容;
  5. 用U Gui Text Set Text將score text物體的Text參數值設置為“ ”(也就是無內容,如果什么字都不打PlayMaker會報錯,所以打個空格就好了);
  6. 用U Gui Text Set Text將win text物體的Text參數值也設置為“ ”。

注意:U Gui Text Set Text行為需要自行安裝uGui行為包。

payer_fsm_05.png

在State 2中:

  1. 添加Int Add讓score數值加1,代表得到1分;
  2. 添加Int Compare比較新的score數值和一個total pickups變量(手動設置為12)中的數值誰大誰小,如果score >= total pickups,則觸發win事件(跳轉到State 4);
  3. 添加Convert Int To String將score變量值轉換成一個字符串變量score string,設置Format參數使其顯示為“Score: 1”這樣的格式;
  4. 添加U Gui Text Set Text將score string指定給score text物體的Text參數值,更新score text的顯示內容。

注意,Int Compare放在Convert Int To String前面,當“吃到”最后一個小方塊的時候,score text不會更新為Score: 12,因為已經直接跳轉到State 4了。如果希望在State 4的時候能看到Score: 12這樣的分數顯示,則需要將Int Compare放在U Gui Text Set Text的后面。

payer_fsm_07.png

在State 4中:

  1. 添加U Gui Text Set Text將win text的文字直接設置成“You Win!”。

這里其實偷了個巧,懶得去做顯示隱藏Win Text物體的操作,就直接用“ ”來假裝Win Text未出現。

最終的UI顯示效果如下:

final_01.png

到此為止,就完成了Unity官方Roll A Ball教程的PlayMaker化!


一些小改進

發布游戲之前,添加了一些小改進:

  1. 給小球添加了貼圖,可以清晰看到小球的旋轉;
  2. 添加了一個RESTART按鈕讓玩家可以重新開始游戲;
  3. 烘焙了光照貼圖;
  4. 添加了一點點后期效果:抗鋸齒、邊緣暗化;
  5. 添加了背景音樂和“吃掉”小方塊時的音效。

WebGL版游戲演示:Roll A Ball


其他的設計思路

Roll A Ball小游戲非常簡單,但我們可以在這個基礎上開開腦洞,設計一些其他玩法,比如:

  • 添加復雜的墻壁,修改小方塊布局,以得到不同的關卡設計;
  • 設置墻壁不可觸碰,碰到墻壁則重置游戲;
  • 規定時限,時限內沒有吃到所有的小方塊則任務失敗;
  • 添加陷阱,比如地面有個洞;
  • 添加機關、道具,比如傳送門;
  • 為小球添加跳躍行為;
  • 添加坡度,將目前的平面關卡設計轉換為立體關卡設計;
  • ……

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容