한 동안 블로그 업데이트를 안했는데 이유는 두가지.

 

1. 참고자료보면서 코드 따라치던거를 제 프로젝트에 이식시켜서 제걸로 만드려고 삽질했습니다

2. 일주일정도 미친듯이 게임만 했습니다.(이제 질림)

 

 

본론으로 돌아가서.

 

세션이 무엇이냐하면.

 

서버를 놀이동산이라 가정했을때. 

세션은 놀이기구를 예로 들을 수 있습니다.

그리고 그 세션에 유저들이 들어가서 노는거죠.

그냥 카드라이더같이 방만들고 플레이하는거라 보면 쉽습니다. 

 

UI 버튼이랑 텍스트입력을 받아올 수 있는 위젯이 있다는 가정하에 씁니다.

 

 

이런상황이 발생했다.

저 IOnlineSubsystem이 헤더파일참조는 되고 빌드는되는데

 

저 안의 내용물들을 가져다 쓸라고하면 일단 빨간줄로 막히고 컴파일에러를 낸다.

 

프로젝트변경->솔루션다시검사. 해도 안된다.

 

먼가해서 구글링했더니 언리얼에서 핫리로드를 쓰다보면 모듈 dll이 쌓여서 예전 설정을 가져다쓴다고한다.

 

이것들 다 지우고 빌드 하랬더니 해결됨.

 

동시에, 내가 쓰던 창설정도 다 날라가서 다시 갖다놔야된다. ^ㅗ^

'언리얼엔진 > 네트워크' 카테고리의 다른 글

세션생성하기  (0) 2019.05.21
서버에서 나오기, 게임종료하기.  (0) 2019.04.15
IP를 입력받아서 로컬에 접속하기.  (0) 2019.04.15
UMG 셋팅하고 적용하기  (0) 2019.04.11
서버 트래블링  (0) 2019.04.10

저번처럼 바인딩할 버튼을 만들고 

인터페이스에 가상함수를 만들고.

 

 

상속받은 인터페이스를 가져오고.

 

 

 

인터페이스 기능을 구현. (핵심)

 

 

 

메뉴에서 인터페이스의 함수를 호출할 함수를 작성 .

그리고 버튼이벤트 바인딩.

 

 

 

 

 

 

 

UMG와 부모위젯헤더파일에 이렇게 바인딩시킨후.

 

클릭했을떄 함수 등록

 

마지막줄의 인터페이스함수를 호출하는 형식으로 동작하는데 구성은 이렇다.

인터페이스 선언 -> 인스턴스에서 다중상속 -> 구현  ->

메인메뉴에서 여기서 구현한 인터페이스를 받아서 호출함. 

 

결과

 

 

 

프로젝트 파일로 가서 source -> 프로젝트이름 폴더 -> 프로젝트이름 .build.cs 라는 c#문서를 열어서 UMG를

추가해준다.

 

에디터에서 마우스오른클 ->유저 인터페이스 -> 위젯 블루프린트를 만들고 대충 저런 모양 나오게 

셋팅한다 (c++보는사람은 블루프린트 이미 알고있을거라 생각하니 사용법은 생략)

 

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

#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "PuzzlePlatformsGameInstance.generated.h"

/**
 * 
 */
UCLASS()
class TEST_API UPuzzlePlatformsGameInstance : public UGameInstance
{
	GENERATED_BODY()
		//c++ 생성자 단에서 초기화 
		UPuzzlePlatformsGameInstance(const FObjectInitializer& ObjectInitializer);
	
public:

	//언리얼 게임인스턴스 단에서 초기화 
	virtual  void Init();

	UFUNCTION(Exec)
		void Host(); //호스트

	UFUNCTION(Exec) //조인 + 접속아이피
		void Join(const FString& Address);

	UFUNCTION(BlueprintCallable)//메뉴불러오는 함수
		void LoadMenu();

private:
	//위젯가져오기
	TSubclassOf<class UUserWidget> MenuClass;
	//메인메뉴 클래스 포인터
	class UMainMenu* Menu;
	
};

위젯을 다룰 인스턴스 소스의헤더파일에 블루프린트에서 사용할수있도록 위와같이 함수선언 +

위젯클래스를 가져올수 있도록 해준다.

 

