游戏开发教育之UGUI系列——OSU!Video!

游戏开发教育之UGUI系列——OSU!Video!

前言

在前篇的OSU教程中已经简单的完成了基础战斗部分,缺失的转动圆盘功能这里会做补充。而且为了让游戏效果更好,我会在游戏中插入视频,并讲解Unity5.6之后新出的VideoPlayer功能(一个很方便的视频播放系统)。最后UI相关的知识点(网上收集整理的)补充游戏啊,这样各位对UGUI的知识就掌握的七七八八了。

废话不多说先上效果图:

游戏开发教育之UGUI系列——OSU!Video!

圆盘转动数学知识

圆盘转动主要是对我么在圆盘上输入的位置点和之前的位置点做处理,让UI知道我们是往哪个方向转动的。曾经入门Unity的时候没有太多的经验,使用的是以圆盘中心划分四个象限,通关鼠标的偏移来做的旋转。现在来看,感叹当初游戏数学知识不过关,为了避免各位读者也走我之前的老路,我先普及一个数学概念。

向量的点乘和叉乘

点乘:

游戏开发教育之UGUI系列——OSU!Video!

两个向量点乘得到一个标量 ,数值等于两个向量长度相乘后再乘以二者夹角的余弦值

公式里面有个余弦值,我们可以利用余弦的特性判断出:

若为 o,则表示两个向量之间角度是垂直关系, 。

若小于0 ,则两个向量夹角大于90°。

若结果 >0 ,则两个向量夹角小于 90°

总结:点乘通常用来判断角度,在判断物体是否转动到目标角度、虚拟摇杆在某个方向上的力度,或者shader里面对光线做处理都会用到这个。

叉乘:

游戏开发教育之UGUI系列——OSU!Video!

数学老师曾说过,两个向量叉乘确定一个平面,而平面是有方向的。

游戏开发教育之UGUI系列——OSU!Video!

a X b不等于b X a,因为确定的平面方向是刚好相反的,比如a X b我们根据右手定则,得到的是向上的向量,若b X a我们的右手就是向着a向量方向收拢,得到是向下的向量。

游戏开发教育之UGUI系列——OSU!Video!

总结:叉乘通常判断向量的方向,判断a在b向量的相对位置通过叉乘的正负判断是非常有效的。

代码原型实现

我们只用获取到鼠标开始拖拽转盘UI时,每次鼠标偏移位置带来的角度变化,以及转盘左转还是右转,因为我们想让转动是单方向的,就直接转动为逆时针的时候直接return,如果要任意转动,则将return的地方改为angle=-angle。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TurnAround :NoteLogic
{
 /// 
 /// UI上的圆盘物体
 /// 
 public RectTransform uiDisk;
 /// 
 /// 对UI监听的一个重写(可以下载源码查看)
 /// 
 public EventTriggerListener eventTrigger;
 /// 
 /// 上一帧点击的方向
 /// 
 Vector2 perTouchDir;
 /// 
 /// 圆盘中心点位置
 /// 
 Vector2 uiDiskPos;
 /// 
 /// 当前转动角度记录
 /// 
 float curAngle;
 /// 
 /// 和上篇一样,通过重构虚函数,让操作部分实现不同Node不同操作。
 /// 
 public override void OnJudgetOperation()
 {
 //将Ugui的开始拖拽事件和拖拽事件绑定功能函数
 eventTrigger.onBeginDrag = BegionTurn;
 eventTrigger.onDrag = Turn;
 uiDiskPos = uiDisk.transform.position;
 //协程判断时间是否超出,超出则直接判定当前分数
 StartCoroutine(OnDelayCall(judgeTime));
 }
 IEnumerator OnDelayCall(float rTime)
 {
 yield return new WaitForSeconds(rTime);
 JudgetStore();
 }
 /// 
 /// 开始拖拽UI的时候,储存一个点击点到转盘中心点的向量
 /// 
 public void BegionTurn(PointerEventData rData)
 {
 perTouchDir = rData.position - uiDiskPos;
 }
 /// 
 /// 转动处理
 /// 
 /// 
 public void Turn(PointerEventData rData)
 {
 //得到当前鼠标到转盘中心的向量
 var curTouchDir = rData.position - uiDiskPos;
 //上一帧向量和当前帧向量叉乘得到一个判断当前向量位置值
 var crossValue = Vector3.Cross(perTouchDir, curTouchDir);
 //获取两帧之间转动的角度(Unity自带的函数,原理其实可以用点乘来搞定)
 float angle = -Vector3.Angle(perTouchDir, curTouchDir);
 //如果逆时针旋转,不响应
 if (crossValue.z > 0)
 {
 return;
 }
 //让ui旋转角度
 uiDisk.transform.Rotate(new Vector3(0, 0, angle));
 //保存当前帧向量
 perTouchDir = curTouchDir;
 curAngle -= angle;
 //提示的圆圈UI根据转动的值由大变小
 circleTipObj.gameObject.transform.localScale = Vector3.one * Mathf.Lerp(10, 0, curAngle / targetValue);
 //转动到目标值判定分数
 if (curAngle > targetValue)
 {
 JudgetStore();
 }
 }
 public void JudgetStore()
 {
 if (curState == eState.Over)
 {
 return;
 }
 if (curAngle > targetValue)
 {
 curScore = eScore.Perfect;
 }
 else if (curAngle > targetValue*0.6f)
 {
 curScore = eScore.Good;
 }
 else
 {
 curScore = eScore.Fail;
 }
 StopCoroutine("OnDelayCall");
 SetCurState(eState.Over);
 }
} 

