接着上次的源码分析:
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); }
如对本文有疑问, 点击进行留言回复!!
asp.net使用三层架构实现简单的增删改查(1)—— 搭建三层架构
分布式计算是指系统的工作方式,主要分为数据分布式和任务分布式
Spark Core快速入门系列(1) | 什么是RDD?一文带你快速了解Spark中RDD的概念!
Spark Core快速入门系列(2) | Spark Core中编程模型的理解与RDD的创建
IOS-海外版授权分享推送统计 Google FaceBook Twitter Instagram
网友评论