void UPuzzlePlatformsGameInstance::LoadMenu()
{
	if (!ensure(MenuClass != nullptr)) return;

	UUserWidget* Menu = CreateWidget<UUserWidget>(this, MenuClass);
	if (!ensure(Menu != nullptr)) return;

	Menu->AddToViewport(); //뷰포트에 나타내기
}

그리고 cpp파일에서 이렇게 코딩해준후 

 

레벨블루프린트에서 다음과 같이 스크립트를 짜준다.

 

게임화면이 이같이 뷰포트에 덮어씌워진다.

 

 

위와같이 나오는데. 캐릭터 asdw로 움직이고 회전 그대로되면서 

 

버튼을 누르고싶은데 마우스커서가 안나옴.

 

그러니까 포커스가 위젯에 맞춰져야한다.

 

블루프린트로는 이런거.

 

 

그러니까 다음과같이 코딩.

 

void UPuzzlePlatformsGameInstance::LoadMenu()
{
	if (!ensure(MenuClass != nullptr)) return;

	UUserWidget* Menu = CreateWidget<UUserWidget>(this, MenuClass);
	if (!ensure(Menu != nullptr)) return;

	Menu->AddToViewport(); //뷰포트에 나타내기

	//현제 이용중인 플레이어 컨트롤러를 얻어옴.
	APlayerController* PlayerController = GetFirstLocalPlayerController();
	if (!ensure(PlayerController != nullptr)) return;

	//사용자 입력을 처리해줄 라이브러리
	FInputModeUIOnly InputModeData;
	//사용랗 위젯을 지정
	InputModeData.SetWidgetToFocus(Menu->TakeWidget());
	//마우스를 뷰포트에 고정할건지 자유롭게 놔둘건지 지정
	InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);

	//위에서 구현한사항을 플레이어 컨트롤러에서 지정
	PlayerController->SetInputMode(InputModeData);
	//마우스커서 보이게하기
	PlayerController->bShowMouseCursor = true;
}

이렇게하고 컴파일하면 키보드입력이 안먹고 마우스커서가 나타나서 버튼을 누를 수 있게된다.

 

그러나 아직 버튼을 눌러도 아무 동작을 하지 않는다 

 

당연히 바인딩을 안해줬으니까.

 

 

준비물.

 

 

usetWidget을 부모로한 c++클래스를 

다음과같은 이름으로 생성해준다.

 

 

 

 

 

 

 

 

 

 

저번에 만든 umg에서 

1.그래프탭 선택.

2.클래스세팅

3.부모클래스를 아까 만든 c++클래스로 설정해준다.

헤더파일에 바인딩할 버튼들을 스샷처럼 코딩하는 방식.

 

주의. 이름똑같이 해줄것

 

mainmenu의 헤더파일

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

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"

#include "MainMenu.generated.h"


/**
 * 
 */
UCLASS()
class TEST_API UMainMenu : public UUserWidget
{
	GENERATED_BODY()

public:
	
protected:
	//초기화 + 유무를 검출하기위해 bool반환
	virtual bool Initialize();

	



private:

	//UMG의 버튼과 코드를 바인딩하기위한 버튼선언.

	UPROPERTY(meta = (BindWidget))
		class UButton* Host;

	UPROPERTY(meta = (BindWidget))
		class UButton* Join;

	UFUNCTION() // 호스트가 되는 함수
		void HostServer();

	
};

 

mainmenu의 소스파일.

bool UMainMenu::Initialize()
{
	bool Success = Super::Initialize();
	if (!Success) return false;

	if (!ensure(Host != nullptr)) return false;

	UE_LOG(LogTemp, Warning, TEXT("succecess!!!"));
	//호스트 버튼이 눌렸을때 HostSever 함수가 호출되도록 바인딩.
	Host->OnClicked.AddDynamic(this, &UMainMenu::HostServer);

	return true;
}

void UMainMenu::HostServer()
{
	UE_LOG(LogTemp, Warning, TEXT("I'm gonna host a server!"));

	
}

 

이제 호스트 버튼을 누를때마다 로그가 뜨는것을 확인 할 수있다.

 

 

 

세팅하기

  이렇게 c++기반 게임인스턴스 하나 만들어요

  맨마지막거가 게임인스턴스입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

