C#我只是一個萌新,由於搞過Java,還是可以看懂C#的 偶然間得到賽車游戲Extreme Drift的源碼 接下來我會花一段時間來解讀,這是一個我學習的過程,記錄在博客 等到我完全解讀之後,我也許會考慮再加入聯機功能等 當然,這個游戲用的是Unity引擎 首先,我先展示一下這個游戲的效果: 選車: ...
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")); }
下麵是EnoughMoney,明天再看