マルチプレイヤーゲームでは、以下の要素が重要です:
// MyFPSCharacter.h #pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "MyFPSCharacter.generated.h" UCLASS() class MYFPSGAME_API AMyFPSCharacter : public ACharacter { GENERATED_BODY() public: AMyFPSCharacter(); // 体力システム UPROPERTY(Replicated, BlueprintReadWrite, Category = "Character") float Health; // 現在の武器 UPROPERTY(ReplicatedUsing = OnRep_CurrentWeapon) class AWeapon* CurrentWeapon; // 武器変更通知 UFUNCTION() void OnRep_CurrentWeapon(); // 発射処理(サーバー) UFUNCTION(Server, Reliable) void ServerFire(); // 発射エフェクト(全クライアント) UFUNCTION(NetMulticast, Reliable) void MulticastOnFire(); protected: virtual void BeginPlay() override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; }; // MyFPSCharacter.cpp #include "MyFPSCharacter.h" #include "Net/UnrealNetwork.h" #include "Engine/Engine.h" AMyFPSCharacter::AMyFPSCharacter() { PrimaryActorTick.bCanEverTick = true; // ネットワーク機能を有効化 bReplicates = true; // デフォルト値の設定 Health = 100.0f; } void AMyFPSCharacter::GetLifetimeReplicatedProps(TArray & OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 変数のレプリケーション設定 DOREPLIFETIME(AMyFPSCharacter, Health); DOREPLIFETIME(AMyFPSCharacter, CurrentWeapon); } void AMyFPSCharacter::OnRep_CurrentWeapon() { // 武器が変更された時の処理 if (CurrentWeapon) { // 武器の表示更新など } } void AMyFPSCharacter::ServerFire_Implementation() { // サーバーでの発射処理 if (HasAuthority()) { // ヒット判定 FHitResult HitResult; FVector Start = GetActorLocation(); FVector End = Start + GetActorForwardVector() * 1000.0f; if (GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility)) { // ヒット時の処理 if (AActor* HitActor = HitResult.GetActor()) { // ダメージ適用 FDamageEvent DamageEvent; HitActor->TakeDamage(20.0f, DamageEvent, GetController(), this); } } // 発射エフェクトを全クライアントに通知 MulticastOnFire(); } } void AMyFPSCharacter::MulticastOnFire_Implementation() { // 発射エフェクトの再生 // サウンド、パーティクル、アニメーションなど }
// ブループリントでの設定手順 1. プレイヤーキャラクターBPを作成 - Content Browser → 右クリック → Blueprint Class → Character 2. 変数の設定 - Variables タブで新しい変数を追加 - Replication セクションで「Replicated」を選択 3. 関数の設定 - Functions タブで新しい関数を追加 - Details パネルで: - Replicates: True - Run on Server/Client を選択
// Weapon.h #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Weapon.generated.h" UCLASS() class MYFPSGAME_API AWeapon : public AActor { GENERATED_BODY() public: AWeapon(); // 武器の基本情報 UPROPERTY(Replicated, BlueprintReadWrite, Category = "Weapon") int32 Ammo; UPROPERTY(Replicated, BlueprintReadWrite, Category = "Weapon") float Damage; // 発射処理 UFUNCTION(Server, Reliable) void ServerFire(); // リロード処理 UFUNCTION(Server, Reliable) void ServerReload(); // エフェクト UFUNCTION(NetMulticast, Reliable) void MulticastPlayFireEffect(); protected: virtual void BeginPlay() override; virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; // コンポーネント UPROPERTY(VisibleAnywhere) USkeletalMeshComponent* WeaponMesh; }; // Weapon.cpp #include "Weapon.h" #include "Net/UnrealNetwork.h" AWeapon::AWeapon() { PrimaryActorTick.bCanEverTick = true; bReplicates = true; // メッシュコンポーネントの設定 WeaponMesh = CreateDefaultSubobject (TEXT("WeaponMesh")); RootComponent = WeaponMesh; // デフォルト値 Ammo = 30; Damage = 20.0f; } void AWeapon::GetLifetimeReplicatedProps(TArray & OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(AWeapon, Ammo); DOREPLIFETIME(AWeapon, Damage); } void AWeapon::ServerFire_Implementation() { if (HasAuthority() && Ammo > 0) { Ammo--; // ヒット判定とダメージ処理 // ... // エフェクト再生 MulticastPlayFireEffect(); } } void AWeapon::ServerReload_Implementation() { if (HasAuthority()) { Ammo = 30; // リロード } } void AWeapon::MulticastPlayFireEffect_Implementation() { // 発射エフェクトの再生 // パーティクル、サウンドなど }
// MyFPSGameMode.h #pragma once #include "CoreMinimal.h" #include "GameFramework/GameModeBase.h" #include "MyFPSGameMode.generated.h" UCLASS() class MYFPSGAME_API AMyFPSGameMode : public AGameModeBase { GENERATED_BODY() public: AMyFPSGameMode(); virtual void PostLogin(APlayerController* NewPlayer) override; virtual void Logout(AController* Exiting) override; // マッチ管理 UFUNCTION(BlueprintCallable, Category = "Game") void StartMatch(); UFUNCTION(BlueprintCallable, Category = "Game") void EndMatch(); protected: virtual void BeginPlay() override; private: void HandleMatchStart(); void HandleMatchEnd(); }; // MyFPSGameMode.cpp #include "MyFPSGameMode.h" #include "GameFramework/PlayerController.h" #include "MyFPSCharacter.h" AMyFPSGameMode::AMyFPSGameMode() { // デフォルトのプレイヤ DefaultPawnClass = AMyFPSCharacter::StaticClass(); } void AMyFPSGameMode::PostLogin(APlayerController* NewPlayer) { Super::PostLogin(NewPlayer); if (NewPlayer) { // プレイヤーのスポーン位置を設定 if (AActor* StartSpot = FindPlayerStart(NewPlayer)) { FRotator StartRotation(0.0f, 0.0f, 0.0f); if (APawn* NewPawn = GetWorld()->SpawnActor(DefaultPawnClass, StartSpot->GetActorLocation(), StartRotation)) { NewPlayer->Possess(NewPawn); } } } } void AMyFPSGameMode::Logout(AController* Exiting) { Super::Logout(Exiting); // プレイヤー退出時の処理 if (Exiting) { if (APawn* ExitingPawn = Exiting->GetPawn()) { ExitingPawn->Destroy(); } } } void AMyFPSGameMode::StartMatch() { if (HasAuthority()) { HandleMatchStart(); } } void AMyFPSGameMode::EndMatch() { if (HasAuthority()) { HandleMatchEnd(); } } void AMyFPSGameMode::HandleMatchStart() { // マッチ開始時の処理 // プレイヤーのリスポーン // スコアのリセット等 } void AMyFPSGameMode::HandleMatchEnd() { // マッチ終了時の処理 // 結果の表示 // 次のマッチの準備等 }
// ゲームインスタンスの設定 // MyGameInstance.h UCLASS() class MYFPSGAME_API UMyGameInstance : public UGameInstance { GENERATED_BODY() public: // セッション作成 UFUNCTION(BlueprintCallable, Category = "Network") void CreateGameSession(); // セッション参加 UFUNCTION(BlueprintCallable, Category = "Network") void JoinGameSession(); protected: virtual void Init() override; private: void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful); void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result); }; // MyGameInstance.cpp void UMyGameInstance::CreateGameSession() { auto Sessions = IOnlineSubsystem::Get()->GetSessionInterface(); if (Sessions.IsValid()) { FOnlineSessionSettings SessionSettings; SessionSettings.bIsLANMatch = true; SessionSettings.NumPublicConnections = 4; SessionSettings.bShouldAdvertise = true; SessionSettings.bUsesPresence = true; Sessions->CreateSession(0, NAME_GameSession, SessionSettings); } } void UMyGameInstance::JoinGameSession() { auto Sessions = IOnlineSubsystem::Get()->GetSessionInterface(); if (Sessions.IsValid()) { Sessions->FindSessions(0, SessionSearch); } }
// エディタ設定 Number of Players: 2 Net Mode: Play As Listen Server // デバッグコマンド stat net // ネットワーク統計 ShowDebug net // デバッグ情報表示 net PktLag=100 // 遅延シミュレーション
// コマンドライン引数 -game -server // サーバーとして起動 -game // クライアントとして起動
// プレイヤーキャラクターの最適化例 void AMyFPSCharacter::Tick(float DeltaTime) { Super::Tick(DeltaTime); // クライアントサイド予測 if (IsLocallyControlled()) { PredictMovement(DeltaTime); } } void AMyFPSCharacter::PredictMovement(float DeltaTime) { // 移動予測の実装 FVector PredictedLocation = GetActorLocation() + GetVelocity() * DeltaTime; // 補間処理など }