서드퍼슨맵을 복사해서 로비맵을 생성.

둘이 서로 알아먹기만 할수있게 표시하면됨 

 

 

 

 

 

맵 &모드에서 게임시작하면 맨처음나오는 맵과 서버가 맨처음 나오는맵을 설정

 

  

생성자초기화와 언리얼에서 제공하는                   게임 인스턴스 초기화의 차이.

 

#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "PuzzlePlatformsGameInstance.generated.h"

/**
 * 
 */
UCLASS()
class TEST_API UPuzzlePlatformsGameInstance : public UGameInstance
{
	GENERATED_BODY()
		//c++ 생성자 단에서 초기화 
		UPuzzlePlatformsGameInstance(const FObjectInitializer& ObjectInitializer);

	//언리얼 게임인스턴스 단에서 초기화 
	virtual  void Init();

	UFUNCTION(Exec)
		void Host(); //호스트

	UFUNCTION(Exec) //조인 + 접속아이피
		void Join(const FString& Address);

	
};

 

 

 

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

#include "PuzzlePlatformsGameInstance.h"

#include "Engine/Engine.h"

UPuzzlePlatformsGameInstance::UPuzzlePlatformsGameInstance(const FObjectInitializer & ObjectInitializer)
{
	UE_LOG(LogTemp, Warning, TEXT("GameInstance Constructor"));//생성자 초가화
}

void UPuzzlePlatformsGameInstance::Init()
{
	UE_LOG(LogTemp, Warning, TEXT("GameInstance Init")); //인스턴스 초기화
}

void UPuzzlePlatformsGameInstance::Host()
{
	UEngine* Engine = GetEngine(); //게임엔진의 현재 인스턴스를 가져움

	if (!ensure(Engine != nullptr)) return;

	Engine->AddOnScreenDebugMessage(0, 2, FColor::Green, TEXT("Hosting")); //로그띄워줌

	UWorld* World = GetWorld(); // 레벨의 현재 레벨을 가져옴

	if (!ensure(World != nullptr)) return;
	//서버전용 .  서버를 입력한 경로의 맵으로 이동시킴, 클라이언트랑 같이감 서버가 접속중인 클라이언트들의
	//플레이어 컨트롤러에서 ClientTravel을 호출함.
	World->ServerTravel("/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap?listen");
}

void UPuzzlePlatformsGameInstance::Join(const FString& Address)
{
	UEngine* Engine = GetEngine();

	//현재 클라의 플레이어컨트롤러의 첫번째 플레이어 컨트롤러 가져옴
	APlayerController* PlayerController = GetFirstLocalPlayerController();

	if (!ensure(Engine != nullptr)) return;
	//로그
	Engine->AddOnScreenDebugMessage(0, 5, FColor::Green, FString::Printf(TEXT("Joining %s"), *Address));

	//아이피가 유효할때 호출되면 입력된 아이피주소의 서버로 이동함.  
	//인텔리센스 빨간줄 무시하셈.
	PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute);

	
}

 

결과.

 

 

 

https://www.udemy.com/share/100YVuA0sbd1tXRng=/

 

이거보고 공부했읍니다.

가격도 매우 저렴합니다 언리얼 블로그에서 링크통해가면 더 할인도 되요(영어주의)

 

 

 

리플리케이트로 움직이는 액터의 

 

 

헤더파일

 

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

#pragma once

#include "CoreMinimal.h"
#include "Engine/StaticMeshActor.h"
#include "MovingPlatform.generated.h"

/**
 * 
 */
UCLASS()
class TEST_API AMovingPlatform : public AStaticMeshActor
{
	GENERATED_BODY()

public:
	AMovingPlatform();
	
	virtual void Tick(float DeltaTime) override;

	virtual void BeginPlay() override;

	UPROPERTY(EditAnywhere)//블프나 에디터상에서 모두 편집가능
		float Speed = 20;

	UPROPERTY(EditAnywhere, Meta = (MakeEditWidget = true))//에디터상 위젯에 나타냄
		FVector TargetLocation;

	void AddActiveTrigger(); //이동
	void RemoveActiveTrigger(); //해제

private:
	FVector GlobalTargetLocation;
	FVector GlobalStartLocation;

	UPROPERTY(EditAnywhere)
		int ActiveTriggers = 0; //트리거 발동조건
};

 