(继承NoteLogic的代码有改动,对项目感兴趣的朋友可以下载源码)

VideoPlayer视频播放

说到视频播放曾经是Unity的一个坑点,PC和手机平台的视频播放采用两种方式。电脑上是MovieTexture格式还得装QuickTime,手机上则是利用Handheld.PlayFullScreenMovie接口播放而且还是直接停止代码运行(怎么做功能啊喂!)。项目中为了用到视频最后采用了MobileMovieTexture插件,但是效果有点差,得用专门的格式,还得放在流文件夹,而且音效还得单独制作。

但是之前5.6更新的时候,新出的VideoPlayer功能搞定了以上的问题,PC端和手机端播放视频的方式都做了统一,而且支持摄像机镜头播放,UGUI播放等多种播放方式,同时还能直接搞定音频。简直太方便了!

先说流程:

1.放入视频文件,这里我将视频转换成了Unity支持的格式MP4

游戏开发教育之UGUI系列——OSU!Video!

2.新建VideoPlayer组件,简单介绍下组件的功能

游戏开发教育之UGUI系列——OSU!Video!

Source:可以选择是本地视频还是URL视频,如果是URL视频只用下方写上地址即可。

Wait For First Frame: 勾选PlayOnAwake后有效,避免加载视频过程中直接播放卡掉前几帧。

PlaybackSpeed:视频播放速度。

RenderMode:视频是哪里方式渲染的,目前有再摄像机上渲染,渲染到贴图上,渲染到材质球,和OnlyAPI(没对这个接口做研究)

AspectRatio:长宽比,是宽度适配还是高度适配。

Audio OutPut Mode:音频输出方式,这里选用通关AudioSource输出。

3.因为我们将视频渲染到UI上,因此需要一个目标渲染的贴图,创建一个渲染贴图

游戏开发教育之UGUI系列——OSU!Video!

可以直接设置贴图的像素:

游戏开发教育之UGUI系列——OSU!Video!

4.创建一个UICanva当作视频播放的界面

游戏开发教育之UGUI系列——OSU!Video!

然后创建一个RawImage组件,挂载VideoPlayer组件,和音频组件

RawImage的贴图可以是任意类型,不一定是Sprite类型,因此我们没有选用Image组件。

游戏开发教育之UGUI系列——OSU!Video!

这样我们就可以实现视频播放了,是不是特别简单?

游戏开发教育之UGUI系列——OSU!Video!

顺便补充:

VideoPlayer可以使用一系列事件来监听播放的各个动作:

errorReceived: 错误监听到时被执行

frameDropped :有丢帧发生时被执行

frameReady :新的一帧准备好时被执行

loopPointReached :播放结束或播放到循环的点时被执行

prepareCompleted :视频准备完成时被执行

seekCompleted :查询帧操作完成时被执行

started:在Play方法调用之后立刻调用

UGUI的相关知识点补充

以下是对UI相关的知识点整理,有自己阐述的也有来源于网络各处的,如果侵权联系我会进行删除。

什么是图集?

在使用3D技术开发2D游戏或制作UI时(即使用GPU绘制),都会使用到图集 ,那么什么是图集呢?准确的说法图集是一张包含了多个小图的大图和一份记录了每个小图id、位置、尺寸等数据的数据文件 。

为什么要用图集?

在GPU已经成为PC、手机等设备的必备组件的现在,把所有显示的绘制操作交给专门处理图像的GPU显然比交给CPU更合适,这样空闲下来的CPU可以集中力量处理游戏的逻辑运算。

而GPU处理图像的做法和CPU是不一样的,在GPU中,我们要绘制一个图像需要提交图片(即纹理)到显存,然后在进行绘制(这个过程称为一次DrawCall),那么如果我们一帧要绘制100个就需要提交100次图片,如果使用包含了这100图片的图集,只需要一次提交即可,即一次DrawCall就搞定,处理效率上会有很大的提升。

