반응형

절대축 기준..

 

 

GetWorld()->GetFirstPlayerController()->GetControlRotation() : 0~360 사이 각도 리턴

 

GetWorld()->GetFirstPlayerController()->GetControlRotation().Quaternion().Euler()  :  -180 ~ 180 사이의 각도를 리턴한다 

 

 

GetControlRotation 은 컨트롤러의 Rotation 을 리턴한다

 

FRotator APawn::GetControlRotation() const
{
return Controller ? Controller->GetControlRotation() : FRotator::ZeroRotator;
}

 

FRotator AController::GetControlRotation() const
{
ControlRotation.DiagnosticCheckNaN();
return ControlRotation;
}

 

 

회전 값을 행렬로 변환하기 FRotationMatrix()FRotationMatrix(GetControlRotation())

 

 

회전 방향에 대한 절대 축 얻기

 

GetControlRotation() 절대축 기준 회전 값

FRotationMatrix(GetControlRotation()).GetUnitAxis(EAxis::X)

FRotationMatrix(GetControlRotation()).GetUnitAxis(EAxis::Y)

 

vector3 방향으로 회전 행렬 생성 (X 축 기준으로 얼마나 회전이 되었는지 계산

FRotationMatrix::MakeFromX( vector3  ).Rotator()

 

 

 

1차 선형 보간

FMath::FInterpTo

 

회전 보간

FMath::RInterpTo

 

 

충돌 처리

 

도형을 특정 시작 위치에서 목표하는 지점까지 쓸면서(Sweep) 충돌한것이 있다면  반환 하는 함수

 

FHitResult hitResult;
//NAME_None 숫자 0
FCollisionQueryParams params(NAME_None, false, this);

 

bool bResult =

 GetWorld()->SweepSingleByChannel(hitResult, GetActorLocation(), GetActorLocation() + GetActorForwardVector() * 200.0f,
FQuat::Identity, ECollisionChannel::ECC_GameTraceChannel12, FCollisionShape::MakeSphere(50.0f), params);

 

ECollisionChannel::ECC_GameTraceChannel12 : 충돌한 채널

 

FCollisionShape::MakeSphere : 스피어를 만든다

 

 

 

 

FMatrix FRotationMatrix::MakeFromZ(FVector const& ZAxis)

 

ZAxis 이 벡터를 Z 축에 대한 기준으로 삼고 이를 토대로 x,y 축을 뽑아내어 회전 행렬을 만든다

ZAxis 의 방향이 나온 결과에 있어선 z 축이 된다

 

 

 

컴포넌트->SetupAttachment( 붙일 대상, 소켓에 붙일려면 소켓명기입 )

 

액터->AttachToComponent(붙일 대상,  컴포넌트를 붙일 규칙, 소켓에 붙일려면 소켓명기입 )

이 방식으로 하면 무기가 월드 아웃라이너에서 액터로 따로분리 되어 있는것을 볼 수 있다

 

+CreateDefaultSubobject에서 사용하는 문자열의 값은 액터에 속한
  컴포넌트를 구별하기 위한 Hash 값 생성에 사용되고 유일해야한다.

 

//바로 오브젝트를 바로 붙일수 있는건 아니고 Skeletal 이면 이를 관리하는 USkeletalMeshComponent 컴포넌트를 먼저 먼든 다음
//이 컴포넌트에서 관리할 메쉬포인터 쪽으로 무기를 넘겨주고
//실제 이 무기를 사용(캐릭텉에 부착하려면) 무기 컴포넌트를 뼈대에 붙여야 한다
FName weaponSocket(TEXT("hand_rSocket"));
if (GetMesh()->DoesSocketExist(weaponSocket))
{
        _weapon = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WEAPON"));
        static ConstructorHelpers::FObjectFinder<USkeletalMesh> SK_WEAPON(TEXT("/Game/무기 경로.."));
        if (SK_WEAPON.Succeeded())
        {
            _weapon->SetSkeletalMesh(SK_WEAPON.Object);
        }
        _weapon->SetupAttachment(GetMesh(), weaponSocket);
    }


//액터를 붙일때의 코드 형태 (AABWeapon 클래스 안에서 웨폰을 생성하여 갖고 있는 상태)
FName weaponSocket(TEXT("hand_rSocket"));
auto currentWeapon = GetWorld()->SpawnActor<AABWeapon>(FVector::ZeroVector, FRotator::ZeroRotator);

if (currentWeapon != nullptr)
{
currentWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, weaponSocket);
}

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
void AABCharacter::SetWeapon(class AABWeapon* newWeapon)
{
    ABCHECK(nullptr != newWeapon && nullptr == _currentWeapon);
    FName weaponSocket(TEXT("hand_rSocket"));
    if (nullptr != newWeapon)
    {
        newWeapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetNotIncludingScale, weaponSocket);
        newWeapon->SetOwner(this); //네트웍 리플리케이션을 위한 setOwner(this);
        _currentWeapon = newWeapon;
    }
}


