https://mingyu0403.tistory.com/259#google_vignette

 

[Unreal C++] 데이터 테이블 만들고, 사용하기 (CSV 파일)

참고 자료 '이득우의 언리얼 C++ 게임 개발의 정석' Chapter 11 & wergia.tistory.com/154 데이터 테이블을 사용하는 이유 게임 데이터를 파일로 따로 관리하면 체계적으로 관리할 수 있고, 더 편하게 사용

mingyu0403.tistory.com

https://www.youtube.com/watch?v=zuJ2tjZW770 

 

#include "HamsterGameInstance.h"

UHamsterGameInstance::UHamsterGameInstance()
{
	FString DialogueDataPath = TEXT("/Game/FirstPerson/Data/HamsterDialogueSample.HamsterDialogueSample");
	static ConstructorHelpers::FObjectFinder<UDataTable> DT_HamDialogue(*DialogueDataPath);
	if (DT_HamDialogue.Succeeded())
	{
		UE_LOG(LogTemp, Log, TEXT("Dialogue TableData succeeded"));
	}
	else
	{
		UE_LOG(LogTemp, Log, TEXT("Dialogue TableData not succeeded"));
	}

	HamsterDialogueTable = DT_HamDialogue.Object; //이건 뭘까 아직 모르겠음



}

FHamsterDialogueData *UHamsterGameInstance::GetDialogueData(FString Name)
{
	return HamsterDialogueTable->FindRow<FHamsterDialogueData>(FName(Name), FString(""));
}

 

GetDialogueData를 TalkableObject에서 가져다가 쓰면 될 것 같은데, 어떻게 써야할지 감이 안 온다...

 

엑셀 데이터를 통해 대화 내용과 이름을 가져오는 작업을 진행 중이다

 

아래는 이전에 책을 보고 진행한 예제의 코드

#pragma once

#include "ArenaBattle.h"
#include "Engine/DataTable.h"
#include "Engine/GameInstance.h"
#include "Engine/StreamableManager.h"
#include "ABGameInstance.generated.h"

USTRUCT(BlueprintType)
struct FABCharacterData : public FTableRowBase
{
	GENERATED_BODY()

public:
	FABCharacterData() : Level(1), MaxHP(100.0f), Attack(10.0f), DropExp(10), NextExp(30) {}

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		int32 Level;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		float MaxHP;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		float Attack;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		int32 DropExp;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		int32 NextExp;
};

캐릭터 데이터를 받아오기 위한 구조를 선언했다

 

이와 동일하게, GameInstance를 상속받는 HamsterGameInstance를 만들고,

그 안에 DataTable 구조체를 만들기로 했다

(GameInstance는 게임 시작부터 종료까지 유지되어 데이터를 관리하는 데 유용함)

 

https://secretroute.tistory.com/entry/1409221002

https://kyoun.tistory.com/183

USTRUCT(BlueprintType)
struct FHamsterGameData : public FTableRowBase
{
	GENERATED_BODY()

public:
	FHamsterGameData() : Name("StartName"), Line("StartLine"), CanTalkMore(true) {}

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		FString Name;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		FString Line;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Data")
		bool CanTalkMore;

};

 

엑셀 파일을 csv로 변환해서 임포트 해주면 된다

CanTalkMore를 bool 로 선언해도 엑셀 내에서는 텍스트라서 제대로 인식될지 잠깐 걱정했는데, 다행히 제대로 인식된다!

 

'[햄] 작업일기' 카테고리의 다른 글

230725 DataTable을 출력하기  (0) 2023.07.25
230721  (0) 2023.07.21
230717 대화 진행, EndInteract 키 변경  (0) 2023.07.17
230714 상호작용 중임을 판단하기  (0) 2023.07.14
230711  (0) 2023.07.11

상호작용 가능함을 안내하는 InteractableText

IsVisible 혹은 AddToViewport 에서 계속 크래시가 남 (IsVisible의 문제로 추측중)

https://forums.unrealengine.com/t/userwidget-addtoviewport-always-crash/459036

 

