效果演示
实现功能
服务端
实现通信功能,我选择的是Scoket通信。
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace ChatRoomService
{
class Service
{
Socket socketSevice ;
List<Socket> userList;
public Service()
{
socketSevice = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
userList = new List<Socket>();
}
public void Start()
{
socketSevice.Bind(new IPEndPoint(IPAddress.Any,10000));
socketSevice.Listen(10);
Console.WriteLine("服务器启动成功");
Thread accThread = new Thread(Accept);
accThread.IsBackground = true;
accThread.Start();
}
private void Accept()
{
Socket clientSocket = socketSevice.Accept();
userList.Add(clientSocket);
Console.WriteLine(IPToAddress(clientSocket)+"连接进来了");
Thread RecvThread = new Thread(ReceMessage);
RecvThread.IsBackground = true;
RecvThread.Start(clientSocket);
Accept();
}
private void ReceMessage(Object obj)
{
Socket client = obj as Socket;
byte[] strByte = new byte[1024];
string str = "";
try
{
int len = client.Receive(strByte);
str = Encoding.UTF8.GetString(strByte, 0, len);
if (str != "")
{
Broadcast(str,client);
Console.WriteLine(str);
}
}
catch (Exception e)
{
Console.WriteLine(IPToAddress(client)+"退出");
userList.Remove(client);
Thread.CurrentThread.Abort();
}
ReceMessage(client);
}
private void Broadcast(string userStr,object obj)
{
Socket clientSend = obj as Socket;
foreach (Socket client in userList)
{
if (client != clientSend)
{
client.Send(Encoding.UTF8.GetBytes(userStr));
}
}
}
private string IPToAddress(Socket soket)
{
return (soket.RemoteEndPoint as IPEndPoint).Address.ToString();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ChatRoomService
{
class Program
{
static void Main(string[] args)
{
Service ss = new Service();
ss.Start();
Console.ReadLine();
}
}
}
客户端
UI界面
Control
我将UI都放在Control空物体下,方便添加脚本统一管理。 RawIamge:用来播放视频,添加VideoPlayer组件 这里的TargetTexture是一个RenderTexture 记住这里的RenderTexture和RawImage大小设置成一样
SendMessage :是一个空物体,子物体是一个InputFiled用来读取输入的信息,还有一个Button用来发送信息 Last:上一集按钮 Next:下一集按钮 Together:一起看按钮
Panel
我们发送弹幕,弹幕都是在视频的上端,所以我就加一个Panel让在RawImage的上端位置,并且弹幕是从头出来才显示,到达另一端逐渐消失,所以为了达到这个效果 我的想法是每发送一条弹幕,我就生成一个Text从Panel右到左移动,所以Panel我家一个Mask组件达到遮罩效果,并且将生成Text做一个对象池,减小性能的消耗。并且Panel的Corol的透明度需要设置透明,但是不能为0,因为我要将Text成为Panel的子物体,方便管理,如果设置为0,Text就看不到了。这里必须将Text设置成Panel的子物体,因为Mask组件只能遮罩子物体。 我将Text设置成了预制体。
脚本
MessageFire
这个脚本最简单,我们给message这个预制体 我这个Message初始化位置就在这里,这样Message向左移动直接就会显示出来
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MessageFire : MonoBehaviour
{
private int StartPosX = 1300;
private int EndPosX = -1300;
private float speed = 150f;
void Start()
{
transform.localPosition=new Vector3(StartPosX,0,0);
}
void Update()
{
transform.localPosition=new Vector3(transform.localPosition.x-speed*Time.deltaTime,0,0);
if(transform.localPosition.x<EndPosX)
BarrageManager.GetInstace().RecyleMessageText(gameObject.GetComponent<Text>());
}
}
对象池BarrageManager
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BarrageManager : MonoBehaviour
{
private int index = 0;
private GameObject message;
private List<GameObject> messageLists=new List<GameObject>();
private static BarrageManager Instance;
public static BarrageManager GetInstace
{
get
{
return Instance;
}
}
private void Awake()
{
Instance = this;
message = Resources.Load<GameObject>("Prefab/Message");
}
private void Start()
{
InitiMessageText();
}
public GameObject GetMessageText()
{
for (int i = index% messageLists.Count; i < messageLists.Count; i++)
{
if (!messageLists[i].activeSelf)
{
if (index != i)
index = i;
index++;
if (index == messageLists.Count)
index = 0;
return messageLists[i];
}
}
InitiMessageText();
return GetMessageText();
}
public void RecyleMessageText(Text messagetext)
{
messagetext.gameObject.transform.localPosition=Vector3.zero;
messagetext.gameObject.SetActive(false);
}
void InitiMessageText()
{
for (int i = 0; i < 10; i++)
{
GameObject text=Instantiate(message);
text.transform.SetParent(transform);
text.SetActive(false);
messageLists.Add(text);
}
}
}
ChatRoom客户端连接
//这里我们还没有连接,我们需要生成一个ChatRoom才会连接,所以我们当点击一起看按钮就会实现连接功能
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace PXZ
{
public class ChatRoom
{
public string message = "";
public Socket clientSocket;
public ChatRoom()
{
clientSocket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
}
public void Connected(string IP, int port)
{
clientSocket.Connect(IP, port);
Thread RecThread=new Thread(RecvMessage);
RecThread.IsBackground = true;
RecThread.Start();
}
public void Send(string str)
{
if(str!="")
clientSocket.Send(Encoding.UTF8.GetBytes(str));
}
private void RecvMessage()
{
try
{
byte[] strByte=new byte[1024];
int len = clientSocket.Receive(strByte);
message = Encoding.UTF8.GetString(strByte, 0, len);
}
catch (Exception e)
{
Console.WriteLine(e);
Thread.CurrentThread.Abort();
throw;
}
RecvMessage();
}
}
}
ViewVideo
using System;
using System.Collections;
using System.Collections.Generic;
using PXZ;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
using UnityEngine.Video;
public class ViewVideo : MonoBehaviour
{
#region 单例模式
private static ViewVideo Instance;
public static ViewVideo GetInstance
{
get
{
return Instance;
}
}
#endregion
public List<VideoClip> clips=new List<VideoClip>();
public bool connect = false;
private int index = 0;
private VideoPlayer videoPlayer;
private Button last;
private Button next;
private Button send;
private Button togerher;
public ChatRoom client;
private void Awake()
{
Instance = this;
videoPlayer = transform.GetChild(0).GetComponent<VideoPlayer>();
last = transform.GetChild(2).GetComponent<Button>();
next = transform.GetChild(3).GetComponent<Button>();
togerher = transform.GetChild(4).GetComponent<Button>();
last.onClick.AddListener(LastButtonOnclik);
next.onClick.AddListener(NextButtonOnclik);
togerher.onClick.AddListener(TogetherButtonOnclik);
}
private void Update()
{
if (connect)
{
if (client.message != "" && client.message!="1"&& client.message!="0")
{
SendMessageFire.Instace.TextFire(client.message);
}
if (client.message == "1" || client.message=="0")
{
ViewVideo.GetInstance.ViewPlayerChange(Convert.ToInt32(client.message));
}
client.message = "";
}
}
private void OnDestroy()
{
if (client != null)
{
client.clientSocket.Close();
}
}
private void NextButtonOnclik()
{
if (connect)
{
client.Send("1");
}
index++;
if (index == clips.Count)
index = 0;
videoPlayer.clip = clips[index];
}
private void LastButtonOnclik()
{
if(connect)
{
client.Send("0");
}
index--;
if (index < 0)
index = clips.Count - 1;
videoPlayer.clip = clips[index];
}
private void TogetherButtonOnclik()
{
if (client == null)
{
client=new ChatRoom();
client.Connected("127.0.0.1",10000);
connect = true;
}
}
public void ViewPlayerChange(int x)
{
if (x == 1)
{
index++;
if (index == clips.Count)
index = 0;
}
if (x == 0)
{
index--;
if (index < 0)
index = clips.Count - 1;
}
videoPlayer.clip = clips[index];
}
}
SendMessageFire
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SendMessageFire : MonoBehaviour
{
#region 单例模式
private static SendMessageFire instace;
public static SendMessageFire Instace
{
get
{
return instace;
}
}
#endregion
private InputField messageInput;
private Button sendButton;
private string message;
private void Awake()
{
instace = this;
messageInput = transform.GetChild(0).GetComponent<InputField>();
sendButton = transform.GetChild(1).GetComponent<Button>();
sendButton.onClick.AddListener(SendButtonOnclik);
}
void SendButtonOnclik()
{
message = messageInput.text;
messageInput.text = "";
if (message != "")
{
if (ViewVideo.GetInstance.connect)
{
ViewVideo.GetInstance.client.Send(message);
}
TextFire(message);
}
}
public void TextFire(string str)
{
GameObject messageObject = BarrageManager.GetInstace.GetMessageText();
Text messageText= messageObject.GetComponent<Text>();
messageText.text = str;
messageObject.SetActive(true);
}
}
脚本添加
Control添加ViewVideo脚本,并给Clips初始化添加视频
SendMessage Panel
问题
- 当两人观看视频不一致的时候,两者点击一起看,再点击上一集或下一集,但是无法保持观看视频一致
- 当两人连接一起看后,一旦一方断开连接关闭程序,服务器就会崩坏。
- 两人一起看,两人都可以更换视频,没有做到只有管理员才能更换视频。没有管理员功能
但是总体功能都已经实现
|