这节课创建了新的游戏关卡Lobby,制作了属于自己的游戏名字"Match Type",制作了加入游戏会话的委托和函数,最后可以用IP就可以把客户端链接到服务端
.h
// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "Logging/LogMacros.h" #include "OnlineSubsystem.h" #include "Interfaces/OnlineSessionInterface.h" #include "MenuCharacter.generated.h" class USpringArmComponent; class UCameraComponent; class UInputMappingContext; class UInputAction; struct FInputActionValue; DECLARE_LOG_CATEGORY_EXTERN(LogTemplateCharacter, Log, All); UCLASS(config=Game) class AMenuCharacter : public ACharacter { GENERATED_BODY() /** Camera boom positioning the camera behind the character */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) USpringArmComponent* CameraBoom; /** Follow camera */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) UCameraComponent* FollowCamera; /** MappingContext */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) UInputMappingContext* DefaultMappingContext; /** Jump Input Action */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) UInputAction* JumpAction; /** Move Input Action */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) UInputAction* MoveAction; /** Look Input Action */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = Input, meta = (AllowPrivateAccess = "true")) UInputAction* LookAction; public: AMenuCharacter(); protected: /** Called for movement input */ void Move(const FInputActionValue& Value); /** Called for looking input */ void Look(const FInputActionValue& Value); protected: // APawn interface virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; // To add mapping context virtual void BeginPlay(); public: /** Returns CameraBoom subobject **/ FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; } /** Returns FollowCamera subobject **/ FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; } public: //Pointer to the online session interface void _MyDebugLog(int32 Key, float TimeToDisplay, FColor DisplayColor, const FString& DebugMessage); IOnlineSessionPtr OnlineSessionInterface; protected: //创建会话 UFUNCTION(BlueprintCallable,Category="My") void CreateGameSession(); //创建会话成功 void OnCreateSessionComplete(FName SessionName, bool bWasSuccess); //加入会话 UFUNCTION(BlueprintCallable,Category="My") void JoinSession(); //查找会话成功 void FindSessionComplete(bool bWasSuccess); // void JoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result); private: //创建会话的委托 FOnCreateSessionCompleteDelegate OnCreateSessionCompleteDelegate; //查找会话的委托 FOnFindSessionsCompleteDelegate OnFindSessionsCompleteDelegate; //查找会话设置 TSharedPtr<FOnlineSessionSearch> SessionSearch; //加入会话 FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate; };
.cpp
// Copyright Epic Games, Inc. All Rights Reserved. #include "MenuCharacter.h" #include "Engine/LocalPlayer.h" #include "Camera/CameraComponent.h" #include "Components/CapsuleComponent.h" #include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/SpringArmComponent.h" #include "GameFramework/Controller.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" #include "OnlineSessionSettings.h" #include "InputActionValue.h" #include "Online/OnlineSessionNames.h" DEFINE_LOG_CATEGORY(LogTemplateCharacter); // // AMenuCharacter AMenuCharacter::AMenuCharacter(): OnCreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this,&ThisClass::OnCreateSessionComplete)), OnFindSessionsCompleteDelegate(FOnFindSessionsCompleteDelegate::CreateUObject(this,&ThisClass::FindSessionComplete)), OnJoinSessionCompleteDelegate(FOnJoinSessionCompleteDelegate::CreateUObject(this,&ThisClass::JoinSessionComplete)) { // Set size for collision capsule GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f); // Don't rotate when the controller rotates. Let that just affect the camera. bUseControllerRotationPitch = false; bUseControllerRotationYaw = false; bUseControllerRotationRoll = false; // Configure character movement GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input... GetCharacterMovement()->RotationRate = FRotator(0.0f, 500.0f, 0.0f); // ...at this rotation rate // Note: For faster iteration times these variables, and many more, can be tweaked in the Character Blueprint // instead of recompiling to adjust them GetCharacterMovement()->JumpZVelocity = 700.f; GetCharacterMovement()->AirControl = 0.35f; GetCharacterMovement()->MaxWalkSpeed = 500.f; GetCharacterMovement()->MinAnalogWalkSpeed = 20.f; GetCharacterMovement()->BrakingDecelerationWalking = 2000.f; GetCharacterMovement()->BrakingDecelerationFalling = 1500.0f; // Create a camera boom (pulls in towards the player if there is a collision) CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom")); CameraBoom->SetupAttachment(RootComponent); CameraBoom->TargetArmLength = 400.0f; // The camera follows at this distance behind the character CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller // Create a follow camera FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera")); FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) // are set in the derived blueprint asset named ThirdPersonCharacter (to avoid direct content references in C++) //添加访问Steam会话系统 IOnlineSubsystem* OnlineSubsystem = IOnlineSubsystem::Get(); if(OnlineSubsystem) { //获得当前会话的指针 OnlineSessionInterface = OnlineSubsystem->GetSessionInterface(); _MyDebugLog(-1,15.f,FColor::Blue,FString::Printf(TEXT("Now Subsystem %s"),*OnlineSubsystem->GetSubsystemName().ToString())); } } void AMenuCharacter::_MyDebugLog(int32 Key, float TimeToDisplay, FColor DisplayColor, const FString& DebugMessage) { if(GEngine) { GEngine->AddOnScreenDebugMessage(Key,TimeToDisplay,DisplayColor,DebugMessage); } } void AMenuCharacter::CreateGameSession() { //Called when pressing the 1 key //检测IOnlineSessionPtr是否有效 if(!OnlineSessionInterface.IsValid()) { return; } //获得当前会话名字并且放在变量内 auto ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession); //当存在会话的时候,删除会话 if(ExistingSession!=nullptr) { OnlineSessionInterface->DestroySession(NAME_GameSession); } OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(OnCreateSessionCompleteDelegate); //创建智能指针会话设置 TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings()); //非局域网 SessionSettings->bIsLANMatch = false; //最多4人 SessionSettings->NumPublicConnections =4; //允许其他玩家加入 SessionSettings->bAllowJoinInProgress = true; //允许好友加入 SessionSettings->bAllowJoinViaPresence = true; //线上公开 SessionSettings->bShouldAdvertise = true; //显示用户状态 SessionSettings->bUsesPresence = true; //使用第三方 SessionSettings->bUseLobbiesIfAvailable = true; //设置会话搜索设置,Name是"MatchType",值是"FreeForAll" SessionSettings->Set(FName("MatchType"),FString("FreeForAll"),EOnlineDataAdvertisementType::ViaOnlineServiceAndPing); const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession , *SessionSettings); } void AMenuCharacter::OnCreateSessionComplete(FName SessionName, bool bWasSuccess) { if(bWasSuccess) { _MyDebugLog(-1,15.f,FColor::Blue,FString::Printf(TEXT("Create Session Success : %s"), *SessionName.ToString())); UWorld* World = GetWorld(); if(World) { World->ServerTravel("/Game/ThirdPerson/Maps/Lobby?listen"); } } else { _MyDebugLog(-1,15.f,FColor::Red,FString(TEXT("Faild to Create Session"))); } return; } void AMenuCharacter::JoinSession() { /*找到会话*/ if(!OnlineSessionInterface.IsValid()) { return; } //添加查询委托 OnlineSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(OnFindSessionsCompleteDelegate); //设置查找 SessionSearch = MakeShareable(new FOnlineSessionSearch()); SessionSearch->MaxSearchResults = 10000; SessionSearch->bIsLanQuery=false; //设置查询设置 SessionSearch->QuerySettings.Set(SEARCH_PRESENCE,true,EOnlineComparisonOp::Equals); //获得本地的第一个玩家 const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); //使用本地的第一个玩家的URL和查找设置进行查找 OnlineSessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(),SessionSearch.ToSharedRef()); } void AMenuCharacter::FindSessionComplete(bool bWasSuccess) { if(!OnlineSessionInterface.IsValid()) { return; } for(auto Result : SessionSearch->SearchResults) { FString Id = Result.GetSessionIdStr(); FString User = Result.Session.OwningUserName; FString MatchType; //找到所有Key是"MatchType"类型的房间 Result.Session.SessionSettings.Get("MatchType",MatchType); _MyDebugLog(-1,15.f,FColor::Cyan,FString::Printf(TEXT("Id : %s , Name : %s"),*Id,*User)); if(MatchType == "FreeForAll") { _MyDebugLog(-1,15.f,FColor::Cyan,FString::Printf(TEXT("Join Match Type : %s"),*MatchType)); //绑定加入委托 OnlineSessionInterface->AddOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegate); const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); //调用JoinSession,并且加入的时候调用OnJoinSessionCompleteDelegate这个委托 OnlineSessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(),NAME_GameSession,Result); } } } void AMenuCharacter::JoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result) { if(!OnlineSessionInterface.IsValid()) { return; } FString Address; // if(OnlineSessionInterface->GetResolvedConnectString(NAME_GameSession,Address)) { _MyDebugLog(-1,15.f,FColor::Yellow,FString::Printf(TEXT("Connect String : %s"),*Address)); APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController(); if(PlayerController) { PlayerController->ClientTravel(Address,ETravelType::TRAVEL_Absolute); } } } void AMenuCharacter::BeginPlay() { // Call the base class Super::BeginPlay(); //Add Input Mapping Context if (APlayerController* PlayerController = Cast<APlayerController>(Controller)) { if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) { Subsystem->AddMappingContext(DefaultMappingContext, 0); } } } // // Input void AMenuCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { // Set up action bindings if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent)) { // Jumping EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump); EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping); // Moving EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMenuCharacter::Move); // Looking EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AMenuCharacter::Look); } else { UE_LOG(LogTemplateCharacter, Error, TEXT("'%s' Failed to find an Enhanced Input component! This template is built to use the Enhanced Input system. If you intend to use the legacy system, then you will need to update this C++ file."), *GetNameSafe(this)); } } void AMenuCharacter::Move(const FInputActionValue& Value) { // input is a Vector2D FVector2D MovementVector = Value.Get<FVector2D>(); if (Controller != nullptr) { // find out which way is forward const FRotator Rotation = Controller->GetControlRotation(); const FRotator YawRotation(0, Rotation.Yaw, 0); // get forward vector const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); // get right vector const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); // add movement AddMovementInput(ForwardDirection, MovementVector.Y); AddMovementInput(RightDirection, MovementVector.X); } } void AMenuCharacter::Look(const FInputActionValue& Value) { // input is a Vector2D FVector2D LookAxisVector = Value.Get<FVector2D>(); if (Controller != nullptr) { // add yaw and pitch input to controller AddControllerYawInput(LookAxisVector.X); AddControllerPitchInput(LookAxisVector.Y); } }
因为一个Steam只能同时链接一个Address,所以我没有测试成功.第一个链接上了Steam,第二个就会出现链接Null