UserWidget AddToViewport always crash

Hi. I’m making a simple game in C++. I’m trying to display a widget when the player’s health reaches 0. But it always crashes in the AddToVierport part. Can someone help me? When I checked whether the widget works with less player’s health, it work

forums.unrealengine.com

https://forums.unrealengine.com/t/custom-uuserwidget-have-lifespan/459168/2

 

Custom UUserWidget have LifeSpan?

No there no life span, but if you detached it it can be deleted, if you want to hide something you should collapse it (SetVisibility mode), also if you wont use UPROPERTY() on UMG widget pointers it may be thrown away by garbage collection. If you composin

forums.unrealengine.com

UPROPERTY 를 추가하지 않았기 때문이라는 글이 있다

 

https://minusi.tistory.com/entry/%EC%96%B8%EB%A6%AC%EC%96%BC-UPROPERTY-Unreal-UPROPERTY

 

언리얼 UPROPERTY( Unreal UPROPERTY )

언리얼 엔진 위에서 언리얼 엔진과 상호작용하려는 코드를 작성하기 위해서는 언리얼에서 제공하는 각종 매크로의 도움을 받을 수 밖에 없습니다. 그 중, UPROPERTY는 멤버 변수( 또는 프로퍼티 )

minusi.tistory.com

UPROPERTY 설명글

일단 임시 땜빵 했으니 IsVisible은 다음에 마저 해결하기로

 


 

TalkableObject에 상호작용 했을 때 (대화) 뜨는 TalkPopup 의 이름과 대사 텍스트를 변경할 수 있도록 조치함

TextLine = Cast<UTextBlock>(TalkPopup->GetWidgetFromName(TEXT("Line")));
	TextName = Cast<UTextBlock>(TalkPopup->GetWidgetFromName(TEXT("Name")));

	TextLine->SetText(FText::FromString("test line"));
	TextName->SetText(FText::FromString("test name"));

 

키를 더 눌러 진행했을 때 대사가 바뀌도록 해야 한다

일단 이 정도로...

(밑에 추가함)


 

상호작용을 종료하는 (대화 끝, 물건 내려놓기) 버튼이 tab으로 바인딩 되어 있는데,

E키 (상호작용 버튼)을 다시 눌렀을 때 작동하도록 해야 함

 

Interact() 에서 버튼이 다시 눌렸을 때

Interact() 내에서 IsInteracting= true 이면 (상호작용 중이면)

EndInteract() 가 작동하게 하려고 했는데,

생각해보니 IsInteracting= true 이면 다시 상호작용이 불가하게 처리해두어서 Interact() 내부로 아예 들어오지 않는다

우짜면좋나...

 

