最后一篇了,给大家介绍一下Unity与UE4之间的通信。
为什么我会想到用Unity和UE4通信呢,主要是有一次开发的时候,我想用UE4打一个IOS包时发现,UE4打IOS包太烦了,搞了好几次都打包失败,这时就看出Unity的优势在哪了,Unity打IOS包真是比UE4方便多了,所以我就想着用Unity做客户端,用UE4做服务器端,采用UDP通信实现他们的消息互传。
1、 首先是服务器端,新建一个UE4工程,新建一个C++类,生成.cpp和.h两个文件
.cpp文件代码
#include "UDPRecive.h"
// Sets default values
AUDPRecive::AUDPRecive()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
ListenSocket = NULL;
}
// Called when the game starts or when spawned
void AUDPRecive::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AUDPRecive::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AUDPRecive::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
//~~~~~~~~~~~~~~~~
delete UDPReceiver;
UDPReceiver = nullptr;
//Clear all sockets!
// makes sure repeat plays in Editor dont hold on to old sockets!
if (ListenSocket)
{
ListenSocket->Close();
ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(ListenSocket);
}
}
//Start UDP Receiver
void AUDPRecive::StartUDPReceiver(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort, bool& success) // 接收器初始化 接收信息前
{
TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
FIPv4Address Addr;
FIPv4Address::Parse(TheIP, Addr);
//Create Socket
FIPv4Endpoint Endpoint(FIPv4Address::Any, ThePort); //所有ip地址本地
//FIPv4Endpoint Endpoint(Addr, ThePort); //指定ip地址
ListenSocket = FUdpSocketBuilder(*YourChosenSocketName)
.AsNonBlocking()
.AsReusable()
.BoundToEndpoint(Endpoint)
.WithReceiveBufferSize(2 * 1024 * 1024)
;
//BUFFER SIZE
int32 BufferSize = 2 * 1024 * 1024;
ListenSocket->SetSendBufferSize(BufferSize, BufferSize);
ListenSocket->SetReceiveBufferSize(BufferSize, BufferSize);
if (!ListenSocket)
{
ScreenMsg("No socket");
success = false;
}
if (ListenSocket)
{
ScreenMsg("The receiver is initialized");
success = true;
}
//return true;
}
void AUDPRecive::DataRecv(FString& str, bool& success) //接收消息处理
{
if (!ListenSocket)
{
ScreenMsg("No sender socket");
success = false;
//return success;
}
TSharedRef<FInternetAddr> targetAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();
TArray<uint8> ReceivedData;//定义一个接收器
uint32 Size;
if (ListenSocket->HasPendingData(Size))
{
success = true;
str = "";
uint8 *Recv = new uint8[Size];
int32 BytesRead = 0;
ReceivedData.SetNumUninitialized(FMath::Min(Size, 65507u));
ListenSocket->RecvFrom(ReceivedData.GetData(), ReceivedData.Num(), BytesRead, *targetAddr);//创建远程接收地址
char ansiiData[1024];
memcpy(ansiiData, ReceivedData.GetData(), BytesRead);//拷贝数据到接收器
ansiiData[BytesRead] = 0; //判断数据结束
FString debugData = ANSI_TO_TCHAR(ansiiData); //字符串转换
str = debugData;
// memset(ansiiData,0,1024);//清空
}
else
{
success = false;
}
//return success;
}
.h文件代码
#pragma once
#include "Engine.h"
#include "Runtime/Networking/Public/Networking.h"
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "UDPRecive.generated.h"
UCLASS()
class UDPMANAGER_API AUDPRecive : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AUDPRecive();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
FSocket * ListenSocket;
FUdpSocketReceiver* UDPReceiver = nullptr;
UFUNCTION(BlueprintCallable, Category = "UDP")
void StartUDPReceiver(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort, bool& success);
UFUNCTION(BlueprintPure, Category = "UDP")
void DataRecv(FString& str, bool& success);
//ScreenMsg
FORCEINLINE void ScreenMsg(const FString& Msg)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, *Msg);
}
FORCEINLINE void ScreenMsg(const FString& Msg, const float Value)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %f"), *Msg, Value));
}
FORCEINLINE void ScreenMsg(const FString& Msg, const FString& Msg2)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %s"), *Msg, *Msg2));
}
public:
/** Called whenever this actor is being removed from a level */
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
};
.Build.cs文件如下
using UnrealBuildTool;
public class UDPManager : ModuleRules
{
public UDPManager(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "Sockets", "Networking" });
PrivateDependencyModuleNames.AddRange(new string[] { });
// Uncomment if you are using Slate UI
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
// Uncomment if you are using online features
// PrivateDependencyModuleNames.Add("OnlineSubsystem");
// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
}
}
新建蓝图类继承刚才的C++类,将蓝图类拖入map中,打开蓝图类
2、然后是客户端,新建一个Unity程序,主要是以下几个脚本文件
登陆界面脚本LoginBegan.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using DG.Tweening;
public class LoginBegan : MonoBehaviour {
public static LoginBegan login;
public GameObject administratorInterface;//IP连接的Panel
public GameObject UpShowView;
public InputField[] meessage;
public string recvIP;
public string recvPort;
// Use this for initialization
private void Awake()
{
}
void Start() {
login = this;
}
//得到输入的IP值
public void InputIp()
{
recvIP = meessage[0].text;
}
public void InputPort()
{
recvPort = meessage[1].text;
}
}
消息传输脚本TCPClientTest.cs
using UnityEngine;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class TCPClientTest : MonoBehaviour
{
public static TCPClientTest tcp;
public static bool successTemp = false;
public static Socket clientSocket;
private IPEndPoint server_Address;
//接收到的数据
//private byte[] data_Receive = new byte[1024];
//要发送的数据
private byte[] data_Send = new byte[1024];
public Thread t;
public GameObject[] panelRestore;//缩放还原
void Start()
{
tcp = this;
}
// Update is called once per frame
void Update()
{
if (successTemp)
{
LianJie();
InitSocket();
}
successTemp = false;
}
void OnApplicationQuit()
{
SocketQuit();
}
//IPEndPoint IP_Address;
public void ConnectBut()
{
successTemp = true;
Debug.Log(successTemp);
}
public void InitSocket()
{
//设置IP地址和端口号,用户监听消息
server_Address = new IPEndPoint(IPAddress.Parse(GetCurrentIP()), 2333);
// Debug.Log("6666666666666666666666666666666666666666666666666666666666666");
//初始化Socket
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Debug.Log("7777777777777777777777777777777777777777777777777777777777777777");
// Debug.Log("AAAAAAAAAAAAAAAAAAAAAAAAAA" + clientSocket.ToString() + "BBBBBBBBBBBBBBBBBBBBBB" + server_Address.Port);
//clientSocket.Bind(server_Address);
// Debug.Log("333333333333333333333333333333333333333333333333333333333333");
//启动接收数据的线程
// receiveThread = new Thread(Socket_Receive);
// receiveThread.Start();
}
//获取本机的IP地址
private string GetCurrentIP()
{
string name = Dns.GetHostName();
IPAddress[] ipadrlist = Dns.GetHostAddresses(name);
foreach (IPAddress ipa in ipadrlist)
{
if (ipa.AddressFamily == AddressFamily.InterNetwork)
{
return ipa.ToString();
}
}
return null;
}
private void SocketQuit()
{
//终止线程
if (t != null)
{
t.Interrupt();
t.Abort();
}
//关闭socket
if (clientSocket != null)
clientSocket.Close();
}
//LoginBegan.login.recvIP
//int.Parse(LoginBegan.login.recvPort)
public void Socket_Send(string _msg)
{
//IPEndPoint IP_Address = new IPEndPoint(IPAddress.Parse("192.168.1.182"), 60095);
//IPEndPoint IP_Address = new IPEndPoint(IPAddress.Parse("192.168.1.121"), 59226);
IPEndPoint IP_Address = new IPEndPoint(IPAddress.Parse(LoginBegan.login.recvIP), int.Parse(LoginBegan.login.recvPort));
data_Send = Encoding.UTF8.GetBytes(_msg);
//将消息发送给指定IP地址和端口
clientSocket.SendTo(data_Send, IP_Address);
}
private static readonly object locker = new object();
private TCPClientTest() { }
public static TCPClientTest Login()
{
if (tcp == null)
{
lock (locker)
{
if (tcp == null)
{
tcp = new TCPClientTest();
}
}
}
return tcp;
}
public string sendStr ;
public void QuYuShaPan()
{
sendStr = "10004";
Socket_Send(sendStr);
}
public void LianJie()
{
LoginBegan.login.administratorInterface.SetActive(false);//连接界面隐藏
LoginBegan.login.UpShowView.SetActive(true); //其他界面显示
}
}
运行效果如下
登录成功之后,点击send,成功接收到消息10014。
Demo地址:https://download.youkuaiyun.com/download/sxx930923/10908746