1. 程式人生 > >Extreme Drift賽車遊戲C#原始碼詳解(1)

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"));
    }