当前位置: 移动技术网 > IT编程>开发语言>.net > Extreme Drift赛车游戏C#源码详解(2)

Extreme Drift赛车游戏C#源码详解(2)

2018年11月28日  | 移动技术网IT编程  | 我要评论

extreme drift赛车游戏c#源码详解(1)

 

接着上次的源码分析:

mainmenu场景的ugui部分:

canvas中的enoughmoney:

作用:当买车后金币不足弹出的页面

内部一个text和一个button,让我有点疑惑的是,button绑定的点击事件是buyvehicle函数:

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

 

下一个对象levelchooser:

内含三个对象,top,bottom,levels:

top:带有outlinelogo的简单的text

bottom:内含back和start,返回上一个场景,原理是传入一个索引值,函数如下

    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;
            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.enoughmoney.setactive(true);
                menupanels.selectlevel.setactive(false);
                break;
        }
    }

start对应的函数如下:调用startgame,然后调用下面的两个函数

    public void startgame()
    {
        //防止出错
        if (startinggame) return;
        //设置背景
        fadebackground.setbool("fadeout", true);
        //调用协程加载(由于不能直接调用c#的多线程,这个函数实现多线程)
        startcoroutine(loadlevelgame(1.5f));
        startinggame = true;
    }


    ienumerator loadlevelgame(float waittime)
    {
        yield return new waitforseconds(waittime);
        //激活加载页面
        menugui.loading.setactive(true);
        //加载
        startcoroutine(loadlevelasync());

    }

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

 

levels是一个带有scroll rect的image,内含group,下有五张地图对象

每一个地图下有star1,star2,star3,简单的image表实获取到的成绩,以及一个locked表示是否解锁,本质是一个简单的image

还有一个currentlevel对象,简单的image背景,里面有两个简单的text表示曾经获取的成绩

每一张地图对象只是一个图片,并不实际含有地图,并且绑定一个函数,根据传参进行下一步:

public void currentlevel(int current)
    {

        for (int i = 0; i < levelsetting.length; i++)
        {
            if (i == current)
            {
                currentlevelnumber = current;
                levelsetting[i].panel.image.color = color.white;
                levelsetting[i].panel.enabled = true;
                levelsetting[i].lockimage.gameobject.setactive(false);
                playerprefs.setint("currentlevelnumber", currentlevelnumber);
            }
            else if (levelsetting[i].locked == false)
            {
                levelsetting[i].panel.image.color = new color(0.3f, 0.3f, 0.3f);
                levelsetting[i].panel.enabled = true;
                levelsetting[i].lockimage.gameobject.setactive(false);
            }
            else
            {
                levelsetting[i].panel.image.color = new color(1.0f, 0.5f, 0.5f);
                levelsetting[i].panel.enabled = false;
                levelsetting[i].lockimage.gameobject.setactive(true);
            }
            //根据保存过的信息进行显示
            if (levelsetting[i].besttime)
            {
                if (playerprefs.getfloat("besttime" + (i + 1).tostring()) != 0.0f)
                {
                    if (playerprefs.getint("levelstar" + (i + 1)) == 1)
                    {
                        levelsetting[i].stars.star1.color = color.white;
                    }
                    else if (playerprefs.getint("levelstar" + (i + 1)) == 2)
                    {
                        levelsetting[i].stars.star1.color = color.white;
                        levelsetting[i].stars.star2.color = color.white;
                    }
                    else if (playerprefs.getint("levelstar" + (i + 1)) == 3)
                    {
                        levelsetting[i].stars.star1.color = color.white;
                        levelsetting[i].stars.star2.color = color.white;
                        levelsetting[i].stars.star3.color = color.white;
                    }

                    levelsetting[i].besttime.text = "best : " + getcomponent<formatsecondsscript>().formatseconds(playerprefs.getfloat("besttime" + (i + 1))).tostring();
                }
            }
        }
    }

 

下一个选项,settings:设置界面

一个深色的background

settingspanel:下面有七个对象

close是一个简单的button,绑定mainmenu的函数:

    public void settingactive(bool activepanel)
    {
        menupanels.settings.gameobject.setactive(activepanel);
    }

quality下有四个button,用于设置画质,一个line用来分割,绑定的函数如下:

直接调用系统画质api,然后持久化保存数据

    public void qualitysetting(int quality)
    {
        qualitysettings.setqualitylevel(quality - 1, true);
        playerprefs.setint("qualitysettings", quality);
    }

 

