절대축 기준..
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
게임 시작 과정
|
만약 레벨에 이미 올라와 있는 액터가 있다면
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 모듈을 추가해주야 한다
기본적으로 이 모듈은 제외되어 있음
파일에 보면 모듈들이 있는데 그 중 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();
}
'게임엔진(GameEngine) > Unreal4' 카테고리의 다른 글
Resolution change, Full, Window (0) | 2020.12.15 |
---|---|
플러그인 모듈 추가 EditorScriptingUtilities (0) | 2020.09.15 |
TSubclassOf, TEnableIf, TPointerIsConvertibleFromTo 의 이해 (0) | 2020.05.21 |
Analytic Two-Bone IK(투 본 IK) (0) | 2020.05.13 |
CCD IK (Cylic Coordinate Descent IK ) : IK (0) | 2020.05.06 |