UE4打通UDP接口,实施案例1

最近跟进的一个汽车相关的项目。UE4开发的HMI原型软件,需UDP通信接口打通,之前没碰过UE4,特记录一下实施过程。

1、下载安装ue4。下载前注册Epic Games账号(此账号可以用来购买虚幻商城的产品,有素材有游戏。素材有不少免费的,可以按需下载)

2、在HMI软件中添加BlueprintFunctionLibrary类。

3、在**.Build.cs 文件中添加依赖模型“Sockets”, “Networking”,代码示例如下:

// Fill out your copyright notice in the Description page of Project Settings.

using UnrealBuildTool;

public class Cluster : ModuleRules
{
    public Cluster(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
    }
}

4、UDPSocketServer.cpp代码如下:

// Fill out your copyright notice in the Description page of Project Settings.


#include "UDPSocketServer.h"
TSharedPtr<FInternetAddr> RemoteAddr;
FSocket* SenderSocket;
FSocket* ListenSocket;
FUdpSocketReceiver* UDPReceiver = nullptr;

void ScreenMsg(const FString& Msg)
{
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, *Msg);
}
void ScreenMsg(const FString& Msg,const float Value)
{
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %f"), *Msg, Value));
}
void ScreenMsg(const FString& Msg, const FString& Msg2)
{
    GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("%s %s"), *Msg, *Msg2));
}

void UUDPSocketServer::CloseUDPSender()
{

    if (SenderSocket) //Clear all sockets!
    {
        SenderSocket->Close();
        ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->DestroySocket(SenderSocket);
    }
}


bool UUDPSocketServer::RamaUDPSenderSendString(FString ToSend)                 //发送消息处理
{
    if (!SenderSocket)
    {
        ScreenMsg("No sender socket");
        return false;
    }
    //~~~~~~~~~~~~~~~~
    //发送消息
    int32 BytesSent = 0;
    FString serialized = ToSend;
    TCHAR* serializedChar = serialized.GetCharArray().GetData();
    int32 size = FCString::Strlen(serializedChar);
    int32 sent = 0;
    //SenderSocket->SendTo(Writer.GetData(), Writer.Num(), BytesSent, *RemoteAddr);
    SenderSocket->SendTo((uint8*)TCHAR_TO_UTF8(serializedChar), size, BytesSent, *RemoteAddr);//发送给远端地址

    if (BytesSent <= 0)
    {
        const FString Str = "Socket is valid but the receiver received 0 bytes, make sure it is listening properly!";
        UE_LOG(LogTemp, Error, TEXT("%s"), *Str);
        ScreenMsg(Str);
        return false;
    }

    ScreenMsg("UDP Send Succcess! INFO Sent = ", ToSend);

    return true;
}

void UUDPSocketServer::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);//清空 
        ScreenMsg(str);

    }
    else
    {
        success = false;
    }

}
bool UUDPSocketServer::StartUDPSender(const FString& YourChosenSocketName, const FString& TheIP, const int32 ThePort)///初始化远端IP 发送信息前
{
    //FIPv4Endpoint Endpoint(FIPv4Address::Any, 6789);
    //Create Remote Address.
    RemoteAddr = ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM)->CreateInternetAddr();

    bool bIsValid;
    RemoteAddr->SetIp(*TheIP, bIsValid);
    RemoteAddr->SetPort(ThePort);

    if (!bIsValid)
    {
        ScreenMsg("Rama UDP Sender>> IP address was not valid!", TheIP);
        return false;
    }


    SenderSocket = FUdpSocketBuilder(*YourChosenSocketName)
        .AsReusable()
        .WithBroadcast() // 广播
        .WithSendBufferSize(2 * 1024 * 1024)
        //.BoundToEndpoint(Endpoint)
        ;


    //check(SenderSocket->GetSocketType() == SOCKTYPE_Datagram);

    //Set Send Buffer Size
    int32 SendSize = 2 * 1024 * 1024;
    SenderSocket->SetSendBufferSize(SendSize, SendSize);
    SenderSocket->SetReceiveBufferSize(SendSize, SendSize);
    if (bIsValid)
    {
        bIsValid = true;
    }
    return bIsValid;

}

void UUDPSocketServer::CloseUDPReceiver()
{
    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);
    }
}

void UUDPSocketServer::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;

}

5、UDPSocketServer.h代码如下:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"

#include "Runtime/Networking/Public/Networking.h"
#include "Engine.h"
#include "UDPSocketServer.generated.h"

/**
 * 
 */
UCLASS()
class UDPCLUSTER0505_API UUDPSocketServer : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()

public:
    UFUNCTION(BlueprintCallable, Category = "UDP")        
        static void StartUDPReceiver(const FString& YourChosenSocketName, const FString& TheIp, const int32 ThePort, bool& success);
    UFUNCTION(BlueprintCallable, Category = "UDP")
        static bool StartUDPSender(const FString& YourChosenSocketName, const FString& TheIp, const int32 ThePort);

    UFUNCTION(BlueprintCallable, Category = "UDP")
        static void CloseUDPReceiver();
    UFUNCTION(BlueprintCallable, Category = "UDP")
        static void CloseUDPSender();
    UFUNCTION(BlueprintCallable, Category = "UDP")
        static bool RamaUDPSenderSendString(FString ToSend);
    UFUNCTION(BlueprintCallable, Category = "UDP")
        static void DataRecv(FString& str, bool& success);
    
};
6、蓝图调用如下:

7、搞定收工! 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
UE4是一款强大的游戏引擎,其中的材质节点是用来创建和控制游戏中物体的表面外观的。在UE4中编写材质节点需要使用C++编程语言来创建自定义的节点。 首先,我们需要创建一个用于材质编程的MaterialInstanceDynamic对象。我们可以使用以下代码来创建它: UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(OriginalMaterial, nullptr); 接下来,我们可以通过使用DynamicMaterial来设置和控制材质的参数。例如,我们可以使用以下代码来设置节点的颜色参数: DynamicMaterial->SetVectorParameterValue(FName("Color"), FLinearColor(1.0f, 0.0f, 0.0f)); 除了设置基本的参数,我们还可以设置纹理和其他复杂的节点属性。例如,我们可以使用以下代码来设置一个纹理节点: DynamicMaterial->SetTextureParameterValue(FName("Texture"), Texture); 我们还可以使用C++代码来创建和连接各种节点的输入和输出。例如,我们可以使用以下代码来创建一个常量节点: UMaterialExpressionConstant* ConstantNode = NewObject<UMaterialExpressionConstant>(); ConstantNode->R = 0.5f; ConstantNode->G = 0.5f; ConstantNode->B = 0.5f; 然后,我们可以使用以下代码将该节点连接到材质的Diffuse输入节点上: DynamicMaterial->BaseColor.Expression = ConstantNode; 最后,我们需要将DynamicMaterial应用于我们想要渲染的物体上。我们可以使用以下代码来完成这一步骤: MeshComponent->SetMaterial(0, DynamicMaterial); 通过使用UE4中的C++编程语言,我们可以创建复杂的材质节点,从而实现更高级的渲染效果和外观。这使得我们能够在游戏中创造出令人印象深刻的图形效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值