sound音量设置下是两个toggle:选项框绑定函数:设置后保存

    public void disableaudiobutton(toggle toggle)
    {
        if (toggle.ison)
        {
            audiolistener.volume = 1;
            playerprefs.setint("audioactive", 0);
        }
        else
        {
            audiolistener.volume = 0;
            playerprefs.setint("audioactive", 1);
        }
    }


    public void disablemusicbutton(toggle toggle)
    {
        if (toggle.ison)
        {
            menumusic.getcomponent<audiosource>().mute = false;
            playerprefs.setint("musicactive", 0);
        }
        else
        {
            menumusic.getcomponent<audiosource>().mute = true;
            playerprefs.setint("musicactive", 1);
        }
    }

 

control下四个对象,用于设置操作相关

两个选项框用于设置操作模式

    public void controlmodebuttons(toggle value)
    {
        if (value.ison)
            playerprefs.setstring("controlmode", "buttons");
    }
    public void controlmodeaccel(toggle value)
    {
        if (value.ison)
            playerprefs.setstring("controlmode", "accel");
    }

下面是音量设置:都是一些简单的函数

    public void disableaudiobutton(toggle toggle)
    {
        if (toggle.ison)
        {
            audiolistener.volume = 1;
            playerprefs.setint("audioactive", 0);
        }
        else
        {
            audiolistener.volume = 0;
            playerprefs.setint("audioactive", 1);
        }
    }


    public void disablemusicbutton(toggle toggle)
    {
        if (toggle.ison)
        {
            menumusic.getcomponent<audiosource>().mute = false;
            playerprefs.setint("musicactive", 0);
        }
        else
        {
            menumusic.getcomponent<audiosource>().mute = true;
            playerprefs.setint("musicactive", 1);
        }
    }

保存敏感系数函数:

    public void editsensitivity()
    {
        playerprefs.setfloat("sensitivity", menugui.sensitivity.value);
    }

 

最后一个erase all data是激活下面的reset panel,进行数据清除

reset panel是一个红色背景和选择yes或者no

    public void erasesave()
    {
        //清除所有数据后重新加载
        playerprefs.deleteall();
        currentvehiclenumber = 0;
        application.loadlevel(0);

        foreach (material mat in allrestmaterials)
            mat.setcolor("_color", new color(0.7f, 0.7f, 0.7f));
    }

 

fade background是一个隐藏对象,如果激活后,会显示车轮样的加载图片,带有一个绑定了动画的animator

 

到这里,ugui的canvas就分析完了

 

下一个,先看简单的vehicle root对象

里面装有12辆车和一个shadow阴影

这12辆车就是汽车的3d模型,没什么好说的,shadow是汽车的阴影

shadow实现是利用projector投影,用到一些阴影资源,这里就不深究了

下一个garage对象,也很简单,就是一个车库3d模型

 

最后来看main camera:

main camera下有两个audio source,分别是背景音乐和点击音效

main camera首先绑定的是mainmenu:

这两篇文章都是围绕mainmenu讲的,现在从头来看:

先看一些全局变量:这里大部分的意思我都看懂了,不过有一部分我无法理解

    //金币
    private int gamescore { get; set; }
    //视角移动速度
    public float camerarotatespeed = 5;
    //加载背景
    public animator fadebackground;
    //背景音乐
    public audiosource menumusic;
    //简单的go
    public transform vehicleroot;
    //所有材质
    public material[] allrestmaterials;
    //主界面:含有五个场景对象
    public menupanels menupanels;
    //界面gui,含有多个对象
    public menugui menugui;
    //车辆数组,保存了汽车的各种信息
    public vehiclesetting[] vehiclesetting;
    //关卡数组,保存了关卡的信息
    public levelsetting[] levelsetting;
    //默认以第一个界面开启
    private panels activepanel = panels.mainmenu;
    //含义暂定
    private bool vertical, horizontal;
    private vector2 startpos;
    private vector2 touchdeltaposition;

    //鼠标按下位置记录
    private float x, y = 0;

    //当前车辆以及各种信息
    private vehiclesetting currentvehicle;

    private int currentvehiclenumber = 0;
    private int currentlevelnumber = 0;

    private color maincolor;
    private bool randomcoloractive = false;
    private bool startinggame = false;

    private float menuloadtime = 0.0f;
    private asyncoperation sceneloadingoperation = null;

 