* Set the owner of this Actor, used primarily for network replication. 
 * @param NewOwner The Actor whom takes over ownership of this Actor
 */
UFUNCTION(BlueprintCallable, Category=Actor)
virtual void SetOwner( AActor* NewOwner );
 
 

 

 

SetVisibility(bool)          : 인게임과 에디터에서 bool 에 따라 보이거나 안보이거나 한다

SetHiddenInGame(bool) :true 일때 에디터 에서 보이지만 인게임에선 안보인다

 

 

SetActorEnableCollision : 액터 전체의 콜리전 을 껐다 켰다 한다

SetCollisionProfileName("") :  콜리전 preset 을 변경 할 수 있다

 

 

 

컴포넌트  OnComponentBeginOverlap 델리게이트 설정 방법

 

//할당
_trigger->OnComponentBeginOverlap.AddDynamic(this&AABItemBox::OnCharacterOverlap);
 
 
 
//헤더 부분에 함수 선언
 
UFUNCTION() 
void OnCharacterOverlap(UPrimitiveComponent* OverlappedComponent, 
AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, 
bool bFromSweep, const FHitResult& SweepResult);
 
 
//정의 
void AABItemBox::OnCharacterOverlap(UPrimitiveComponent* OverlappedComponent, 
AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, 
bool bFromSweep, const FHitResult& SweepResult) 
///



 

 

 

 

 

 

//게임 인스턴스 구하기

auto abGameInstance = Cast<UABGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));


프로퍼티 

Transient

이 프로퍼티는 휘발성이라, 저장 또는 로드되지 않습니다. 이런 식의 지정자가 붙은 프로퍼티는 로드 시간에 0 으로 채워집니다.

https://docs.unrealengine.com/ko/Programming/UnrealArchitecture/Reference/Properties/index.html


액터 수명 주기

https://docs.unrealengine.com/ko/Programming/UnrealArchitecture/Actors/ActorLifecycle/index.html

 

액터의 수명 주기

액터가 로드 또는 스폰된 후 결국 죽을 때 벌어지는 일에 대해서입니다.

docs.unrealengine.com

 

게임 시작 과정 

 
만약 레벨에 이미 올라와 있는 액터가 있다면 
 
AActor::AActor() // 레벨에 올라가 있던것
 
AActor::PostLoad or AActor::PostActorCreated  // 레벨에 올라가 있던것
이 과정을 거친다음
 
UGameInstance::Init  : 상주하는 게임 인스턴스가 초기화
 
 
AActor::PostInitializeComponents // 레벨에 올라가 있던것
 
이후에는 GameMode 에 의해서 생성된것을 기준으로 보면
 
APlayerController::AABPlayerController         //컨트롤러 먼저 생성하고
 
APlayerController::PostInitializeComponents 
 
AGameMode::PostLogin(26)PostLogin Begin  //게임모드 PostLogin 이 실행하기 전(함수는 실행되나 
                                 Super::PostLogin(NewPlayer); 이 실행되기 이전임, 즉 이 함수 실행이 되면서
 
ACharacter::ACharacter(76)                      //게임 모드에서 생성되는 캐릭터
ACharacter::PostActorCreated(218)           //캐릭터가 생성됨
ACharacter::PostInitializeComponents(196)
 
APlayerController::OnPossess(15)OnPossess begin   //컨트롤러가 Pawn(캐릭터)를 시작 전
(즉 Super::OnPossess(InPawn); 실행전)
 
