嗨大家好我是yumir。
經過上一次2D畫素遊戲“Seed”的洗禮我決定休息一下換個題材,做一個3D遊戲就不會出現自己畫素材畫哭的情況啦!於是決定實現《jetpack jump》中的跳躍,算是物理系統小練習,大家可以自己搜尋安裝包試玩,不過不要過渡沉迷,會影響你打程式碼的~( ̄▽ ̄)~*
但是直接使用unity的免費素材來做遊戲,又比較沒意思,畢竟unity娘谷歌娘什麼的,除了又好看又方便之外還有什麼優點嗎,沒有。我們怎麼能滿足於這種唾手可得的資源呢,我們要去別的地方找更有意思的東西(其實就是想用自己喜歡的動畫片的模型)。
這次的模型是從
https://www。
spriters-resource。com/
上下載的,主要是因為我在別的網站都沒有找到JOJO的模型,同學們如果有別的資源來源請務必在評論區分享。
其實找模型有一個方法是透過找MMD作品看有沒有好看的想要的模型,以前聽大佬說MMD都是要求要把使用的資源連結列在簡介裡面的(除非資源是自己製作並且不願意共享的),再看看MMD轉Unity的外掛教程,就可以讓可愛的MMD角色跑起來了。
但是我找JOJO的MMD完全沒有看到連結,也許都是自己建模的?或者是我太菜了不會找,我本來心儀的是Q版豆豆眼的那個JOJO,就是這個:
但是想想這麼可愛的豆豆眼在地上瘋狂摩擦的樣子實在是不忍心,所以我決定還是讓Dio在地上摩擦吧,於是今天做的是DiavoloJump!JOJOJump?永遠抵達不到。
其實我也想過吉良吉影在不能回頭的巷子裡Jump,但是吧。。。
這就不是我短時間內能解決的問題了。
然後我掏出了老闆的模型。
突然卡茲。
我們喬斯達家族世世代代都是紳士,絕不會這樣就放棄!
然後我下載了blender,同時找到一個可以從unity匯出在unity中修改過的模型的外掛,但是匯出來之後模型的uv就莫得了,對比發現模型匯入到blender中修改再匯出,該有的材質都有,所以最後是在blender裡面幫BOSS把一頭秀髮修剪整齊了。
之所以使用的是blender主要是因為。
(#`O′)他免費啊!
感覺只要是建模軟體應該都能做這一步,但是你要我說是不是肯定都一樣我當然是不知道的,畢竟只是一個普普通通的上班族而已。
因為快捷鍵不一樣磨合時間也比較長,所以有別的建模軟體經驗的小夥伴不必強行下載。這個模型腳底下還有上下牙和舌頭,不知道到底是什麼遊戲,才需要把牙齒做出來,難道是要玩櫻桃嗎。
所以為了保護同學們的鍵盤我把我改好的模型上傳到了網盤:
https://
pan。baidu。com/s/1-JaKrh
SOu_Fr48xBRbugZw
將模型上傳到Mixamo綁骨再下載下來,我們的主要素材就完成啦!什麼你還不知道Mixamo是什麼?這麼好用的網站快儲存下來啊!
人物的動畫是在unity官方下載的,裡面的動畫正好夠用,再在官方商店隨便找了兩個差不多的場景包再差不多的搭一個場景做個差不多的天空盒我們的前期準備就完成啦。
如果同學們想讓遊戲時間變得更長的話需要更多的場景素材,itch上不止有免費的遊戲還有很多免費的素材,需要的同學可以自己去看看,非常不錯。
在畫天空盒的時候發現天空盒的顏色也是會反射到場景中的(這不是當然的嗎!)於是乾脆把天空調成了奇妙的綠色,天空盒的製作方法如下:
1、新建一個材質球,設定Shader為Skybox,這裡我設定為Skybox/Panoramic,我比較喜歡這個效果,也可以做六面體。
2、開啟ps做一個漸變顏色圖片給該天空盒賦值。
3、點選window→rendering→lightingsetting,將skybox material設定為剛才新建的天空盒。
場景的搭建其實是很費時費力的,所以大概搭了個夠用的,就是下面這個醜醜的場景↓
沒關係,畢竟我做的是DiavoloJump嗒!再下載一個緋紅之王套一個打籃球的動作,Boss的“噴射揹包”也有了,那麼可以開始我們的大工程啦~
——————————不介紹實現功能就開始薅程式碼的經驗分享都是耍流氓——————————
這次做的遊戲的玩法就是點選螢幕跳躍,但是如果一個遊戲隨便跳那就沒有意義了,所以是有條件限制的跳,因為是在電腦實現功能所以我做的是按下滑鼠左鍵跳躍,內容如下:
1、遊戲中BOSS一直向前奔跑,按下滑鼠左鍵跳躍。
2、如果第一跳的位置正好在起跑線,可以雙倍跳躍。
3、如果在落地的瞬間按下滑鼠左鍵,可以雙倍跳躍。
4、第三跳是噴射跳躍,在空中可以有若干次加速機會。
5、如果超過起跑線一段時間沒有跳躍,遊戲失敗。
6、如果落地一段時間沒有跳躍,遊戲失敗。
7、Boss永遠抵達不到終點。
畫了一張圖來表示整個遊戲流程,不過這次我只做了結算之前的跳躍,會在文末給感興趣的同學補充一些結算狀態的思路。
為了可以一直看到Boss的背影我們需要做一個攝像機跟隨,在製作這部分功能的時候考慮到遊戲中會有不同的攝像機角度,所以新建了一個空物體先把當前的跟隨角度儲存起來,後期需要新的角度的時候只需要增加新的空物體和邏輯就可以了。
public
float
smooth
;
// 平滑度
public
Transform
cameraFPTran
;
//人物活動時攝像機跟隨位置
public
Transform
cameraStartTran
;
//攝像機初始位置
private
GameObject
player
;
// 目標
private
Vector3
targetPosition
;
// 攝像機移動目標
private
bool
isStart
=
true
;
void
Start
()
{
player
=
GameObject
。
FindWithTag
(
“Player”
);
cameraFPOffset
=
cameraFPTran
。
position
-
player
。
transform
。
position
;
//攝像機放在初始位置,置標誌位為f
jetSlider
。
SetActive
(
false
);
}
void
LateUpdate
()
{
if
(
isStart
)
{
CameraFollow
(
cameraFPOffset
);
}
}
void
CameraFollow
(
Vector3
follow
)
{
targetPosition
=
player
。
transform
。
position
+
follow
;
transform
。
position
=
Vector3
。
Lerp
(
transform
。
position
,
targetPosition
,
Time
。
deltaTime
*
smooth
);
transform
。
LookAt
(
player
。
transform
);
}
在實現跳躍之前我們需要讓模型在遊戲場景中往前跑,首先新建Boss的遊戲物體,然後進行以下操作:
1、在Boss身上新增碰撞體、剛體以及動畫三個元件,新建一個角色控制指令碼。
2、把動畫的“Apply Root Motion”取消選中。
3、將剛體的旋轉角度鎖定。
因為我把跑道搭在Z軸上,所以Boss只需要一直在Z軸上面跑就行了,同時我希望Boss在起跑的時候有加速度的過程,於是我做了一個動畫混合樹,將走路和跑步的動畫混合在一起。
嘗試過幾種移動方法之後發現使用“AddForce”進行移動的效果是最好的。在移動的過程中我們需要控制Boss的移動速度(人類的力量是有極限的)以及懸空的時候不會繼續往前加速,所以我們需要對Boss的速度和是否跳躍進行監控,我是這樣實現的:
private void FixedUpdate()
{
if (!isJump && playerRigdbody。velocity。z < speed)
{
playerRigdbody。AddForce(Vector3。forward * speed);
}
playerAnimator。SetFloat(“Blend”, playerRigdbody。velocity。z / speed);
}
接下來就要實現跳躍功能了,跳躍有:起跳、空中、下落這三個狀態,加上本身有一個奔跑狀態,而起跳到空中這段動作是不需要條件轉換的,我的動畫狀態機是這樣搭建的。
其中指向“Run”的轉換條件是“run=true”,指向“JumpStart”的轉換條件是“jump=true”指向“JumpEnd”的轉換條件是“down=true”,“JumpStart”的動畫播放結束自動跳轉到“JumpMidAir”。
因為有機率出現明明“run”為True但是卻沒有從“JumpEnd”跳轉到“Run”的情況,我又在“JumpEnd”和“JumpStart”之間增加了一條線。在指令碼中定義一個列舉型別區分三個狀態就能輕鬆控制動畫的切換了,因為程式碼太簡單就不浪費篇幅了。
畫面表現搞定之後就是指令碼控制遊戲物體移動了,同樣的,用AddForce給一個向上的力就可以讓Boss上天,但是Boss可以一直上天嗎,Boss不行。
於是乎我需要讓他只能在腳踩地面的時候上天,這個判斷我是透過射線實現的:
Physics
。
Raycast
(
transform
。
position
+
Vector3
。
up
*
0。05f
,
-
Vector3
。
up
,
out
hit
,
0。1f
)
解決了Boss上天的問題我開始思考每一次跳躍之間的差別,整個遊戲只有按下滑鼠左鍵一個操作,但是每個階段的操作都是不一樣的,可以看出來最大的問題是最後一條需要出現反饋噴射進度的UI,而且是在起跳後一段時間才出現噴射進度條。
我的解決方法利用委託,定義一個沒有返回型別沒有引數的委託變數,在遊戲中每幀呼叫,在不同狀態中更改改委託的內容,這樣一來我就可以在遊戲的不同時期做不同的事了。
而後我又定義了一個int型別的數用來判斷Boss處於第幾個階段(狀態),透過Switch語句控制不同階段的操作,這個方法其實並不好,但是在學習的過程中我們需要靈活運用各種技巧,這個遊戲並不會進行後期修改所以可以這樣控制。
以第一階段為例,第一階段所做的事情是:起跑&第一次跳躍
我設定的起跑線是Z=15,當玩家超過起跑線一段距離(我設定的值是Z大於等於18)時玩家死亡,如果在起跑線浮動範圍裡面起跳則將“jumpSpeed”翻倍否則不變,起跳時設定動畫引數並將表示階段(第幾跳)的變數自增,這樣在下一幀執行的便是下一個狀態的方法。
if (isGround)
{
isJump = false;
if (Input。GetMouseButtonDown(0) && playerTransform。position。z < 18。0f)
{
if (playerTransform。position。z > 14。5f && playerTransform。position。z < 15。5f)//最佳
{
jumpSpeed *= 2;
}
SetPlayerAnima(PlayerStateType。Jump);
playerRigdbody。AddForce((Vector3。up) * jumpSpeed, ForceMode。Impulse);
jumpNum++;
jumpTime = 0;
isJump = true;
}
if (playerTransform。position。z >= 18。0f)
{
playerMove = PlayerDie;
}
}
第二跳第三跳大同小異,與第一跳不同的地方是第一跳用距離判斷是否加倍,後面的跳躍則是用落地時間,所以當Boss落地之後就要開始計時,在起跳的時候將計時器清零。
if (isGround)
{
jumpTime += Time。deltaTime;
if (jumpTime > timing){ playerMove = PlayerDie; }
else if (Input。GetMouseButtonDown(0) && jumpTime <= timing)
{
if (jumpTime <= bestTiming){ jumpSpeed *= 2; }
Jump();
}
}
需要注意的是如何控制動畫的播放,當Boss快要落地的時候要切換為“Down”動畫,也就是我需要知道他是否下墜,下墜時離地面多高,我透過記錄Boss的Y軸數值並比較上一幀和當前幀的Y值大小來判斷:
if (lastPosY > playerTransform。position。y && playerTransform。position。y < 2)
{
SetPlayerAnima(PlayerStateType。Down);
}
lastPosY = playerTransform。position。y;
Boss的第三次起跳需要延遲呼叫,我是用協程來實現的,在協程中對委託進行新的賦值操作,並且解開對Boss剛體的旋轉鎖定,以及一系列該有的操作。
IEnumerator Jet()
{
yield return new WaitForSeconds(1);
playerRigdbody。freezeRotation = false;
GameManager。instance。jetSlider。SetActive(true);
jetValue = jetTimes;
playerMove = PlayerMove02;
}
噴射進度條是我自己用PS做的,用了一個和遊戲場景比較搭的配色,在場景中新建兩個Image,將方格圖作為漸變色圖的子物體,因為Unity中的UI物體越在列表的下方則越靠近螢幕,自然可以將方格圖顯示在漸變色的前方。
將漸變色圖的引數設定如下,並持有這個遊戲物體,我是在GameManager裡持有的。
在Boss的控制指令碼中“PlayerMove02”中的設定更新該image的Amount並在每次推進中給Boss一個往前的力。當Boss落地的時候將動畫暫停播放,隱藏緋紅之王,遊戲到這裡就結束了。
if (isGround)
{
playerAnimator。speed = 0;
kingCrimson。SetActive(false);
}
else if (Input。GetMouseButton(0) && jetValue > 0)
{
——jetValue;
GameManager。instance。SetJetSlider(jetValue / jetTimes);
playerRigdbody。AddForce(Vector3。forward * jetSpeed, ForceMode。Impulse);
}
功能實現效果
最後可以透過剛體的IsSleeping判斷Boss是不是已經停下最後的滑行,在結束的時候彈出遊戲結束的各種效果,遊戲中的里程可以透過3D Object→3D Text來實現顯示,有更多問題歡迎在評論區留言,或者到群裡勾搭~
Github:
——————————————————————
有知友看了上一篇文章成功實現了自己的小專案,在原遊戲的基礎上做了擴充套件,雖然我也不是真大佬但是還是感覺很Diohh。
——分割線——
歡迎加入遊戲開發群歡樂攪基:869551769
有意向參與線下游戲開發學習的讀者可戳這裡進一步瞭解:
http://www。
levelpp。com/