Unity模拟弹幕效果
Posted 御雪妃舞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity模拟弹幕效果相关的知识,希望对你有一定的参考价值。
最近看到好多平台都有弹幕,觉得挺有意思,就做的试试看,但也有不少问题。
1.制作弹幕字体预制
新建一个unity工程,新建了一个Canvas的Text,然后制作脚本,主要用来字体移动效果和文本输入,建立的脚本叫TextItem,脚本内容如下:using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class TextItem : MonoBehaviour
/// <summary>
/// text控件显示文字
/// </summary>
public string text="";
/// <summary>
/// 当前脚本所在的text控件
/// </summary>
private Text currentText;
/// <summary>
/// 弹幕移动的速度
/// </summary>
public float speed;
void Start()
//初始化
currentText = GetComponent<Text>();
//设置显示字体以及随机颜色
currentText.text = text;
currentText.color = Random.ColorHSV();
//获取屏幕范围内的y坐标随机,这里没做屏幕适配,free aspect举列
float y = Random.Range(-200f, 220f);
transform.localPosition = new Vector3(550f, y, 0);
void Update()
if (speed != 0)
float x = transform.localPosition.x + speed * Time.deltaTime;
transform.localPosition = new Vector3(x, transform.localPosition.y, 1);
//出屏幕销毁
if (transform.localPosition.x < -550f)
Destroy(gameObject);
然后把Text控件挂上脚本拖入Project中成为预制。
2.建立输入框,输入弹幕内容,生成弹幕
Canvas下建立unity自带的ugui带的InputField控件,并且建立脚本叫InputControl,脚本内容如下:using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class InputControl : MonoBehaviour
/// <summary>
/// text预制获取
/// </summary>
public TextItem item;
/// <summary>
/// 设立弹幕父物体
/// </summary>
public Transform parent;
/// <summary>
/// 当前输入框控件
/// </summary>
private InputField inputField;
// Use this for initialization
void Start()
//初始化
inputField = GetComponent<InputField>();
/// <summary>
/// 输入完成,创建输入内容的弹幕
/// </summary>
public void OnSumbit()
CreateItem(inputField.text);
inputField.text = "";
/// <summary>
/// 实例化弹幕
/// </summary>
/// <param name="text">弹幕内容</param>
public void CreateItem(string text)
var temp = Instantiate(item) as TextItem;
temp.transform.SetParent(parent);
temp.text = text;
把脚本挂到InputField控件上,并且在InputField的脚本上设置On End Exit执行OnSumbit方法,并且拖拽InputControl脚本的预制和父物体内容,具体效果如图:
3.单机的弹幕效果完成
按照前面两步后,运行,就可以看到自己在输入框中输入内容,弹幕就飘出来了,然后继续输入,会继续飘出来,效果如图:中英文都可以输入
当然这只是单机的效果。
4.延伸到服务器
这里我们把当前的项目端当做服务器端,制作一个本机的服务器和客户端的交互,当然楼主对服务器内容知道的很少,遇到了不少问题,具体的后面再说。
首先我们新建一个服务器脚本叫TcpServer,设置ip为本机的:127.0.0.1,端口假设为是10050,具体脚本内容如下:
Tcp脚本:
using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
public class TcpServer : MonoBehaviour
/// <summary>
/// 接受客户端消息字段
/// </summary>
private static byte[] result = new byte[1024];
/// <summary>
/// 设定端口
/// </summary>
private static int myProt = 10050;
/// <summary>
/// Socket服务
/// </summary>
static Socket serverSocket;
/// <summary>
/// 接受消息的文本
/// </summary>
public static String Info="";
/// <summary>
/// 所有线程的队列
/// </summary>
public static List<Thread> allThreads;
void Awake()
//初始化线程队列
allThreads = new List<Thread>();
allThreads.Clear();
void Start()
//服务器IP地址
IPAddress ip = IPAddress.Parse("127.0.0.1");
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(ip, myProt)); //绑定IP地址:端口
serverSocket.Listen(10); //设定最多10个排队连接请求
Debug.Log("启动监听" + "成功" + serverSocket.LocalEndPoint.ToString());
//通过Clientsoket发送数据
Thread myThread = new Thread(ListenClientConnect);
myThread.Start();
allThreads.Add(myThread);
/// <summary>
/// 监听客户端连接
/// </summary>
private static void ListenClientConnect()
while (true)
Debug.Log("My Thread is running");
Socket clientSocket = serverSocket.Accept();
clientSocket.Send(Encoding.ASCII.GetBytes("Server Say Hello"));
Thread receiveThread = new Thread(ReceiveMessage);
receiveThread.Start(clientSocket);
allThreads.Add(receiveThread);
/// <summary>
/// 接收消息
/// </summary>
/// <param name="clientSocket"></param>
private static void ReceiveMessage(object clientSocket)
Socket myClientSocket = (Socket)clientSocket;
while (true)
try
Debug.Log("receiveThread is running");
//通过clientSocket接收数据
int receiveNumber = myClientSocket.Receive(result);
Debug.Log(String.Format("接收客户端0消息1", myClientSocket.RemoteEndPoint.ToString(), Encoding.ASCII.GetString(result, 0, receiveNumber)));
Info = Encoding.ASCII.GetString(result, 0, receiveNumber);
//调用主线程方法出错,后使用临时解决方案,在Update里执行
InputControl.msgReturn = true;
catch (Exception ex)
Debug.Log(ex.Message);
myClientSocket.Shutdown(SocketShutdown.Both);
myClientSocket.Close();
break;
/// <summary>
/// 关闭所有的线程,并关闭服务
/// </summary>
private static void ServerClosed()
Debug.Log("总共有" + allThreads.Count + "个线程在运行");
foreach (var item in allThreads)
item.Abort();
Debug.Log(item.Name + " is stop");
serverSocket.Close();
void OnDestroy()
Debug.Log("server closed");
ServerClosed();
当然此时的InputControl有所改动,改后的内容如下:
InputControl脚本:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class InputControl : MonoBehaviour
/// <summary>
/// text预制获取
/// </summary>
public TextItem item;
/// <summary>
/// 设立弹幕父物体
/// </summary>
public Transform parent;
/// <summary>
/// 当前输入框控件
/// </summary>
private InputField inputField;
/// <summary>
/// 客户端是否有消息发送
/// </summary>
public static bool msgReturn = false;
// Use this for initialization
void Start()
//初始化
inputField = GetComponent<InputField>();
void Update()
//监测客户端消息发送,根据消息实例化弹幕
if (msgReturn)
msgReturn = false;
CreateItem(TcpServer.Info);
/// <summary>
/// 输入完成,创建输入内容的弹幕
/// </summary>
public void OnSumbit()
CreateItem(inputField.text);
inputField.text = "";
/// <summary>
/// 实例化弹幕
/// </summary>
/// <param name="text">弹幕内容</param>
public void CreateItem(string text)
var temp = Instantiate(item) as TextItem;
temp.transform.SetParent(parent);
temp.text = text;
在场景中新建一个空物体,挂上TcpServer脚本,这里我们用了一个tcp分析工具模拟了一个客户端:
运行流程如下:
首先运行,发现服务器启动
然后运行分析器工具:
注意红框的地方设置好客户端,ip,端口后点击,建立连接
点击后,连接成功,服务器返回了消息,跟你说Hello
然后我们在下面的框中输入:Hello world,然后点击发送数据,如图:
客户端这边显示的是发送成功了。
我们再到Unity服务器端看下它是否接受到了:
看如下图片内容打印的日志,服务器是接受到了
Game界面也飘出了我们发送的字体弹幕如图:
到这里,我们小小的客户端和服务器的互动功能就完成了,你也可以不用Tcp工具,复制工程一份,写一个客户端的脚本,另一个工程当做客户端在输入框中输入消息,不仅客户端自己可以看到,而且服务器端的工程也能看到。
当然这里由于不是很懂Socket的原因也遇到了不少问题。
5.遇到的问题
a.线程问题
在服务器端的Receive线程中无法调用主线程的方法,比如我用InputControl的单列来调用它的方法就会报这样的错:目前采用的是临时解决方案,根据布尔值在Update里调用:
有知道 其它解决方案的大神,希望多多指教。
b.客户端发送中文乱码问题
比如,我在客户端工具中发送中文如图:然后Untiy里接受和显示出来的都是问号:
c.线程停不掉的问题
当我tcp分析器,断开连接后,服务器端的Receive脚本的线程一直在每帧执行,即使unity停止运行了还是如此:
如图所示的脚本receive方法一直在执行:
但是结束的时候明明关闭了服务且停止了所有线程:
以上三个问题拜托会的人能交流解答下,谢谢!
工程源码下载
以上是关于Unity模拟弹幕效果的主要内容,如果未能解决你的问题,请参考以下文章
如图,如何在Unity中判断一个物体自身的旋转是不是处于某个特定范围内?