近年来直播app和视频app如日中天,在这些app里往往会有一个弹幕功能。实际的项目中肯定是用服务器客户端直接的数据来控制的,这里只在客户端进行测试实现弹幕核心功能。
下面说的就是我是如何实现弹幕功能的。
首先是需求:要求全屏有四行弹幕,从下至上排列,每行依次显示,弹幕从右往左移动。弹幕移动出屏幕就消失。
制作步骤:
1)建立弹幕文字的prefab和要显示的UI;(下图中DanmuText就是弹幕text的预设物体,parents是弹幕在UI中作为parents的子物体)
2)新建脚本productdanmu添加给Canvas,然后将弹幕预设和弹幕的父物体拖进去(如上图)。
重点是productdanmu脚本中弹幕移动的实现
下面是源码:
usingUnityEngine;
usingSystem.Collections;
usingUnityEngine.UI;
usingDG.Tweening;
usingSystem.Collections.Generic;
usingSystem.Text.RegularExpressions;
usingSystem;
publicclassproductdanmu : MonoBehaviour
{
publicGameObject
textsdanmu, Danmu_parents;//弹幕预设物体和其父物体
privateGameObject
texts;//生成的弹幕物体
privateQueue
texts_queue =newQueue();//弹幕物体的队列
privatefloatproduction_timer;//生成弹幕的时间间隔
privateint[]
numb =newint[]
{ 39, 139, 239, 339 };//四行弹幕的位置
privateintRow_index;//弹幕行数变化
privateinta;////弹幕行数变化中间变量(桥的作用)
privateVector3
textpositon;//生成弹幕位置
privateQuaternion
textrotation;//生产弹幕角度
privatestringcontent;//弹幕文字内容
voidStart()
{
Row_index
= numb[0];//默认弹幕生产在第一行
textpositon
=newVector3(96,
Row_index, 0);//弹幕默认位置
textrotation.eulerAngles
=newVector3(0,
0, 0);
production_timer
= 2f;
}
voidUpdate()
{
production_timer-=Time.deltaTime;
if(production_timer<=0f)
{
inti
= UnityEngine.Random.Range(0, DanMuStrings.Length);//弹幕的随机内容
content
= DanMuStrings[i];
createDanMuEntity();//调用生成弹幕方法
production_timer
= 2f;//每隔2秒生成一个弹幕
}
#region
判断应该在第几行
foreach(GameObject
texintexts_queue.ToArray())//判断每一行是否满了
{
if(tex.transform.localPosition.y
== numb[0])//第一行
{
a
= 2;
}
else
if(tex.transform.localPosition.y
== numb[1])//第二行
{
a
= 3;
}
else
if(tex.transform.localPosition.y
== numb[2])//第三行
{
a
= 4;
}
else
if(tex.transform.localPosition.y
== numb[3])//第4行
{
a
= 1;
}
}
switch(a)
{
case1:
Row_index
= numb[0];
break;
case2:
Row_index
= numb[1];
break;
case3:
Row_index
= numb[2];
break;
case4:
Row_index
= numb[3];
break;
default:
Debug.Log("没有满足任何一行");
break;
}
#endregion
if(texts_queue.Count
>0)//退出队列方法一(节省资源开销)
{
GameObject
go = texts_queue.Peek();
if(go.transform.localPosition.x
< -999)//当弹幕位置移出屏幕
{
texts_queue.Dequeue();//移出队列
Destroy(go);//销毁弹幕
Debug.Log("save==="+
texts_queue.Count);
}
}
//foreach
(GameObject tex in texts_queue.ToArray())//退出队列方法二(耗费资源开销)
//{
//
if (tex.transform.localPosition.x < -999)//当弹幕位置移出屏幕
//
{
//
texts_queue.Dequeue();//移出队列
//
Destroy(tex);//销毁弹幕
//
Debug.Log("save===" + texts_queue.Count);
//
}
//}
}
[HideInInspector]
#region
弹幕内容(测试用)
publicstring[]
DanMuStrings =
{
"这个剧情也太雷人了吧!",
"还是好莱坞的电影经典啊,这个太次了还是好莱坞的电影经典啊,这个太次了",
"是电锯惊魂的主角,尼玛",
"这个游戏还是很良心的么",
"卧槽还要花钱,这一关也太难卧槽还要花钱,这一关也太难了卧槽还要花钱,这一关也太难了卧槽还要花钱,这一关也太难了了",
"这个游戏好棒偶",
"全是傻逼",
"求约:13122785566",
"最近好寂寞啊,还是这个游戏好啊是胸再大点就更是胸再大点就更是胸再大点就更",
"难道玩游戏还能撸",
"办证:010
- 888888",
"为什么女主角没有死?",
"好帅呦,你这个娘们儿",
"欠揍啊,东北人不知道啊",
"我去都是什么人啊,请文明用语还是好莱坞的电影经典啊,这个太次了是胸再大点就更",
"这个还是不错的",
"要是胸再大点就更好了",
"这个游戏必须顶啊",
"还是好莱坞的电影经典啊,这个太次了还是好莱坞的电影经典啊,这个太次了怎么没有日本动作爱情片中的角色呢?",
"好吧,这也是醉了!",
"他只想做一个安静的美男子!"
};
#endregion
publicvoidcreateDanMuEntity()//生成弹幕和移动弹幕
{
texts
= (GameObject)(Instantiate(textsdanmu, textpositon, textrotation));//生成弹幕
if(texts
!=null)
{
texts.transform.SetParent(Danmu_parents.transform);//设置父物体
//
texts.transform.parent = Danmu_parents.transform;//设置父物体的另种方法
texts.transform.localScale
=newVector3(1,
1, 1);
textrotation.eulerAngles
=newVector3(0,
0, 0);
texts.transform.localRotation
= textrotation;
texts.transform.localPosition
=newVector3(290,
Row_index, 0);//--弹幕移动的起始位置X
texts.transform.GetComponent().text
= content;//弹幕内容
if(texts.GetComponent()
==null)
texts.AddComponent();//添加DOTween插件
texts.transform.DOLocalMoveX(-1200,
20);//移动弹幕(20秒移动到-1200的位置)
}
texts_queue.Enqueue(texts);//生成的弹幕添加到队列
}
}
代码中的注释已经讲解了弹幕功能制作的每一步。大致思路是:
每隔2秒创建一个弹幕,然后使用DOTWeen插件进行弹幕移动和位置控制;用队列对生成的弹幕先后顺序进行控制和销毁。
运行效果如下;