频道栏目
首页 > 程序开发 > 移动开发 > 其他 > 正文
Unity模拟弹幕效果
2016-10-13 09:09:59         来源:御雪妃舞  
收藏   我要投稿

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>
    ///<cke:param name="text"></cke: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>
    ///<cke:param name="clientSocket"></cke: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
{
    /// 
    /// text预制获取
    /// 
    public TextItem item;
    
    /// 
    /// 设立弹幕父物体
    /// 
    public Transform parent;

    /// 
    /// 当前输入框控件
    /// 
    private InputField inputField;

    /// 
    /// 客户端是否有消息发送
    /// 
    public static bool msgReturn = false;

    // Use this for initialization
    void Start()
    {
        //初始化
        inputField = GetComponent();
    }

    

    void Update()
    {
        //监测客户端消息发送,根据消息实例化弹幕
        if (msgReturn)
        {
            msgReturn = false;
            CreateItem(TcpServer.Info);
        }
    }

    /// 
    /// 输入完成,创建输入内容的弹幕
    /// 
    public void OnSumbit()
    {
        CreateItem(inputField.text);
        inputField.text = "";
    }

    /// 
    /// 实例化弹幕
    /// 
    ///弹幕内容
    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方法一直在执行:

 

\

 

但是结束的时候明明关闭了服务且停止了所有线程:

 

\

 

以上三个问题拜托会的人能交流解答下,谢谢!

点击复制链接 与好友分享!回本站首页
上一篇:多渠道打包之动态修改App名称,图标,applicationId,版本号,添加资源
下一篇:Java Socket 通信 (三)
相关文章
图文推荐
文章
推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站