ACharacter::PossessedBy(223)   //캐릭터가 컨트롤러에 의해서 소유됨
 
APlayerController::OnPossess(18)OnPossess end //캐릭터 소유, Super::OnPossess(InPawn); 실행이후
 
AGameMode::PostLogin(28)PostLogin end //로그인 과정 끝


Actor::BeginPlay() //미리 로드되어 있던것

AABPlayerController::BeginPlay()

ACharacter::BeginPlay()

AGameMode::BeginPlay() //미리 로드되어 있던것



AGameMode::StartPlay(33)StartPlay() //게임 플레이 시작

블루프린트를 만들때 부모를 .cpp 로 만든다음 SkeletalMesh 값을 자식 BP 에서 변경 했을때

 

C++ 쪽에서 부모에서 default 로 기본이 되는 mesh 를 적용했고 이것을 상속 받은

BP 에서 열고 새롭게 할당한 Mesh 가 블루프린트에서 적용되는 C++ 지점은 PostLoad() 부분이다

PostLoad 를 레벨이 이미배치 됐을때 호출 되는것이며

SpawnActor 로 스폰하면 PostLoad가 아닌 PostActorCreated 이 호출 된다(즉 상호 배제적)

 

 

 

 

 

 

델리게이트

 

다이네믹 델리게이트

C++ 만의 델리게이트가 있고 C++ 과 블루프린트간에 연동되는 델리게이트가 있는데 이 연동 되는 델리게이트를

다이네믹 델리게이트라 한다, 다이네믹 델리게이트의 경우 UFUNCTION() 과 사용해야함으로 C++ 람다식을 사용할 수는 없다

 

DECLARE_MULTICAST_DELEGATE 는 람다 가능

 

 

FOnMontageEndedMCDelegate OnMontageEnded;  : 몽타주 애니가 끝날때(섹션 재생도중 중간에 끝나도) 이벤트가 발생

 

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMontageEndedMCDelegate, UAnimMontage*, Montage, bool, bInterrupted);

//Animinstance.h 에 있는 내장형

UPROPERTY(BlueprintAssignable) 

FOnMontageEndedMCDelegate OnMontageEnded;

 

 

 

UFUNCTION() //다니네믹 멀티 라서 UFUNCTION 이 들어감

void OnAttackMontageEnded(UAnimMontage* montage, bool bInterrupted);

 

 

//UFUNCTION() c++ 과 블루프린트에서 모두에 호출되는 함수 바인딩시 AddDynamic

_aBAnim->OnMontageEnded.AddDynamic(this&AABCharacter::OnAttackMontageEnded);

 

 

 

 

멀티캐스트 델리게이트  : 등록된 모든 함수에게 알려주는 기능

 

람다를 델리게이트에 바인딩 시

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

DECLARE_MULTICAST_DELEGATE(FOnNextAttackCheckDelegate);

 

 

FOnNextAttackCheckDelegate OnNextAttackCheck;

 

// UFUNCTION 을 연결하는 것이 아님

    _aBAnim->OnNextAttackCheck.AddLambda([this]()->void

    {

        //ABLOG(Warning, TEXT("OnNextAttackCheck"));

        _canNextCombo = false;

        if (_isComboInputOn)

        {

            AttackStartComboState();

            _aBAnim->JumpToAttackMontageSection(_currentCombo);

        }

    }

    );

 

// 연결된것 모두 호출

OnNextAttackCheck.Broadcast(); // 호출

 

 

C++ 블루프른트와 연동 되면서 등록된 함수모두에게 알려주는 기능 : 다이네믹 멀티캐스트 델리게이트

DECLARE_DYNAMIC_MULTICAST_DELEGATE

 

 

 

Montage_IsPlaying () : 몽타주가 재생중인지 확인

Montage_JumpToSection()  : 해당 섹션으로 몽타주 재생 아니 jump 하기

 

Primitive : 기본 도형

 

 

 

 

void AttackCheck();

 

일반 UObject 함수 바인딩시

_aBAnim->OnAttackHitCheck.AddUObject(this, &AABCharacter::AttackCheck);

 

 

이벤트

여러 함수에 바인딩하여 모두 한 번에 실행시킬 수 있는 델리게이트입니다.

이벤트(Event)는 멀티캐스트 델리게이트 와 매우 유사합니다.