自定义的几个类:

    //游戏的gui
    [system.serializable]
    public class menugui
    {
        public text gamescore;
        public text vehiclename;
        public text vehicleprice;

        public slider vehiclespeed;
        public slider vehiclebraking;
        public slider vehiclenitro;

        public slider sensitivity;

        public toggle audio;
        public toggle music;
        public toggle vibratetoggle;
        public toggle buttonmode, accelmode;

        public image wheelcolor, smokecolor;
        public image loadingbar;

        public gameobject loading;
        public gameobject customizevehicle;
        public gameobject buynewvehicle;
    }
    //五个场景的panel
    [system.serializable]
    public class menupanels
    {
        public gameobject mainmenu;
        public gameobject selectvehicle;
        public gameobject selectlevel;
        public gameobject enoughmoney;
        public gameobject settings;
    }
    //车辆信息
    [system.serializable]
    public class vehiclesetting
    {
        public string name = "vehicle 1";

        public int price = 20000;

        public gameobject vehicle;
        public gameobject wheelsmokes;

        public material ringmat, smokemat;
        public transform rearwheels;

        public vehiclepower vehiclepower;
        //是否购买,隐藏
        [hideininspector]
        public bool bought = false;
        //车辆性能参数
        [system.serializable]
        public class vehiclepower
        {
            public float speed = 80;
            public float braking = 1000;
            public float nitro = 10;
        }
    }
    //可以使用的几张地图信息
    [system.serializable]
    public class levelsetting
    {
        public bool locked = true;
        public button panel;
        public text besttime;
        public image lockimage;
        public starclass stars;
        //该地图获得了几颗星
        [system.serializable]
        public class starclass
        {
            public image star1, star2, star3;
        }
    }

 

这个脚本其他所有的函数都有说过了,除了awake和update函数:

先来看看awake函数:

    //初始化
    void awake()
    {

        audiolistener.pause = false;
        time.timescale = 1.0f;

        //震动选项,这里没用
        menugui.vibratetoggle.ison = (playerprefs.getint("vibrationactive") == 0) ? true : false;

        //默认金币999999
        gamescore = 999999;

        //加载第一个场景
        currentpanel(0);

        //设置画质
        if (playerprefs.getint("qualitysettings") == 0)
        {
            playerprefs.setint("qualitysettings", 4);
            qualitysettings.setqualitylevel(3, true);
        }
        else
        {
            qualitysettings.setqualitylevel(playerprefs.getint("qualitysettings") - 1, true);
        }
        //设置车辆敏感度
        if (playerprefs.getfloat("sensitivity") == 0.0f)
        {
            menugui.sensitivity.value = 1.0f;
            playerprefs.setfloat("sensitivity", 1.0f);
        }
        else
        {
            menugui.sensitivity.value = playerprefs.getfloat("sensitivity");
        }

        //设置操作模式
        switch (playerprefs.getstring("controlmode"))
        {
            case "":
                menugui.buttonmode.ison = true;
                break;
            case "buttons":
                menugui.buttonmode.ison = true;
                break;
            case "accel":
                menugui.accelmode.ison = true;
                break;
        }

        //当前车辆
        currentlevelnumber = playerprefs.getint("currentlevelnumber");
        //地图解锁情况处理
        for (int lvls = 0; lvls < levelsetting.length; lvls++)
        {
            if (lvls <= playerprefs.getint("currentlevelunlocked"))
                levelsetting[lvls].locked = false;

        }

        //设置地图
        currentlevel(currentlevelnumber);

        //读取默认控制信息设置
        switch (playerprefs.getstring("controlmode"))
        {
            case "":
                playerprefs.setstring("controlmode", "buttons");
                menugui.buttonmode.ison = true;
                break;
            case "buttons":
                menugui.buttonmode.ison = true;
                break;
            case "accel":
                menugui.accelmode.ison = true;
                break;
        }

        //默认只买了第一辆车
        playerprefs.setint("boughtvehicle0", 1);


        //背景音乐和音量设置
        menugui.audio.ison = (playerprefs.getint("audioactive") == 0) ? true : false;
        audiolistener.volume = (playerprefs.getint("audioactive") == 0) ? 1.0f : 0.0f;

        menugui.music.ison = (playerprefs.getint("musicactive") == 0) ? true : false;
        menumusic.mute = (playerprefs.getint("musicactive") == 0) ? false : true;

        currentvehiclenumber = playerprefs.getint("currentvehicle");
        currentvehicle = vehiclesetting[currentvehiclenumber];


        int i = 0;

        //遍历所有车辆,进行轮胎颜色烟雾设置
        foreach (vehiclesetting vsetting in vehiclesetting)
        {

            if (playerprefsx.getcolor("vehiclewheelscolor" + i) == color.clear)
            {
                vehiclesetting[i].ringmat.setcolor("_diffusecolor", color.white);
            }
            else
            {
                vehiclesetting[i].ringmat.setcolor("_diffusecolor", playerprefsx.getcolor("vehiclewheelscolor" + i));
            }



            if (playerprefsx.getcolor("vehiclesmokecolor" + i) == color.clear)
            {
                vehiclesetting[i].smokemat.setcolor("_tintcolor", new color(0.8f, 0.8f, 0.8f, 0.2f));
            }
            else
            {
                vehiclesetting[i].smokemat.setcolor("_tintcolor", playerprefsx.getcolor("vehiclesmokecolor" + i));
            }


            //bought=true说明车没有买
            if (playerprefs.getint("boughtvehicle" + i.tostring()) == 1)
            {
                vsetting.bought = true;

                if (playerprefs.getint("gamescore") == 0)
                {
                    playerprefs.setint("gamescore", gamescore);
                }
                else
                {
                    gamescore = playerprefs.getint("gamescore");
                }
            }

            //显示当前车辆
            if (vsetting == vehiclesetting[currentvehiclenumber])
            {
                vsetting.vehicle.setactive(true);
                currentvehicle = vsetting;
            }
            else
            {
                vsetting.vehicle.setactive(false);
            }

            i++;
        }
    }

 

 