void AHamsterDemoCharacter::OnInteract()
{
	if (isSuccessInteract)
	{
		UE_LOG(LogTemp, Log, TEXT("E pressed"));

		if (InteractableObj != nullptr)
		{
			UE_LOG(LogTemp, Log, TEXT("interactable obj not null"));
			
			auto Movable = Cast<AMovableObject>(InteractableObj);
			if (Movable != nullptr) //interactable 중 movable 인지 확인
			{
				Movable->SetHandle(characterPhysicsHandle);
				Movable->SetHandleLocation(characterGrabLocation);
			}

			lockMoveForInteract = !InteractableObj->CanMove();
			InteractableObj->Interact();
		}
		
	}
	else
	{
		OnEndInteract();
	}

E키를 눌렀을 때 추가 인터랙트가 불가하면 (=상호작용 중이면)

EndInteract()가 발동하도록 함

 


TalkableObejct에서,

E를 눌러 대화 시작 후 E를 누르면 대화가 진행되도록 함

 

CanTalkMore가 true이면 Interact()가 실행될 수 있도록 하고,

CanTalkMore가 false이면 EndInteract()가 실행되도록 했다

이후 EndInteract()에서 CanTalkeMore를 다시 true로 바꿔서 대화 종료 후 다시 대화를 걸 수 있도록 했다.

bool ATalkableObject::IsInteractable()
{
	
	
	return CanTalkMore == true;

	//이야기 남았으면 true, 끝나면 false
	//이야기 남았으면 Interact() 다시 해서 이야기 진행
	//이야기 끝났으면 false해서 EndInteract()로 가게
}

void ATalkableObject::Interact()
{
	Super::Interact();

	if (!TalkPopup->IsVisible()) //뷰포트에 없으면 위젯 띄우기
	{
		UE_LOG(LogTemp, Log, TEXT("talkable interact"));
		TalkPopup->AddToViewport();
		TextName->SetText(FText::FromString("test name2"));
		TextLine->SetText(FText::FromString("test line2"));
		CanTalkMore = true;

	}
	else
	{
		TextName->SetText(FText::FromString("test name3"));
		TextLine->SetText(FText::FromString("test line3"));
		CanTalkMore = false;
	}
	
}

void ATalkableObject::EndInteract()
{
	Super::EndInteract();

	if (TalkPopup->IsVisible())
	{
		UE_LOG(LogTemp, Log, TEXT("talkable end interact - close talkpopup"));
		TalkPopup->RemoveFromParent();
	}
    
	CanTalkMore = true;

}

 

이름 나중에 CanProgressTalk 정도로 바꿔야겠음

 

대화 추가 진행 여부를 대화 데이터가 더 있는지로 판단하도록 해야함.

 

'[햄] 작업일기' 카테고리의 다른 글

230721  (0) 2023.07.21
0718 대화 내용을 엑셀 데이터로 불러오기  (0) 2023.07.18
230714 상호작용 중임을 판단하기  (0) 2023.07.14
230711  (0) 2023.07.11
230706  (0) 2023.07.07

상호작용 중일때는 상호작용 가능 텍스트(Press E to Interact)가 뜨지 않도록 처리하려면

상호작용 중일 때에는 isSucessInteract 를 false로 뱉도록 하려고 했는데

 

 

Interact() 에 isSuccessInteract를 넣어줘서 이 때는 false로,

EndInteract()에서는 true로 뱉도록 하려고 했는데

 

생각해보니 character.cpp의 tick에서 항상 상호작용 가능 여부를 체크하고 있기 때문에 이렇게 처리해주면 한 번 false로 변경되었어도 금방 다시 true로 갱신되는 것 같다.

 

 

실제로 해결한 방법)
상호작용 가능 여부를 체크하는 과정에서 쓰이는 InteractableObj의 bool IsInteractable() 에서 (해당 함수가 true를 반환하면 상호작용 가능, 반대는 불가능. )

해당 물체가 상호작용 중임을 나타내는 bool IsInteracting를 사용한다

IsInteracting은 디폴트로 false로 되어 있고, E키를 눌러 Interact() 함수가 작동하게 되면 IsInteracting이 true로 바뀐다.

IsInteractable 에서는 IsInteracting==false 를 반환하여 상호작용 가능 여부를 판단하게 된다. (IsInteracting이 false 이면 true 반환)

 

 

'[햄] 작업일기' 카테고리의 다른 글

0718 대화 내용을 엑셀 데이터로 불러오기  (0) 2023.07.18
230717 대화 진행, EndInteract 키 변경  (0) 2023.07.17
230711  (0) 2023.07.11
230706  (0) 2023.07.07
230704  (0) 2023.07.04

두 물체를 연결하기 위해서 socket을 사용해야 한다는 조언을 들었다.

https://blog.naver.com/destiny9720/220903194593

 

[2-7] 소켓 시스템

이번 강좌에서는 언리얼 엔진이 제공하는 소켓 시스템을 이용해 체계적으로 닫힌 공간을 제작하고 캐릭터에...

blog.naver.com

https://docs.unrealengine.com/4.27/ko/WorkingWithContent/Types/StaticMeshes/HowTo/Sockets/

 

스태틱 메시에 소켓 구성 및 사용

소켓 셋업 및 사용 하우투입니다.

docs.unrealengine.com

 

https://danny-padron09.medium.com/using-the-physics-handle-to-grab-objects-in-unreal-70ec9e5382f4

 