그러나 어느 클래스도 이벤트 바인딩이 가능하지만, 이벤트를 선언한 클래스만이 이벤트의 Broadcast, IsBound, Clear 함수를 호출할 수 있습니다.

즉 이와 같이 민감한 함수에 대한 접근권을 외부 클래스에 주면 어떡하지 하는 걱정 없이,

이벤트 오브젝트는 퍼블릭 인터페이스에 노출시킬 수 있다는 뜻입니다. 이벤트가 사용되는 곳은, 순수 추상 클래스의 콜백 포함하기, 외부 클래스의 Broadcast, IsBound, Clear 함수 호출 제한시키기 입니다.

 

DECLARE_EVENT( OwningType, EventName )

이벤트를 생성합니다.

DECLARE_EVENT_OneParam( OwningType, EventName, Param1Type )

파라미터가 하나인 이벤트를 생성합니다.

...

DECLARE_EVENT 매크로의 첫 파라미터는 이 이벤트를 "소유"(own)하게 될 클래스,

 Broadcast() 함수를 호출할 수 있는 클래스입니다.

 

https://docs.unrealengine.com/ko/Programming/UnrealArchitecture/Delegates/Events/index.html

 

 

 

//액터에 UI 위젯을 달수 있는 컴포넌트, 액터가 이것을 달면 UI HP 같은 바를 나타낼 수 있음

//이걸 들고 있으면 됨

UWidgetComponent 

 

이것을 사용하려면 언리얼 엔진에서 UMG 모듈을 추가해주야 한다

기본적으로 이 모듈은 제외되어 있음

 

프로젝트명.Build.cs

 

파일에 보면 모듈들이 있는데 그 중 UMG 가 빠져 있는 것을 볼 수 있다

 

언리얼 엔진은 여러 모듈들이 합쳐진 형태로 구성되고 해당 프로젝트마다 모듈을 조합하여 하나의 프로젝트를 구성하게 된다

 

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore"});

 

"UMG" 부분 추가

 

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG" });

 

UE4 프로젝ㅌ에서 Source> runtime > UMG 폴더에 위치하게된다

 

이렇게 모듈을 추가하면 .h 는 추가해줘야 하지만 전체 경로를 몰라도 Public 폴더에 있는 헤더 파일을 게임 프로젝트(현재 게임을 만드는 프로젝트)에 이있는 헤더 파일처럼 자유롭게 참조 할 수 있다 

헤더는 Source>Runtime>UMG>Public>Components>WidgetComponent.h  에 있는데

 

WidgetComponent.h 이것을 포함하면 된다

#include "Components/WidgetComponent.h"

 

UPROPERTY(VisibleAnywhere, Category=UI)
class UWidgetComponent* _hpBarWidget;

 

_hpBarWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("HPBARWIDGET"));

 

_hpBarWidget->SetupAttachment(GetMesh());

 

 

UI 로직은 위젯 블루프린트는 애님인스턴스와 비슷하게 C++ 클래스에서 미리 만들어 제공할 수 있다

위젯 블루프린트가 사용하는 기반 C++ 클래스는 UserWidget 이다

 

 

 

위젯의 초기화 시점이 4.21 부터 PostInitializeComponents 에서 BeginPlay 로 변경 됨

 

 

UI 초기화 시점은 PlayerController의 BeginPlay 에서 UI 가 생성된다

생성시 NativeConstruct 함수가 호출된다

PlayerController::PostInitializeComponents() 함수에서 실행한 명령은 UI 에 반영 되지 않음으로

UI 시스템이 준비되면 호출 되는 함수 NativeConstruct 함수 에서 실행한다

여기에서 위젯 내용을 업데이트 한다

 

 

위젯에 있는것중에 이름으로 ProgressBar 를 얻어올 수 있음

_hPProgressBar = Cast<UProgressBar>(GetWidgetFromName(TEXT("PB_HPBar")));

 

void UABCharacterWidget::NativeConstruct()
{
Super::NativeConstruct();
_hPProgressBar = Cast<UProgressBar>(GetWidgetFromName(TEXT("PB_HPBar")));
ABCHECK(_hPProgressBar!=nullptr);
UpdateHPWidget();
}

반응형

+ Recent posts