另外使用图集也方便管理和归类各个模块的图片,可以通过一次加载和一次卸载完成多个图片的处理,同理,加载次数也下来了,可以提升运行效率。

CPU与GPU的限制

GPU一般具有填充率(Fillrate)和内存带宽(Memory Bandwidth)的限制,如果你的游戏在低质量表现的情况下会快很多,那么,你很可能需要限制你在GPU的填充率。

CPU一般被所需要渲染物体的个数限制,CPU给GPU发送渲染物体命令叫做DrawCalls。一般来说DrawCalls数量是需要控制的,在能表现效果的前提下越少越好。通常来说,电脑平台上DrawCalls几千个之内,移动平台上DrawCalls几百个之内。这样就差不多了。当然以上并不是绝对的,仅作一个参考。

如何使用图集

在Unity中我们只要使用小图片即可,可以通过设置图片的Packing Tag来指定小图会被打包到的图集,比如2个小图的Packing Tag都叫“MyAtlas”,则Unity会将这两个小图打包到名为“MyAtlas”的图集中。

注意图片不能放在Resources文件夹下面,Resources文件夹下的资源将不会被打入图集。

通过设置我们就可以发现多个同一Packing Tag的小图放到场景中只会消耗一个DrawCall,表示我们的图集已经开始起作用了。

Unity用到的基本图片格式

Unity3D引擎对纹理的处理是智能的:不论你放入的是PNG,PSD还是TGA,它们都会被自动转换成Unity自己的Texture2D格式。

在Texture2D的设置选项中,你可以针对不同的平台,设置不同的压缩格式,如IOS设置成PVRTC4,Android平台设置成RGBA16等。嗯,非常的智能。

tga是无损支持透明的无压缩格式,dds有一点点压缩,png是无损压缩,对效率要求高的可以tga,dds,ui一般png,psd不可取

格式对比

游戏开发教育之UGUI系列——OSU!Video!

2的n次方幂天然被GPU接受

为什么要关心渲染顺序?

1.如果是2D游戏,渲染顺序关系着每个层次的显示先后,比如UI在游戏内容前面,游戏内容又有多层次。举一个简单的例子,在横版2D游戏中,经常会用到多层滚动的背景,把游戏物体分层管理起来,可以有效的减少出错几率,很好的控制显示效果。

2.对于3D游戏,游戏内容是3D的,UI一般是2D,有很多时候需要把某个模型啊,粒子特效啊,放在界面上,这样就有一个问题,3D物体和2D界面的先后关系,比如有些界面是在模型之上的,有些在下面,尝试过很多种办法,都能实现需求,但不是每种办法都是那么舒服的。

unity中控制渲染顺序的方式

Camera是unity中最优先的渲染顺序控制。depth越大,渲染顺序越靠后。

游戏开发教育之UGUI系列——OSU!Video!

sortingLayer 和 sortingOrder

按照字面意思是层的排序,Canvas和Renderer都有这个属性。

Canvas中的sorting layer可以控制Canvas的层级

Sorting order可以控制UI和粒子的层级

RenderQueue

这是unity中的一个概念,大致意思就是渲染顺序 。

所以一般设置材质的renderQueue或直接在shader中设置。

游戏开发教育之UGUI系列——OSU!Video!

(可以再Debug模式下直接修改)

在ShaderLab中,有4个提前定义好的render queue,你可以设置更多的在他们之间的值:

Background :表示渲染在任何物体之前

Geometry(default):渲染大多数几何物体所用的render queue

AlphaTest:用于alpha测试

Transparent:用于渲染半透明物体

Overlay:渲染所有物体之上

空间深度

在摄像机坐标系下的Z轴,控制着该相机下的物体的深度,在fragment shader中进行深度测试,这样就控制了渲染到屏幕的顺序。

总结

转盘转动功能用数学方法可以很容易来解决,游戏中用到数学的地方非常的多。

关于视频功能,Unity新出的VideoPlayer功能简单易用,同时安全性也高。若旧版本的升级后,项目需要视频功能的朋友可以试试这个功能。而且视频相对使用2D动画和即时演算虽然占用包体大小,但是对实际内存占用缺不高,对资源的依赖性也非常低。如果制作开场效果,选用视频方法来实现是非常不错的。

最后补充的UI相关知识,Unity在弱化图集的概念,但是工程项目中图集理解缺至关重要。同时渲染的知识也牵扯到UI,这个对自动化开关管理UI和修改粒子的层级效果至关重要。

最后附上源码:

https://github.com/chs71371/OSU_Battle

(包里有视频,我做了一个压缩包,解压就可以了,位置Resources/assetsbundles/video)


分享到:


相關文章: