*重新做了一份,修改了之前的,文末有完整项目
右侧目录跳转
场景搭建
一张图简述:
play和音量是image,倍速和时间是text,这是最初版的,后续会创建一些子物体
记得给那三个image挂button组件(或者之间创建仨button然后拉成圆形放在左下角)和一个text子物体
*如果你做到后面发现ui缩放过小可以调canvas的scale,看不清字可以调canvasscaler,同时我这里的canvas是worldspace的
然后创建这仨脚本:
分别挂在rawimage,slider和canvas上
视频
(站里已经有很多人做过了,这里还是写一份吧)
新建一个rendertexture,设置一下宽和高(1920*1080一般)
然后在rawimage上添加一个videoplayer组件
把你的mp4文件拖到videoplayer的vidoeclip
把rendertexture拖到rawimage的texture和videoplayer的targettexture
点一下运行,你的rawimage就应该已经在播放了
在rawimage上加audiosource组件,然后把videoplayer的audio output mode改成audio source,再把刚加的组件拖到audio source的位置接口
滑动条
(这个站内也有,简单讲讲)
代码:
SliderControl.cs 挂在slider上
using UnityEngine;
using UnityEngine.EventSystems;
public class SliderControl : MonoBehaviour, IDragHandler, IEndDragHandler, IBeginDragHandler
{
public UImain uimain;
//是否拖拽进度条(滑动条)
public bool isDragMove;
public void OnDrag(PointerEventData eventData)
{
isDragMove = true;
}
public void OnEndDrag(PointerEventData eventData)
{
uimain.MoveSlider();
isDragMove = false;
}
public void OnBeginDrag(PointerEventData eventData)
{
isDragMove = true;
}
}
uimain.cs
//UImain.cs
//start函数中
videoslider = this.transform.GetChild(0).GetChild(1).GetChild(0).GetComponent<Slider>();//UIBG->Slider
public void MoveSlider()
{
videoplayer.time = videoplayer.length * videoslider.value;
}
在update里加上
if (!sliderControl.isDragMove)
{
videoslider.value = (float)(videoplayer.time / videoplayer.length);
}
就这些,至于滑动条的效果,贴图什么的就是自己发挥的地方了
我做成了类似b站的效果
底部按钮(快进,暂停,快退)
直接整仨button,这里我偷懒直接用的text没重新画材质,最后效果是这样的
此外这里需要在rawimage下新建一个image作为tip,然后在tip下新建text
并自行设置样式
代码
uimain.cs
public void Backward()
{
videoplayer.time -= 5.0;
videoplayer.transform.GetChild(2).GetChild(0).GetComponent<Text>().text = "快退5秒";
videoplayer.transform.GetChild(2).gameObject.SetActive(true);
PlayPPT();
Invoke("CloseTip", 0.5f);
}
public void FastForward()
{
videoplayer.time += 5.0;
videoplayer.transform.GetChild(2).GetChild(0).GetComponent<Text>().text = "快进5秒";
videoplayer.transform.GetChild(2).gameObject.SetActive(true);
PlayPPT();
Invoke("CloseTip", 0.5f);
}
public void CloseTip()
{
videoplayer.transform.GetChild(2).gameObject.SetActive(false);
}
public void PausePPT()
{
isPause = true;
videoplayer.Pause();
videoplayer.transform.GetChild(0).gameObject.SetActive(true);
}
public void PlayPPT()
{
isPause = false;
videoplayer.GetComponent<VideoPlayer>().Play();
videoplayer.transform.GetChild(0).gameObject.SetActive(false);
}
说明
其中backward是快退5s,fastforward是快进5s,
pauseppt是暂停,ispause是个bool,存在是因为我有点一次暂停再点继续的需求
名字都是随便取的毕竟我这里只是练手的项目
这三个函数直接挂在三个button的onclick上,就是最下面那个
videoplayer.transform.GetChild(2).GetChild(0).GetComponent<Text>().text = "快进5秒";
这个是一个提示,点快进快退会弹一个小image,然后显示后面的内容
videoplayer.transform.GetChild(0).gameObject.SetActive(true);
这是那个暂停按钮(rawimage下的play),暂停就出现,播放就失活,同时别忘了为它加上button组件,并把playppt赋给它
声音
“音量”这个物体同样是一个空物体,他的范围(unity中按t可以看到)要包括图片和slider
新建一个image,大小为整个“音量”的大小减去UIBG的部分,命名为sliderbg
然后把slider拖进去
image和sliderbg最好有交界,避免出现鼠标划过去音量条闪烁的问题
然后自定义你的slider形式即可,注意value为0时handle在下方即可
做好就是这个样子
然后加组件:
“音量”:
喇叭图标:
sliderbg:
slider:
记得在canvas中完成拖拽(部分已经在代码中写好了的就不需要了):
物体“音量”和图片“音量”是不一样的需要注意
如果你觉得这个喇叭图片有点大可以给他加一个空父物体,然后修改一点代码就好
代码
public SliderControl sliderControl;
public GameObject volume;
public Sprite sound;
public Sprite Mute;
bool isVolumeShow = false;
void Start()
{
sliderControl= GameObject.FindObjectOfType<SliderControl>();
volume = this.transform.GetChild(0).GetChild(1).GetChild(2).gameObject;
}
void Update()
{
if (!isVolumeShow)
{
volume.transform.GetChild(1).gameObject.SetActive(false);
}
pptvideo.playbackSpeed = speed;
}
public void ChangeVolume()
{
// 将视频音量设置为滑动条的值
videoplayer.GetComponent<AudioSource>().volume = volume.transform.GetChild(1).GetChild(0).GetComponent<Slider>().value;
volume.transform.GetChild(1).GetChild(1).GetComponent<Text>().text = ((int)(volume.transform.GetChild(1).GetChild(0).GetComponent<Slider>().value * 100)).ToString();
if (videoplayer.GetComponent<AudioSource>().volume == 0)
{
volume.transform.GetChild(0).GetComponent<Image>().sprite = Mute;
}
else
{
if (volume.transform.GetChild(0).GetComponent<Image>().sprite == Mute)
{
volume.transform.GetChild(0).GetComponent<Image>().sprite = sound;
}
}
}
public void CloseVolume()
{
isVolumeShow = false;
}
public void ShowVolume()
{
isVolumeShow = true;
volume.transform.GetChild(1).gameObject.SetActive(true);
}
倍速
这里是5个倍速(0.5,1,1.25,1.5,2,可以更多,自己加就是了)
(注意,“倍速”这个物体是个空物体,文字是title显示的)
别忘了五个speed都加上button组件
然后为各个物体添加eventtrigger:
“倍速”:
title:
如果觉得手调倍速内容的位置比较麻烦可以在content(image,颜色为黑色有一定透明)上加一个vertical layout group,然后把六个勾都勾上
代码
uimain.cs(脚本挂在canvas上)
bool isHover = false;
void Update()
{
if (!isHover)
{
GameObject.Find("倍速").transform.GetChild(1).gameObject.SetActive(false);
isHover = true;
}
videoplayer.playbackSpeed = speed;
}
/// <summary>
/// 修改倍速
/// </summary>
/// <param name="speed">修改后的值,由编辑器界面写死</param>
public void ChangeSpeed(float speed)
{
this.speed = speed;
GameObject.Find("倍速").transform.GetChild(1).gameObject.SetActive(false);//更换倍速之后关掉这个部分
PlayPPT();//暂停部分的bug 的补丁
}
//修改状态
public void ChangeClose()
{
isHover = false;
}
public void ShowXSpeedUI()
{
GameObject.Find("倍速").transform.GetChild(1).gameObject.SetActive(true);
isHover = true;
//高亮当前倍速
foreach (Transform item in GameObject.Find("倍速").transform.GetChild(1))
{
if (item.gameObject.GetComponent<Text>().text == "x" + speed)
{
item.gameObject.GetComponent<Text>().color = Color.blue;
}
else
{
item.gameObject.GetComponent<Text>().color = Color.white;
}
}
}
说明
效果:
当鼠标进入title的范围中时触发ShowXSpeedUI,将content激活
此时当鼠标在“倍速”的范围中时content不会失活,还可以点击倍速进行切换,当前倍速为蓝色,点击之后content失活
时间
新建一个text即可
代码
public void MatchTime()
{
int curm = (int)pptvideo.time / 60;
int curs = (int)pptvideo.time % 60;
timeText.text = $"{curm:D2}:{curs:D2}/{(int)pptvideo.length / 60:D2}:{(int)pptvideo.length % 60:D2}";
}
timetext就是新建的那个text,拿到其中的text组件,然后在update里一直调用就好了
暂停
这个暂停值得我单开一小节
我想实现的效果类似常规播放器(或者说b站那种效果)
鼠标出现在屏幕中时下方ui出现,点击上方无ui空白区域暂停视频,点击有ui的区域无效
这个东西还挺不好弄的,直接用pointerclick会按任何鼠标键都生效,也不会区分有无ui
所以我最后想到的办法是——用ray
ray是不能识别到ui元素的,所以需要在ui和ground之间加一层实体,我是把ground复制了一份(称为clickposition)然后将scale的z调成0,再把meshrender删掉,这样它就没有厚度也没有材质,但确实能被ray检测到
建议先调好位置再删meshrender,不然不好操作
代码
ClickToPauseTheScreen.cs
进阶效果的,可以不要,会有一些bug,没找到解决办法就只能打补丁了,挂在rawimage上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class ClickToPauseTheScreen : EventTrigger
{
private UImain uimain;
public GameObject clickposition;
void Start()
{
uimain = GameObject.FindObjectOfType<UImain>();
clickposition = GameObject.Find("clickposition");
}
public override void OnPointerEnter(PointerEventData eventData)
{
uimain.ShowPPTUI();
base.OnPointerEnter(eventData);
}
public override void OnPointerExit(PointerEventData eventData)
{
uimain.ClosePPTUI();
base.OnPointerExit(eventData);
}
}
另一部分写在关于人物控制的地方,我这里省事就直接控制的摄像机
写一个脚本挂在摄像机上,在update函数里这样写
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (Input.GetMouseButtonDown(0))
{
if (hit.collider.name == "clicktopause")
{
uimain.PausePPT();
}
}
}
代价是任何范围内的点击操作都会暂停,但是没关系加一个playppt就好了
完整文件
有一些写的过程中没删掉的冗余代码,但是
嗯……能看懂就行
https://pan.baidu.com/s/1oyAQyJvRpYmo0L8QFT86xA?pwd=jv9u