<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      UE4 中實現簡單的本地登錄注冊功能 (UMG C++ 入門向)

      前言

      之前在 minigame 中開發游戲的登錄注冊功能時,發現網上關于 UE4 的介紹資料寥寥,對于登錄注冊功能的介紹更少,且大多要求通過 HTTP 等網絡協議與服務器或者數據庫進行通信交互,提高了開發難度,且不符合我們只是想做一個休閑單機小游戲的預期。

      在翻閱了相關資料后,找到了一種通過本地文件交互實現登錄注冊功能的方法,考慮到相關資料介紹并不多,將實現方式總結如下,僅是一篇拋磚引玉的文章,希望有興趣的人多多交流學習。

      一、前期準備

      Unreal Engine 4.25.4

      Visual Studio 2019

      1. 新建空白項目,命名為 LoginRegister

      新建空白項目

      2. 新建空白關卡和對應的用戶控件

      空白關卡和對應的用戶控件

      如何新建關卡可以參考以下視頻
      新關卡一片黑?初學者必知的UE4新建關卡時的一些設置【虛幻引擎】

      3. 修改關卡 Login 的關卡藍圖,將 UMG 添加到視口

      修改關卡

      二、修改控件

      首先修改控件 LoginUI,添加兩個文本框和兩個按鈕。

      控件 UI

      需要注意的地方

      1. 按鈕和可編輯文本框需要暴露為變量,而且為了方便后續編碼需要起合適的變量名,比如 UsernameTextBoxPasswordTextBoxLoginButtonRegisterButton
      2. 密碼文本框需要在外觀中設置成 為密碼
      3. 可編輯文本框的提示文本可以在外觀中進行設置,比如上圖中的 請輸入用戶名請輸入密碼
      4. 按鈕里的文字需要使用文本控件,并用外層按鈕進行包裹作為子控件。

      這樣就完成了基本的 UI 設計,修改完后別忘了保存和編譯。

      執行當前 Login 關卡,顯示以下界面。

      登錄界面

      三、UMG C++ 添加控件邏輯

      新建 C++ 類,注意需要打開 顯示所有類,繼承自 UserWidget 父類,并將生成的類命名為 LoginWidget,如下圖所示。

      選擇父類

      控件類命名

      生成源文件后,編輯源碼 LoginWidget.hLoginWidget.cpp

      // LoginWidget.h
      // Fill out your copyright notice in the Description page of Project Settings.
      
      #pragma once
      
      #include "CoreMinimal.h"
      #include "Blueprint/UserWidget.h"
      #include "Components/Button.h"          // 使用按鈕控件 api
      #include "Components/EditableTextBox.h" // 使用可編輯文本框 api
      
      #include "LoginWidget.generated.h"
      
      /**
       *
       */
      UCLASS()
      class LOGINREGISTER_API ULoginWidget : public UUserWidget
      {
      	GENERATED_BODY()
      
      public:
          // 構造函數
      	ULoginWidget(const FObjectInitializer& ObjectInitializer);
      
          // 點擊登錄按鈕的響應事件
          UFUNCTION()
      	    void PlayerLogin();
          // 點擊注冊按鈕的響應事件
          UFUNCTION()
              void PlayerRegister();
      
      protected:
      	virtual void NativeConstruct();
      
          // 工具函數: 檢查數據文件是否存在
          bool CheckTextFileExists(FString FileName);
          // 工具函數: 將數據存入文本文件
          bool SaveToTextFile(FString FileName);
          // 工具函數: 從文本文件讀取數據
          bool LoadFromTextFile(FString FileName);
      
      private:
      
          UButton* LoginButton;
          UButton* RegisterButton;
      
          UEditableTextBox* UsernameTextBox;
          UEditableTextBox* PasswordTextBox;
      
          FString Username;
          FString Password;
      };
      
      
      // LoginWidget.cpp
      // Fill out your copyright notice in the Description page of Project Settings.
      
      
      #include "LoginWidget.h"
      #include "HAL/PlatformFileManager.h"
      
      ULoginWidget::ULoginWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
      {
          LoginButton = nullptr;
          RegisterButton = nullptr;
          UsernameTextBox = nullptr;
          PasswordTextBox = nullptr;
      }
      
      void ULoginWidget::NativeConstruct()
      {
      	Super::NativeConstruct();
      
          UE_LOG(LogTemp, Warning, TEXT("ULoginWidget::NativeConstruct()"));
      
          if (UButton* SBtn = Cast<UButton>(GetWidgetFromName("LoginButton")))
          {
              LoginButton = SBtn;
      
              FScriptDelegate sgbDelegate;
              sgbDelegate.BindUFunction(this, "PlayerLogin");
              LoginButton->OnClicked.Add(sgbDelegate);
          }
          if (UButton* SBtn = Cast<UButton>(GetWidgetFromName("RegisterButton")))
          {
              RegisterButton = SBtn;
      
              FScriptDelegate sgbDelegate;
              sgbDelegate.BindUFunction(this, "PlayerRegister");
              RegisterButton->OnClicked.Add(sgbDelegate);
          }
          if (UEditableTextBox* SText = Cast<UEditableTextBox>(GetWidgetFromName("UsernameTextBox")))
          {
              UsernameTextBox = SText;
          }
          if (UEditableTextBox* SText = Cast<UEditableTextBox>(GetWidgetFromName("PasswordTextBox")))
          {
              PasswordTextBox = SText;
          }
      }
      
      void ULoginWidget::PlayerLogin()
      {
          if (UsernameTextBox == nullptr || PasswordTextBox == nullptr)
          {
              UE_LOG(LogTemp, Warning, TEXT("Widget can't get"));
              return;
          }
      
          // 獲取當前編輯框內的文本內容
          FText UsernameText = UsernameTextBox->GetText();
          FText PasswordText = PasswordTextBox->GetText();
          FString UsernameStr = UsernameText.ToString();
          FString PasswordStr = PasswordText.ToString();
          if (UsernameStr.Len() <= 0 || PasswordStr.Len() <= 0)
          {
              UE_LOG(LogTemp, Warning, TEXT("Username or Password must not be empty"));
              return;
          }
      
          // 數據文件路徑
          FString FileName = TEXT("Player_") + UsernameStr + TEXT(".data");
      
          // 找不到數據文件,用戶未注冊
          if (!this->CheckTextFileExists(FileName))
          {
              UE_LOG(LogTemp, Warning, TEXT("Player-[%s] Not Registered"), *UsernameStr);
              return;
          }
      
          // 讀取數據文件
          if (!this->LoadFromTextFile(FileName))
          {
              UE_LOG(LogTemp, Warning, TEXT("Player-[%s] Login Failed. DataFile Wrong Occured"), *UsernameStr);
              return;
          }
      
          // 檢查密碼正確性
          if (this->Password != PasswordStr)
          {
              UE_LOG(LogTemp, Warning, TEXT("Player-[%s] Login Failed. Password Not Correct"), *UsernameStr);
              return;
          }
      
          // Login Successfully. Do Something !
          GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Red, TEXT("Login Successfully"), false, FVector2D(2.0, 2.0));
      }
      
      void ULoginWidget::PlayerRegister()
      {
          if (UsernameTextBox == nullptr || PasswordTextBox == nullptr)
          {
              UE_LOG(LogTemp, Warning, TEXT("Widget can't get"));
              return;
          }
      
          // 獲取當前編輯框內的文本內容
          FText UsernameText = UsernameTextBox->GetText();
          FText PasswordText = PasswordTextBox->GetText();
          FString UsernameStr = UsernameText.ToString();
          FString PasswordStr = PasswordText.ToString();
          if (UsernameStr.Len() <= 0 || PasswordStr.Len() <= 0)
          {
              UE_LOG(LogTemp, Warning, TEXT("Username or Password must not be empty"));
              return;
          }
      
          // 數據文件路徑
          FString FileName = TEXT("Player_") + UsernameStr + TEXT(".data");
      
          // 存在數據文件,用戶已注冊
          if (this->CheckTextFileExists(FileName))
          {
              UE_LOG(LogTemp, Warning, TEXT("Player-[%s] Already Registered"), *UsernameStr);
              return;
          }
      
          // 準備注冊信息
          this->Username = UsernameStr;
          this->Password = PasswordStr;
      
          // 存儲數據文件
          if (!this->SaveToTextFile(FileName))
          {
              UE_LOG(LogTemp, Warning, TEXT("Player-[%s] Register Failed. DataFile Wrong Occured"), *UsernameStr);
              return;
          }
      
          // Register Successfully. Do Something !
          GEngine->AddOnScreenDebugMessage(0, 5.0f, FColor::Red, TEXT("Register Successfully"), false, FVector2D(2.0, 2.0));
      }
      
      bool ULoginWidget::CheckTextFileExists(FString FileName)
      {
          // 獲取文件操作接口
          IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
      	return PlatformFile.FileExists(*FileName);
      }
      
      bool ULoginWidget::SaveToTextFile(FString FileName)
      {
          TArray<FString> SaveArray; // 構造字符串數組 保存需要存儲的數據
          SaveArray.Add(this->Username);
          SaveArray.Add(this->Password);
          if (!FFileHelper::SaveStringArrayToFile(SaveArray, *FileName, FFileHelper::EEncodingOptions::ForceUTF8))
          {
              UE_LOG(LogTemp, Warning, TEXT("Save Text File-[%s] Failed"), *FileName);
              return false;
          }
          return true;
      }
      
      bool ULoginWidget::LoadFromTextFile(FString FileName)
      {
          TArray<FString> SaveArray;
          if (!FFileHelper::LoadFileToStringArray(SaveArray, *FileName))
          {
              UE_LOG(LogTemp, Warning, TEXT("Load Text File-[%s] Failed"), *FileName);
              return false;
          }
          if (SaveArray.Num() < 2)
          {
              UE_LOG(LogTemp, Warning, TEXT("Text File-[%s] Broken"), *FileName);
              return false;
          }
      
          this->Username = SaveArray[0];
          this->Password = SaveArray[1];
          return true;
      }
      

      編寫好源文件后,需要將 LoginUI 空間中的類設置改為繼承 LoginWidget

      修改UI繼承

      重新運行 Login 關卡,用戶名輸入 test,密碼輸入 test,先點擊注冊按鈕,屏幕上會打印出紅色日志,如下圖所示。

      成功注冊

      然后再點擊登錄按鈕。

      成功登錄

      存檔數據在 $UE_INSTALL_DIR/Engine/Binaries/Win64/Player_test.data,其中 $UE_INSTALL_DIR 為 ue4 的安裝路徑,比如在我的電腦上為 C:\Program Files\Epic Games\UE_4.25

      使用記事本或其他軟件打開存檔文件,可以發現數據是分行進行存儲,第一行是用戶名,第二行是密碼,密碼是明文存儲,實際應用中可以再通過單向加密算法等轉為密文存儲。

      以上,成功通過本地文件存儲的方式實現了簡單的登錄注冊功能,讀者可以在此基礎上更進一步擴展開發,比如加入登錄成功的關卡跳轉功能、對用戶或密碼的合法性檢查等,此處不再贅述。

      參考文獻

      1. UE4/CPP C++綁定UMG中的按鈕事件_I_itaiit的博客-CSDN博客
      2. UE4 UMG中C++成員變量綁定藍圖Widget - 知乎
      3. UE4 開發之實現按鈕事件響應 - 騰訊云開發者社區-騰訊云
      4. [UE4]UMG widget構造初始化函數中獲取其內部組件_玄冬Wong的博客-CSDN博客
      5. 虛幻4(Unreal Engine4)中的代理委托Delegate的使用方法 - 知乎
      6. UE4-文件操作 - 知乎
      7. 【UE4 C++】讀寫Text文件 FFileHelper - 砥才人 - 博客園
      8. 【UE4】UE4文件系統_Goulandis的博客-CSDN博客_ue4game是什么文件夾
      9. 淺談UE4序列化系列(1) 結合用例淺談 UE4序列化 - 知乎
      posted on 2023-02-16 16:10  孤舟掠影  閱讀(1435)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 久久精品女人的天堂av| 亚洲日韩亚洲另类激情文学| 国产精品永久在线观看| 精品精品久久宅男的天堂| 濮阳县| 日本高清不卡一区二区三| 亚洲精品麻豆一区二区| 久久99热只有频精品8| 国产女人叫床高潮大片| 中文有无人妻vs无码人妻激烈| 中国大陆高清aⅴ毛片| 亚洲电影天堂av2017| 精品免费看国产一区二区| 亚洲日本欧洲二区精品| 亚洲热视频这里只有精品| 亚洲国产大胸一区二区三区| 另类 专区 欧美 制服| 国产麻豆一区二区精彩视频| 欧美人与性动交α欧美精品| 亚洲青青草视频在线播放| 亚洲国产成人无码av在线影院| 亚洲中文字幕伊人久久无码| 国产精品女人毛片在线看| 午夜天堂精品久久久久| 人妻无码久久精品| 天堂V亚洲国产V第一次| 欧美午夜成人片在线观看 | 日本黄色三级一区二区三区| 中文字幕国产日韩精品| 麻豆精品一区二正一三区| 国产精品视频第一第二区| 亚洲一区二区三区激情在线| 日韩不卡二区三区三区四区| 色狠狠色婷婷丁香五月| 日韩亚洲精品中文字幕| 永久免费在线观看蜜桃视频| 久久先锋男人AV资源网站| 东京热一精品无码av| 久久精品娱乐亚洲领先| 豆国产97在线 | 亚洲| 青青青青国产免费线在线观看|