Using the Physics Handle to Grab Objects in Unreal

The time has come to finally put all the preparation work that we have been doing to make sure that this Grab functionality in our game is…

danny-padron09.medium.com

 

소켓!!!!!!!!!!!!!!!!!

일단은 필요 없는 걸로 결론남 ㅠㅠ

편해 보이긴 하는데 나중에 다시 살펴봐야겠다

 

손에 붙이려고 그렇게 난리쳤던 게 손에 안 붙은 이유는

액터의 스태틱메시에 Physics가 활성화되어있지 않아서였음

 

HookedComponent->SetSimulatePhysics(true);

 

바로 손에 달라붙는다......

 

 

위치가 좀 이상하게 붙는다 싶더니

캐릭터 블루프린트에 붙여둔 GrabLocation 을 제대로 가져오지 못해서였다

 

FindComponentByClass로 USceneComponent인 GrabLocation을 불러오려고 했는데,

USceneComponent가 여러 개라서 더 상위에 있는 애를 가져온 것 같다

characterGrabLocation = Cast<USceneComponent>(GetDefaultSubobjectByName(TEXT("GrabLocation")));

GetDefaultSubobjectByName으로 해결...

 

블루프린트에서의 위치도 적절히 옮겨 주었다

 

 

 

'[햄] 작업일기' 카테고리의 다른 글

230717 대화 진행, EndInteract 키 변경  (0) 2023.07.17
230714 상호작용 중임을 판단하기  (0) 2023.07.14
230706  (0) 2023.07.07
230704  (0) 2023.07.04
230625-230627  (0) 2023.06.24

물건을 잡았을 때 캐릭터 블루프린트에 임의로 설정해둔 GrabLocation 에 위치를 두게 하고 싶은데

 

예상)

NewLocation = GrabLocation -> GetWorldLocation

NewLocation 으로 SetTargetLocation 하면 될 것 같음

 

실제로 한 것)

1. BeginPlay에서, 캐릭터 블루프린트에 있는 GrabLocation(씬 컴포넌트)의 위치를 받아서 SetHandleLocation 함수를 통해 MovableObject로 넘겨줌. GetComponentLocation으로 FVector 형태로 변환해서 위치 설정

2. 1의 방법은 BeginPlay를 통해 실행되다 보니 위치 갱신이 안 됐음.

캐릭터.cpp에서 씬 컴포넌트 자체를 넘겨줌. MovableObject의 Tick에서 씬 컴포넌트를 FVector로 변경함 (실시간 반영됨)

 

문제점)

위치 실시간 반영됨 (적어도 FVector 값을 실시간으로 변경되는 중)

mobility와 physics가 없어서 그런지 물체 자체가 움직이지는 않는다.

 

 

Character.cpp에 있는 PhysicsHandle 을 MovableObject로 매개변수로 넘겨주고 싶은데,

InteractableObject는 Interact()로 시작하는데

Interact() 에 PhysicsHandle을 넘겨주면...

PhysicsHandle은 Movable에서만 쓰이는데 Interact로 넘겨주면 좀 그렇지 않나?!

 

1. 보이드 포인터 사용 (C++이라서 언리얼은 못 쓸지도?)

2. 완전 베이스 클래스를 넣어라 (?)

매개변수로 베이스 클래스를 넣어서

필요한 곳에서 필요한 형태로 캐스팅하기 (사람을 넣어서 아기, 학생, 어른 다 사용 가능하게)

3. Set 계열 함수 만들기

OnInteract에서 Interact() 외의 다른 함수 호출

Cast는 무조건 상속받은 애 (자식 클래스/서브클래스)만 쓸 수 있는데

사람 중에 여자인지 판단(cast), (여자가 아니거나 사람도 아니면 nullptr)

여자면 여자만 할 수 있는 여자화장실들어가기함수 사용할 수 있다!

 

 

3번 채택

캐릭터.cpp