再看看update方法:

    void update()
    {

        //如果加载了下一个scene
        if (sceneloadingoperation != null)
        {
            //根据时间显示加载轮胎动画(圆形逐渐圆满)
            /*public static vector3 movetowards(vector3 current, vector3 target, float maxdistancedelta);
            作用是将当前值current移向目标target。(对vector3是沿两点间直线)
            maxdistancedelta就是每次移动的最大长度。
            返回值是当current值加上maxdistancedelta的值,如果这个值超过了target,返回的就是target的值*/
            menugui.loadingbar.fillamount = mathf.movetowards(menugui.loadingbar.fillamount, sceneloadingoperation.progress + 0.2f, time.deltatime * 0.5f);
            //加载完成
            if (menugui.loadingbar.fillamount > sceneloadingoperation.progress)
                sceneloadingoperation.allowsceneactivation = true;
        }


        if (menugui.smokecolor.gameobject.activeself || randomcoloractive)
        {
            //车辆的后轮旋转
            vehiclesetting[currentvehiclenumber].rearwheels.rotate(1000 * time.deltatime, 0, 0);
            //开启车辆轮胎烟雾
            vehiclesetting[currentvehiclenumber].wheelsmokes.setactive(true);
        }
        else
        {
            vehiclesetting[currentvehiclenumber].wheelsmokes.setactive(false);
        }


        //车辆参数的显示
        menugui.vehiclespeed.value = vehiclesetting[currentvehiclenumber].vehiclepower.speed / 100.0f;
        menugui.vehiclebraking.value = vehiclesetting[currentvehiclenumber].vehiclepower.braking / 100.0f;
        menugui.vehiclenitro.value = vehiclesetting[currentvehiclenumber].vehiclepower.nitro / 100.0f;
        menugui.gamescore.text = gamescore.tostring();

        //如果车已购买
        if (vehiclesetting[currentvehiclenumber].bought)
        {
            //一些简单的设置
            menugui.customizevehicle.setactive(true);
            menugui.buynewvehicle.setactive(false);

            menugui.vehiclename.text = vehiclesetting[currentvehiclenumber].name;
            menugui.vehicleprice.text = "bought";
            playerprefs.setint("currentvehicle", currentvehiclenumber);
        }
        else
        {
            //车没买的话一些简单的设置
            menugui.customizevehicle.setactive(false);
            menugui.buynewvehicle.setactive(true);

            menugui.vehiclename.text = vehiclesetting[currentvehiclenumber].name;
            menugui.vehicleprice.text = "cost: " + vehiclesetting[currentvehiclenumber].price.tostring();
        }

        //我改了下源码,因为暂时用不到安卓系统
        if (input.getmousebutton(0) && activepanel != panels.selectlevel)
        {
            //这些数学函数我看不懂,但明白意思,就是鼠标点击屏幕出现是视觉效果和旋转效果
            x = mathf.lerp(x, mathf.clamp(input.getaxis("mouse x"), -2, 2) * camerarotatespeed, time.deltatime * 5.0f);
            camera.main.fieldofview = mathf.clamp(camera.main.fieldofview, 50, 60);
            camera.main.fieldofview = mathf.lerp(camera.main.fieldofview, 50, time.deltatime);
        }
        else {
            x = mathf.lerp(x, camerarotatespeed * 0.01f, time.deltatime * 5.0f);
            camera.main.fieldofview = mathf.lerp(camera.main.fieldofview, 60, time.deltatime);
        }
        //慢慢旋转视角
        transform.rotatearound(vehicleroot.position, vector3.up, x);


    }

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网