구현부

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

#include "MovingPlatform.h"

//움직이는 스태틱메쉬
AMovingPlatform::AMovingPlatform() {
	//틱 이벤트 사용
	PrimaryActorTick.bCanEverTick = true;

	//이물체가 이동성을 가지는지 설정 Enum형
	SetMobility(EComponentMobility::Movable);

}

void AMovingPlatform::BeginPlay()
{
	Super::BeginPlay();

	if (HasAuthority()) {
		//서버와 클라이언트를 동기화
		SetReplicates(true);
		SetReplicateMovement(true);
	}
	GlobalStartLocation = GetActorLocation();
	GlobalTargetLocation = GetTransform().TransformPosition(TargetLocation);
}

void  AMovingPlatform::Tick(float DeltaTime) {
	//부모로부터 가상함수를 재정의 하고있는지 확인
	Super::Tick(DeltaTime);

	if(ActiveTriggers >0 ) //트리거 발동되었을때.

	//참이면 서버, 거짓이면 단일 클라이언트일때를 분기
	if (HasAuthority()){
		//현재액터의 위치 변수저장하기
		FVector location = GetActorLocation();
	//틱마다 x축으로 델타시간*스피드 만큼 이동

	float JourneyLength = (GlobalTargetLocation - GlobalStartLocation).Size(); //목표지점과 첫지점의 거리
	float JourneyTravelled = (location - GlobalStartLocation).Size(); //현재내지점과 목표지점의 거리 

	if (JourneyTravelled >= JourneyLength) //목표지점 첫지점을 바꿈 
	{
		FVector Swap = GlobalStartLocation;
		GlobalStartLocation = GlobalTargetLocation;
		GlobalTargetLocation = Swap;
	}

	//방향벡터구하기
	FVector Direction = (GlobalTargetLocation - GlobalStartLocation).GetSafeNormal();
	//이동
	location += Speed * DeltaTime * Direction;
	SetActorLocation(location);
	
	
	
}
	
}

void AMovingPlatform::AddActiveTrigger()
{
	ActiveTriggers++;
}

void AMovingPlatform::RemoveActiveTrigger()
{
	if (ActiveTriggers > 0) {
		ActiveTriggers--;
	}
}

 

 

버튼이눌렸을때 액터가 움직이도록  하는 액터의 헤더파일 

 

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "PlatformTrigger.generated.h"

UCLASS()
class TEST_API APlatformTrigger : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	APlatformTrigger();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

private:
	UPROPERTY(VisibleAnywhere)
		class UBoxComponent* TriggerVolume;


	UFUNCTION() // 겹쳤을때 함수
		void OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION() // 나왔을대 함수
		void OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

	UPROPERTY(EditAnywhere) //트리거가 발동되었을때 움직이는 플랫폼의 배열 
		TArray<class AMovingPlatform*> PlatformsToTrigger;

};

 

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

#include "PlatformTrigger.h"
#include "Components/BoxComponent.h"
#include "MovingPlatform.h"

// Sets default values
APlatformTrigger::APlatformTrigger()
{
 	// 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;

	TriggerVolume = CreateDefaultSubobject<UBoxComponent>(FName("TriggerVolume"));
	if(!ensure(TriggerVolume != nullptr)) return;
		RootComponent = TriggerVolume;

		TriggerVolume->OnComponentBeginOverlap.AddDynamic(this, &APlatformTrigger::OnOverlapBegin);
		TriggerVolume->OnComponentEndOverlap.AddDynamic(this, &APlatformTrigger::OnOverlapEnd);
}

// Called when the game starts or when spawned
void APlatformTrigger::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void APlatformTrigger::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

void APlatformTrigger::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	UE_LOG(LogTemp, Warning, TEXT("Activated"));

	for (AMovingPlatform* Platform : PlatformsToTrigger) //배열에있는 트리거들 모두순회
	{//이동트리거발동
		Platform->AddActiveTrigger();
	}

}

void APlatformTrigger::OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	UE_LOG(LogTemp, Warning, TEXT("Deactivated"));

	
	for (AMovingPlatform* Platform : PlatformsToTrigger)
	{//이동트리거제거
		Platform->RemoveActiveTrigger();
	}
}

 

 

+ Recent posts