void AHamsterDemoCharacter::OnInteract()
{
	if (isSuccessInteract)
	{
		UE_LOG(LogTemp, Log, TEXT("E pressed"));

		if (InteractableObj != nullptr)
		{
			UE_LOG(LogTemp, Log, TEXT("interactable obj not null"));
			
			auto Movable = Cast<AMovableObject>(InteractableObj);
			if (Movable != nullptr) //interactable 중 movable 인지 확인
			{
				Movable->SetHandle(characterPhysicsHandle);
			}
			
			InteractableObj->Interact();
		}
		
	}
}

OnInteract() 함수에서

상호작용 하는 물체가 InteractableObj 중 MovableObj 인지 확인 (Cast 사용)

Movable이면 SetHandle함수로 Handle을 붙이기 위한 PhysicsHandle을 넘겨줌 (SetHandle함수는 PhysicsHandle을 넘겨주기 위한 함수)

 

void AMovableObject::Interact()
{
	//PhysicsHandle을 매개변수로 받아서, interactableObj(this)를 getcomponent

	if (MovableHandle == nullptr)
	{
		UE_LOG(LogTemp, Log, TEXT("MovableHandle nullptr"));
		return;
	}
	if (ComponentToGrab == nullptr)
	{
		UE_LOG(LogTemp, Log, TEXT("ComponentToGrab nullptr"));
		return;
	}

	MovableHandle->GrabComponentAtLocationWithRotation(ComponentToGrab, NAME_None, ComponentToGrab->GetOwner()->GetActorLocation(), ComponentToGrab->GetOwner()->GetActorRotation());
}

MovableObject에 Interact()시

MovableObject의 위치에서 Grab

 

 

void AMovableObject::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);

	if (MovableHandle == nullptr)
	{
		return;
	}

	if (MovableHandle->GrabbedComponent)
	{
		// 잡고있는 쪽으로 오브젝트 이동
		//MovableHandle->SetTargetLocation();
		UE_LOG(LogTemp, Log, TEXT("MovableHandle Grabbed Component"));
	}

}

Tick마다 

Handle이 컴포넌트를 잡고 있으면 <<<<물체 이동... 부터는 아직 구현 안 함

 

 

해야 되는 것

- 물체 이동

- 캐릭터가 물체를 잡는 위치 조정 (BP에 붙여둔 GrabLocation과 연동(?)

- 대화창, 인벤토리 등 팝업이 떠 있을 때는 움직일 수 없도록 처리

 

'[햄] 작업일기' 카테고리의 다른 글

230714 상호작용 중임을 판단하기  (0) 2023.07.14
230711  (0) 2023.07.11
230704  (0) 2023.07.04
230625-230627  (0) 2023.06.24
230616  (0) 2023.06.16

캐릭터가 물건을 잡기 위한 Physics Handle 을 캐릭터에 부여하는 과정에서

 

1차 시도

PhysicsHandle = GetOwner()->FindComponentByClass<UPhysicsHandleComponent>();

BeginPlay에서 캐릭터 블루프린트의 Physic Handle 의 이름과 스크립트에서의 이름이 같으니 충돌이 났고,

이름을 다르게 하니까 서로 인식을 못 했다

 

2차 시도

characterPhysicsHandle = CreateDefaultSubobject<UPhysicsHandleComponent>(TEXT("UPhysicsHandleComponent"));

생성자에서 이름을 다르게 하고, 블루프린트에 있는 Phsycis Handle을 불러와서 쓰려고 했으나 실패

 

3차 시도

characterPhysicsHandle = this->FindComponentByClass<UPhysicsHandleComponent>();

BeginPlay에서...

첫 번째 시도의 GetOwner()가 잘못됐음을 깨달음

요상한... Pawn 이 들어왔었나 여튼 의도와 다른 애를 가져오더라

this(현재 객체)로 바꿔주니 해결...

 

 

'[햄] 작업일기' 카테고리의 다른 글

230711  (0) 2023.07.11
230706  (0) 2023.07.07
230625-230627  (0) 2023.06.24
230616  (0) 2023.06.16
230615  (0) 2023.06.15

+ Recent posts