Extreme Drift賽車遊戲C#原始碼詳解(1)
Extreme Drift賽車遊戲C#原始碼詳解(1)
C#我只是一個萌新,由於搞過Java,還是可以看懂C#的
偶然間得到賽車遊戲Extreme Drift的原始碼
接下來我會花一段時間來解讀,這是一個我學習的過程,記錄在部落格
等到我完全解讀之後,我也許會考慮再加入聯機功能等
當然,這個遊戲用的是Unity引擎
首先,我先展示一下這個遊戲的效果:
選車:
然後選圖,進入比賽:
WASD,SHIFT氮氣,空格漂移
不得不說,車輛的手感非常不錯!
作為育碧的老玩家,講真的,這個小遊戲的手感比育碧的賽車手感好多了
甚至就我感覺,車輛除了一些引數感覺需要調整,整體來看,手感和GTA5的感覺有點像
不多說了,我打包出來一個Windows可執行的程式,雙擊就可以體驗賽車遊戲:
連結:https://pan.baidu.com/s/1kF61eguRJf1Gd7aGn4w5jg
提取碼:ks1l
原始碼的地址:花錢買的,免費分享了!
連結:https://pan.baidu.com/s/1yiayLBXOBcSoJstHJQw33A
提取碼:eyyq
下面正式開始檢視原始碼:
匯入之後目錄結構:並且會自動匯入Unity自帶資源ImageEffects
開啟Scenes的MainMenu場景,啟動遊戲:
然而第一次啟動在載入地圖的時候會報錯,因為這一步:
IEnumerator LoadLevelAsync() { yield return new WaitForSeconds(0.4f); sceneLoadingOperation = Application.LoadLevelAsync(currentLevelNumber + 1); sceneLoadingOperation.allowSceneActivation = false; while (!sceneLoadingOperation.isDone || sceneLoadingOperation.progress < 0.9f) { menuLoadTime += Time.deltaTime; yield return 0; } }
這裡非同步載入索引為currentLevelNumber+1的場景,然而,實際上不存在這個索引,所以,我們需要在Build Setting設定好這些場景:
然後在啟動,就可以順利遊戲了!
有六個場景,那麼就先從主選單MainMenu場景來看:
負責UGUI的事件系統:
Standalone Input Module:專為滑鼠/鍵盤/控制器輸入而設計:
這裡沒有做什麼多餘操作,只是添加了這個元件,一個引數也沒有改
Touch Input Module:為觸控式螢幕裝置而設計,暫時與我無關
接下來看UGUI部分:
一個Canvas,裡面有八個物件
Top Panel是頂部的一個橫條,右邊有金幣和設定選項
觀察金幣,發現這只是一個簡單的圖片,而金幣之內,包含GameScore物件,這個應該是處理金幣的核心
猜錯了,觀察GameScore物件發現,這也是一個簡單的Text,那麼金幣相關功能應該是find這個物件來處理的
然後看設定,是一個Button,綁定了MainMenu裡面的一個函式,而且播放點選聲音,另外有一個Shadow元件:作用是給按鈕新增陰影輪廓
檢視這個函式:
public void SettingActive(bool activePanel) { menuPanels.Settings.gameObject.SetActive(activePanel); }
OK,只是使另一個UI物件active,可以理解為:點選設定按鈕後跳轉到另一個頁面
MainMenu相當於是全螢幕,包含了左上的logo和底部的一個Panel:
標題Tilt:一個簡單的圖片,在它下面的Image有點意思,是一個較亮的矩形,反覆從右到左位移,配合Logo實現發光的效果
實現機制:Image利用Aminator元件將自身和Tilt這個Logo繫結,實現迴圈動畫
然後就是底部的Panel,裡面有四個物件,退出,資源,油管,選車進行下一步
退出:綁定了Shadow、點選音效的一個按鈕,以及一個MainMenu的函式:就是簡單的退出
public void ClickExitButton() { Application.Quit(); }
資源和油管都是連結,本質一個按鈕帶Shadow和Audio,繫結OpenURL指令碼的函式:傳入URL,開啟,簡單
public void OpenTab (string URL) { Application.OpenURL(URL); }
選車:一個簡單的按鈕,帶Shadow,繫結MainMenu的一個函式:我在下面的註釋中將會詳細解釋
public void CurrentPanel(int current) { //這裡為什麼要傳一個INT呢?因為開頭有定義 //public enum Panels { MainMenu = 0, SelectVehicle = 1, SelectLevel = 2, Settings = 3 } //activePanel預設為0,這裡傳入的是1,就是選車 activePanel = (Panels)current; //PlayerPrefs是資料持久化,從存檔取出資料驗證 if (currentVehicleNumber != PlayerPrefs.GetInt("CurrentVehicle")) { currentVehicleNumber = PlayerPrefs.GetInt("CurrentVehicle"); //迴圈所有的車輛 foreach (VehicleSetting VSetting in vehicleSetting) { //當前車啟用狀態,否則不啟用 if (VSetting == vehicleSetting[currentVehicleNumber]) { VSetting.vehicle.SetActive(true); currentVehicle = VSetting; } else { VSetting.vehicle.SetActive(false); } } } //根據傳入值做一些操作 switch (activePanel) { case Panels.MainMenu: menuPanels.MainMenu.SetActive(true); menuPanels.SelectVehicle.SetActive(false); menuPanels.SelectLevel.SetActive(false); if (menuGUI.wheelColor) menuGUI.wheelColor.gameObject.SetActive(true); break; //這裡傳入的是1,進入選車 case Panels.SelectVehicle: menuPanels.MainMenu.gameObject.SetActive(false); menuPanels.SelectVehicle.SetActive(true); menuPanels.SelectLevel.SetActive(false); break; case Panels.SelectLevel: menuPanels.MainMenu.SetActive(false); menuPanels.SelectVehicle.SetActive(false); menuPanels.SelectLevel.SetActive(true); break; case Panels.Settings: menuPanels.MainMenu.SetActive(false); menuPanels.SelectVehicle.SetActive(false); menuPanels.SelectLevel.SetActive(false); break; } }
VehicleGarage:車庫情景,下面有五個物件
Top:頂部。左邊一個logo:帶有Outline的一個Text。中下是汽車的名字,也是一個Outline的Text
然後是三個車輛效能資訊,速度,剎車,氮氣,都是簡單的Text+Slider
NextVehicle:繫結點選聲音和MainMenu的一個函式:
public void NextVehicle() { if (menuGUI.wheelColor) { menuGUI.wheelColor.gameObject.SetActive(false); } currentVehicleNumber++; //取模運算,防止越界 currentVehicleNumber = (int)Mathf.Repeat(currentVehicleNumber, vehicleSetting.Length); foreach (VehicleSetting VSetting in vehicleSetting) { if (VSetting == vehicleSetting[currentVehicleNumber]) { VSetting.vehicle.SetActive(true); //迴圈到下一輛車賦值給當前 currentVehicle = VSetting; } else { VSetting.vehicle.SetActive(false); } } }
PreviousVehicle是類似的:
public void PreviousVehicle() { if (menuGUI.wheelColor) { menuGUI.wheelColor.gameObject.SetActive(false); } currentVehicleNumber--; currentVehicleNumber = (int)Mathf.Repeat(currentVehicleNumber, vehicleSetting.Length); foreach (VehicleSetting VSetting in vehicleSetting) { if (VSetting == vehicleSetting[currentVehicleNumber]) { VSetting.vehicle.SetActive(true); currentVehicle = VSetting; } else { VSetting.vehicle.SetActive(false); } } }
Bottom下有四個物件:
Back:一個按鈕,返回上一場景,原理和上邊的選車按鈕一直,呼叫同一個函式
Next:下一步地圖選擇頁面,也和上面的原理一樣,都是呼叫一個函式CurrentPanel
CustomizeVehicle:自定義車輛,按鈕繫結函式,點選後隱藏一些場景,開啟自定義場景
BuyNewVehicle:買車,預設是不啟用的,點選後啟用下一個物件BuyConfirm
BuyConfirm:一個不啟用的Panel,被啟用後有兩個選項,Yes的話掉MainMenu的函式,否則返回:
public void BuyVehicle() { //金幣足夠或者車輛未買才會執行 if ((gameScore >= vehicleSetting[currentVehicleNumber].price) && !vehicleSetting[currentVehicleNumber].Bought) { //資料持久化 PlayerPrefs.SetInt("BoughtVehicle" + currentVehicleNumber.ToString(), 1); //減錢 gameScore -= vehicleSetting[currentVehicleNumber].price; //防止負數 if (gameScore <= 0) { gameScore = 1; } //儲存金幣數量 PlayerPrefs.SetInt("GameScore", gameScore); //儲存車輛購買狀態 vehicleSetting[currentVehicleNumber].Bought = true; } else { menuPanels.EnoughMoney.SetActive(true); } }
CustomizeVehicle:自定義車輛,下面有三個物件
Top:簡單的一個頂部Logo,Colors裡面有八個顏色物件,綁定了MainMenu的一個函式:
public void ActiveCurrentColor(Image activeImage) { mainColor = activeImage.color; //根據傳參持久化資料 if (menuGUI.wheelColor.gameObject.activeSelf) { vehicleSetting[currentVehicleNumber].ringMat.SetColor("_Color", mainColor); PlayerPrefsX.SetColor("VehicleWheelsColor" + currentVehicleNumber, mainColor); } else if (menuGUI.smokeColor.gameObject.activeSelf) { vehicleSetting[currentVehicleNumber].smokeMat.SetColor("_TintColor", new Color(mainColor.r, mainColor.g, mainColor.b, 0.2f)); PlayerPrefsX.SetColor("VehicleSmokeColor" + currentVehicleNumber, new Color(mainColor.r, mainColor.g, mainColor.b, 0.2f)); } }
Bottom下面很多的物件,首先是一個返回,機制和函式上邊提到了
WheelColor、SmokeColor和RandomColor都是繫結MainMenu幾個函式,這幾個函式不難:
public void ActiveWheelColor(Image activeImage) { randomColorActive = false; activeImage.gameObject.SetActive(true); menuGUI.wheelColor = activeImage; menuGUI.smokeColor.gameObject.SetActive(false); } public void ActiveSmokeColor(Image activeImage) { randomColorActive = false; activeImage.gameObject.SetActive(true); menuGUI.smokeColor = activeImage; menuGUI.wheelColor.gameObject.SetActive(false); }
public void RandomColor() { randomColorActive = true; menuGUI.wheelColor.gameObject.SetActive(false); menuGUI.smokeColor.gameObject.SetActive(false); //隨機數函式 vehicleSetting[currentVehicleNumber].ringMat.SetColor("_Color", new Color(Random.Range(0.0f, 1.1f), Random.Range(0.0f, 1.1f), Random.Range(0.0f, 1.1f))); vehicleSetting[currentVehicleNumber].smokeMat.SetColor("_TintColor", new Color(Random.Range(0.0f, 1.1f), Random.Range(0.0f, 1.1f), Random.Range(0.0f, 1.1f), 0.2f)); //持久化 PlayerPrefsX.SetColor("VehicleWheelsColor" + currentVehicleNumber, vehicleSetting[currentVehicleNumber].ringMat.GetColor("_Color")); PlayerPrefsX.SetColor("VehicleSmokeColor" + currentVehicleNumber, vehicleSetting[currentVehicleNumber].smokeMat.GetColor("_TintColor")); }