필요한 개념
* 액션 매핑 추가
* Aiming을 위한 SpringArm 설정
1) Target Arm Length를 줄여서 가까워지고
2) SocketOffset(앞부분)을 조정하면 틀어져서 보이게 된다.
3) camera의 FOV(Field of View, 수직 시야각) : 얘는 숫자가 작을 수록 시야각이 좁아짐(레이싱 게임할때 부스트 쓸때 시야각이 좁아짐, FPS Aiming도 시야각이 좁아짐, 줄여서 확 좁아지게)
선의 시작이 SocketOffset(앞부분) 끝 부분이 Target Offset(뒷부분)
Q) 실행해보면 Aim할때 뚝뚝 끊기는 것처럼 보임?
그래서 Curve(커브)를 활용해서 부드럽게 땡기도록 함(ZoomIn, ZoomOut), Spline이랑은 다름(비슷한 수식이긴 하지만)
커브(Curve) : 값이 어느 일정 시간동안 어떻게 변할지
이걸 운용하는 것이 타임라인(Timeline)
이 둘다 C에서 다룰 수 있으나, 나중에 C로 하고 지금은 BP로 작업
타임라인(Timeline) : 커브 에셋을 이용해 시간에 따라 변하는 값을 가져오는 기능
BP에서 타임라인 생성후 더블 클릭해서 들어가면 여기서 커브를 제작가능
f+(float 트랙 추가) 클릭한다. 근데 여기서 만들면 귀찮아져서
커브 에셋을 만들고 타임라인에서 불러오는 것으로 한다.(외부커브 클릭하면 된다.), 불러오고 길이(시간)에 맞도록 세팅해주면 됨
BP를 보면 플레이에 입력이 들어오면 매 프레임마다 Update핀을 실행, Update 핀에서는 Fov값을 가져다 사용함(해당 시간에 대한 FOV가 리턴됨), 그거를 카메라의 FOV에다가
넣을 것임(BP의 SetFieldOfView()), 해서 매 프레임마다 Fov값이 SetFieldOfView()됨
타임라인이 콜되면 업데이트 되는 시간동안 계속 콜이되면서 지정한 값을 가져다 쓸 수 있게됨(Curve의 리턴 값을 가져다 씀)
ZoomOut이벤트는 Timeline에 Reverse에 넣어주면(0.1 ~ 0으로 거꾸로 된다.)
기타->커브 추가-> Float(x), LinearColor(r,g,b,a), Vector(x,y,z) 종류 3가지가 있다. 우리는 x만 사용할 것이라서 float으로 생성한다.
생성해서 들어가면
x축 : 시간, y축 : 값
X축 시간에 따라 변하는 Y값을 사용
우클릭 -> 키 추가 하고 위에 값을 입력하는게 있다. (ex) 0(x)초 일때 값 90(y))fov가 0초일때 90이니깐
또 키추가 하고 0.1일때 fov를 40으로 준다.
0.1초 동안 90 ~ 40 fov값을 하겠다는 의미
그래프를 한눈에 보고 싶다면 위에서 4번째 마우스 클릭하면 된다.
* 자동 탄젠트 적용
너무 선형으로 밑으로 떨어지니까 위에 자동탄젠트 버튼이 있다. 그러면 부드럽게 spline과 같은 형태로 떨어짐
값을 굴곡이 있게 처리함
* 나머지(TargetArmLength나 SocketOffset도 Curve로 변해줘도 되지만, FieldofView만 해도 저것들이 변하는 것처럼 보여서 굳이 할 필요는 없음)
* 이제는 줌 땡길때 사격자세가 되도록 AimingPose를 넣어준다.(AnimBlueprint 편집)
CAnimInstance에서 direction을 구함(1 : 속도, 2 : 캐릭터의 진행 회전값), BP와 똑같은 함수
Direction = CalculateDirection(OwnerCharacter->GetVelocity(), OwnerCharacter->GetControlRotation());
BS_Aim이 원래 권총 모드꺼여서 Rifle_Aim_Idle만 상체로 해서 섞음(본마다 레이어로 블랜딩)
Aiming 상태인지 CRifle에서 체크해서 bool로 포즈를 블랜딩하면 된다.
* 에임상태에서 총구 및 애니메이션이 위 아래로 움직이지 않음(AimOffset을 준다.)
위로 본 자세, 정면 본자세, 아래 본자세를 3개를 값에 따라 섞음, BlendSpace와 가장 큰 차이는 Aimoffset은 중간에 값이 들어와서 섞는 애이다.
* AimOffset 준비하기(Animation Additive로 세팅)
애니메이션 들어가 보면
Addtive Layer : 원래 동작에서 본 마다 설정을 바꿔 다른 동작처럼 사용할 수 있독록 해주는 작업(이 자세가 나오도록 본 마다 회전해서 저장한 것) -> 완전 노가다(모든 AimOffset 에셋으로 사용될 애니메이션에 base포즈 세팅해주고 저거 다 해주면됨)
AddtiveSettings에 base포즈해서 세팅되어 있다.
디자이너의 영역
Tip)
에임 오프셋은 블렌딩 스페이스와 상당히 유사하지만 블렌딩 스페이스는 애니메이션의 시작값이지만 에임 오프셋은 이전의 결과에 섞어 플레이 하는 방식
에임오프셋을 생성할때 2D는 BlendSpace2D와 유사하고, 1D는 BlendSpace1D와 유사
우리는 여기서 위, 앞, 아래만 있게 할꺼라서 1D를 씀
AnimationBP에서 보면
AO에서
Alpha는 얼마만큼 섞일건지(어느본 기준으로 섞일 건지는 디자이너가 이미 정해놈)
우리가 넣은 값 Pitch는 수직 회전 값이 된다.
Pitch 값을 C에서 구해오면 됨
언리얼 시초는 언리얼토너먼트(FPS)여서 FPS를 위해 개발한 엔진이다. 지금은 범용이지만,
그래서 FPS관련 것들이 있다.
그래서 APawn에 GetBaseAimRotation(); 함수가 있다.
GetBaseAimRotation() : 캐릭터가 겨냥하고 있는 곳의 회전 값을 리턴
Pitch = OwnerCharacter->GetBaseAimRotation().Pitch;
<조준점(CrossHair) 구현(위젯으로 구현함)>
위젯 블루프린트의 부모 클래스는 기본적으로 UUserWidget으로부터 상속 받아 구현함
Tip) 그냥 실수로 만들게 되면 BP들어가서 파일->블루프린트 부모변경이 있음
SizeBox : 해상도를 맞추기 위해 씀
실행할 때 화면 Viewport(독립형 게임)와 WidgetBP의 CanvasPanel은 정확히 1 : 1 매칭됨
1) Image를 추가하면 된다. -> Image 속성의 SizeToContent 체크하면 이미지 사이즈에 자동으로 맞게됨
2) 앵커도 가운데 맞춰야 한다.
3) 가운데 맞춰주면 가운데 중앙에 이미지가 오지 않는다. 그래서 Alignment에서 x 0.5 y 0.5를 주면 앵커 가운데 맞춰짐
cpp에서는 UUserWidget으로부터 상속받은 클래스를 클래스로부터 상속받는 BP클래스를 제작할 것임
(함수 재정의할 수 있도록 놓고 BP에서 정의함)
CPlayer에서 BP 불러오고 CreateWidget() 해주면된다.
// BP랑 같음
// CreateWidget<위젯 클래스 타입, 위젯을 출력할 컨트롤러 클래스 타입>()
// 위젯은 보통 카메라(뷰포트)에 발라서 플레이어 컨트롤러가 필요함
// 1 : GetController()-> AController로 반환되어서 이것을 APlayerController로 캐스팅해서 반환해라의미 2 : 위젯 static 클래스(TSubclassOf)
CrossHair = CreateWidget<UCUserWidget_CrossHair, APlayerController>(GetController<APlayerController>(), CrossHairClass);
// 이렇게 하면 화면에 달라붙음
CrossHair->AddToViewport();
<발사 구현>
발사 처리(Rifle의 tick에서 검사)
Projectile로 총알 나가는 모양만 보여줄 것고, 실제 발사는 LineTrace로 처리
적일 때는 전방방향으로 처리하고, 플레이어는 카메라 방향으로 발사 처리를 해야한다.(IIRifle에서 순수가상함수로 줘서 자식에서 처리하도록 함)
나중에 캐릭터의 방향 구현시 Direction을 총구 방향 - 캐릭터의 방향으로 해줘도 됨
// 탄창꾼 생성을 위해
// 랜덤으로 발사 도착 위치 하기 위해
// UnitVector(단위 벡터) : 크기가 1인 벡터
// ConeInDegree : 깔대기 모양을 눈 앞에 댔으면, 눈 앞에는 동그라미가 작을꺼고, 뒤에는 커짐
// 커지는 원 내에서 크기를 정해주면 그 크기에서 랜덤한 방향이 나옴
// 그러니까, 눈 앞에다 깔때기 대고 뒤에 큰 원, 어느 지점을 랜덤으로 지나가는 방향을 리턴(탄창꾼 형성)
// RandomUnitVectorInConeInDegrees() : Elliptical이 붙지않은 거는 끝에가 정원, 가로세로 동일, Radius 하나가 들어감
// RandomUnitVectorInEllipticalConeInDegrees() : 얘는 가로 회전크기, 세로 회전 크기가 들어감
// 정리하자면 Eliiptical이 붙은것은 가로 세로를 지정하는 것이고, 안 붙은거는 정원으로 하는 것임
//1 : 리턴될 2 : Yaw(가로) 크기 3 : Pitch(세로) 크기
FVector conDirection = UKismetMathLibrary::RandomUnitVectorInEllipticalConeInDegrees(OutDirection, 0.2f, 0.3f);
// 단위벡터니까 3000정도 늘림(전방으로 3000 거리의 콘으로 확장)
conDirection *= 3000.0f;
// 거리가 3000 이하인 애들만 LineTrace하기 위해
OutEnd = cameraLocation + conDirection;
정리하자면
UKismetMathLibrary::RandomUnitVectorInEllipticalConeInDegrees() : 콘의 시작지점에서 콘의 끝지점 원에서의 한 지점을 랜덤으로 선택해 시작 지점으로 부터 끝지점까지의 방향 단위백터 생성
LineTrace를 썼을때
이전에는 UkistmetSystemLibrary에 있는 것을 썼는데 결국 이것도 World에 LineTrace를 불르는 것이다.
이번에는 GetWorld()->의 LineTrace 직접적으로 불러서 씀
Player에 OnFocus(), OffFocus() 넣어주고 Player가 기진 widget의 OnFocus() OffFocus()를 호출해주면 된다. 거기서 이미지 색상 바꾸면 됨 이미지 색상 바꾸는 것은 BP에서 하면된다.
BP에서 SetBrushTintColor()로 색상을 바꿔준다. SetBrushTintColor() : 해당 텍스쳐 색상 * TintColor이다.
OnFocus()에서는 빨간색, OffFocus()에서는 다시 흰색하면 맞을 수 있는 것은 빨간색 아닌것은 흰색이 된다.(실제 게임에도 그럼)
* 단발, 연사 구현 준비
// 쏠 수 있도록(3개 준 이유는, 연사 구현때문에)
void Begin_Fire();
void Firing();
void End_Fire(); // End_Fire()는 연사때 쓸려고
SingleTraceByChannel() : 시작 위치에서 끝 위치까지 해당 Channel로 된 가장 가까운 액터를 찾음
LineTrace할 때 총이 나갈 방향을 만듬
// 힘을 주는 방향을 만듬(Owner에서 쏘는 방향으로 방향벡터가 만들어짐)
direction = staticMeshActor->GetActorLocation() - OwnerCharacter->GetActorLocation();
// 방향벡터니까 정규화 시켜줌(크기를 1로 만듬)
direction.Normalize()
// AddImpulseAtLocation() : 지정된 위치에서 지정된 방향으로 나가는 힘을 주는 함수(해당 위치로 부터 해당 방향으로 힘을 전달)
// 2번 위치에서 1번 길이의 방향으로 힘을 주겠다라는 의미
meshComponent->AddImpulseAtLocation(direction * meshComponent->GetMass() * 100, OwnerCharacter->GetActorLocation());
IRifle.h 추가된 내용
...
class UONLINE_03_CPP_API IIRifle
{
GENERATED_BODY()
public:
...
// 총 발사 시작, 끝 위치, 방향 구해줌
virtual void GetLocationAndDirection(FVector& OutStart, FVector& OutEnd, FVector& OutDirection) = 0;
// 우리가 쏠 수 있는 지점이면 포커스를 줌(사격할때)
// 플레이어에서는 크로스헤어에 포커스를 주고 적에서는 뭔가 처리를 할 수 있음
virtual void OnFocus() = 0;
virtual void OffFocus() = 0;
};
CPlayer.h 추가된 내용
...
UCLASS()
class UONLINE_03_CPP_API ACPlayer : public ACharacter, public IIRifle
{
GENERATED_BODY()
private:
// 자료형으로 불러올 것이다.
UPROPERTY(EditDefaultsOnly, Category = "Widgets")
TSubclassOf<class UCUserWidget_CrossHair> CrossHairClass;
// 타임라인 리턴값 FOV에 세팅위해
protected:
UPROPERTY(BlueprintReadOnly, VisibleDefaultsOnly)
class UCameraComponent* Camera;
protected:
// BP(자식)에서 정의해서 쓰세요
UFUNCTION(BlueprintImplementableEvent)
void OnZoomIn();
UFUNCTION(BlueprintImplementableEvent)
void OnZoomOut();
public:
void GetLocationAndDirection(FVector& OutStart, FVector& OutEnd, FVector& OutDirection) override;
public:
void OnFocus() override;
void OffFocus() override;
private:
...
// Aiming 모드
void OnAim();
void OffAim();
// 사격
void OnFire();
void OffFire();
private:
class UCUserWidget_CrossHair* CrossHair;
};
CPlayer.cpp 추가된 내용
...
ACPlayer::ACPlayer()
{
...
SpringArm->SetRelativeLocation(FVector(0, 0, 60));
// 거리
SpringArm->TargetArmLength = 200.0f;
// 벽 같은데 붙어서 선 사이에 물체 들어오면 충돌체크 할거냐?
// true시 카메라 뒤집어짐
SpringArm->bDoCollisionTest = false;
// 컨트롤러에 따라 폰이 회전할거냐?
SpringArm->bUsePawnControlRotation = true;
SpringArm->SocketOffset = FVector(0, 60, 0);
CHelpers::GetClass<UCUserWidget_CrossHair>(&CrossHairClass, "WidgetBlueprint'/Game/Widgets/WB_CrossHair.WB_CrossHair_C'");
}
void ACPlayer::GetLocationAndDirection(FVector& OutStart, FVector& OutEnd, FVector& OutDirection)
{
OutDirection = Camera->GetForwardVector();
// 컴포넌트의 Relative된 위치에 액터 위치에 더해서 절대 공간으로 리턴
FTransform transform = Camera->GetComponentToWorld();
FVector cameraLocation = transform.GetLocation();
// 카메라의 위치의 전방방향만큼 살짝 늘어남
OutStart = cameraLocation + OutDirection;
// 탄창꾼 생성을 위해
// UnitVector(단위 벡터) : 크기가 1인 벡터
// ConeInDegree : 깔대기 모양을 눈 앞에 댔으면, 눈 앞에는 동그라미가 작을꺼고, 뒤에는 커짐
// 커지는 원 내에서 크기를 정해주면 그 크기에서 랜덤한 방향이 나옴
// 그러니까, 눈 앞에다 깔때기 대고 뒤에 큰 원, 어느 지점을 랜덤으로 지나가는 방향을 리턴(탄창꾼 형성)
// RandomUnitVectorInConeInDegrees() : Elliptical이 붙지않은 거는 끝에가 정원, 가로세로 동일, Radius 하나가 들어감
// RandomUnitVectorInEllipticalConeInDegrees() : 얘는 가로 회전크기, 세로 회전 크기가 들어감
// 정리하자면 Eliiptical이 붙은것은 가로 세로를 지정하는 것이고, 안 붙은거는 정원으로 하는 것임
// 콘의 시작 부터 끝지점 원까지 한 지점을 랜덤으로 선택해서, 시작부터 끝지점까지의 방향을 만드고, 단위 벡터를 생성
//1 : 리턴될 2 : Yaw(가로) 크기 3 : Pitch(세로) 크기
FVector conDirection = UKismetMathLibrary::RandomUnitVectorInEllipticalConeInDegrees(OutDirection, 0.2f, 0.3f);
// 단위벡터니까 3000정도 늘림(전방으로 3000 거리의 콘으로 확장)
conDirection *= 3000.0f;
// 거리가 3000 이하인 애들만 LineTrace하기 위해
OutEnd = cameraLocation + conDirection;
}
void ACPlayer::BeginPlay()
{
...
// BP랑 같음
// CreateWidget<위젯 클래스 타입, 위젯을 출력할 컨트롤러 클래스 타입>()
// 위젯은 보통 카메라(뷰포트)에 발라서 플레이어 컨트롤러가 필요함
// 1 : GetController()-> AController로 반환되어서 이것을 APlayerController로 캐스팅해서 반환해라의미 2 : 위젯 static 클래스(TSubclassOf)
CrossHair = CreateWidget<UCUserWidget_CrossHair, APlayerController>(GetController<APlayerController>(), CrossHairClass);
// 이렇게 하면 화면에 달라붙음
CrossHair->AddToViewport();
CrossHair->SetVisibility(ESlateVisibility::Hidden);
Rifle = ACRifle::Spawn(GetWorld(), this);
// 처음부터 장착하도록
OnRifle();
}
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
...
PlayerInputComponent->BindAction("Aim", EInputEvent::IE_Pressed, this, &ACPlayer::OnAim);
PlayerInputComponent->BindAction("Aim", EInputEvent::IE_Released, this, &ACPlayer::OffAim);
PlayerInputComponent->BindAction("Fire", EInputEvent::IE_Pressed, this, &ACPlayer::OnFire);
PlayerInputComponent->BindAction("Fire", EInputEvent::IE_Released, this, &ACPlayer::OffFire);
}
void ACPlayer::OnFocus()
{
// 크로스 헤어에 포커스를 주면 된다.
CrossHair->OnFocus();
}
void ACPlayer::OffFocus()
{
CrossHair->OffFocus();
}
void ACPlayer::OnAim()
{
// 쥔 상태인지
CheckFalse(Rifle->GetEquipped());
// 쥐고 있는 상태인지
CheckTrue(Rifle->GetEquipping());
// true로 만들어서 카메라의 방향대로 함
bUseControllerRotationYaw = true;
// 이동방향 회전하는거 금지
GetCharacterMovement()->bOrientRotationToMovement = false;
SpringArm->TargetArmLength = 100;
// 오른쪽 어깨 위로 가도록
SpringArm->SocketOffset = FVector(0, 30, 10);
// 수직 시야각을 좁힘
//Camera->FieldOfView = 40;
OnZoomIn();
Rifle->Begin_Aiming();
CrossHair->SetVisibility(ESlateVisibility::Visible);
}
void ACPlayer::OffAim()
{
CheckFalse(Rifle->GetEquipped());
CheckTrue(Rifle->GetEquipping());
bUseControllerRotationYaw = false;
GetCharacterMovement()->bOrientRotationToMovement = true;
// 기본 값 200으로
SpringArm->TargetArmLength = 200;
// 다시 기본으로
SpringArm->SocketOffset = FVector(0, 60, 0);
//Camera->FieldOfView = 90;
OnZoomOut();
Rifle->End_Aiming();
CrossHair->SetVisibility(ESlateVisibility::Hidden);
}
void ACPlayer::OnFire()
{
Rifle->Begin_Fire();
}
void ACPlayer::OffFire()
{
Rifle->End_Fire();
}
CRifle.h 추가된 내용
...
UCLASS()
class UONLINE_03_CPP_API ACRifle : public AActor
{
GENERATED_BODY()
...
public:
bool GetAiming() { return bAiming; };
public:
...
void Begin_Aiming();
void End_Aiming();
// 쏠 수 있도록(3개 준 이유는, 연사 구현때문에)
void Begin_Fire();
void Firing();
void End_Fire();
private:
// Aiming 상태인지
bool bAiming;
// 쏘고 있는 중
bool bFiring;
};
CRifle.cpp 추가된 내용
...
void ACRifle::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 발사 체크
CheckFalse(bAiming);
// ownerCharacter가 IIRifle을 상속받는 애인지 체크
// 상속 받지 않는애라면 제대로 애초에 처리할 수가 없음
IIRifle* rifle = Cast<IIRifle>(OwnerCharacter);
// cast가 안되었다면 IIRifle을 상속 받지 않고 있음
CheckNull(rifle);
// LineTrace 체크할 것임
// 쏠 위치, 완료될 끝점,
FVector start, end, direction;
rifle->GetLocationAndDirection(start, end, direction);
// 3.0f은 3초 동안 존재하라는 것
//DrawDebugLine(GetWorld(), start, end, FColor::Green, false, 3.0f);
FCollisionQueryParams params;
// 자기 자신 제거
params.AddIgnoredActor(this);
// 자기 소유한 캐릭터 제거
params.AddIgnoredActor(OwnerCharacter);
FHitResult hitResult;
// ECC_WorldDynamic : Dynamic 개체들 가져옴
// WorldDynamic : 물리를 받을 수 있는 개체를 포함한 모빌리티가 무버블로 설정된 객체
// 하나라도 충돌 된다면 true가 나옴
if (GetWorld()->LineTraceSingleByChannel(hitResult, start, end, ECollisionChannel::ECC_WorldDynamic, params))
{
// hitResult의 actor를 가져와 캐스팅 성공이면 충돌한 것으로 판정
AStaticMeshActor* staticMeshActor = Cast<AStaticMeshActor>(hitResult.GetActor());
if (!!staticMeshActor)
{
// staticMesh 보면은 최상위 루트 노드가 staticMeshComponent이다. 그래서 rootComponent로 가져온다.
UStaticMeshComponent* meshComponent = Cast<UStaticMeshComponent>(staticMeshActor->GetRootComponent());
if (!!meshComponent)
{
// 물리가 켜져있는 애인지
// 우리가 과녁들은 물리를 켜놨다.
if (meshComponent->BodyInstance.bSimulatePhysics)
{
rifle->OnFocus();
return;
}
}//if(!!meshComponent)
}//if(!!staticMeshActor)
}
rifle->OffFocus();
}
void ACRifle::Begin_Aiming()
{
bAiming = true;
}
void ACRifle::End_Aiming()
{
bAiming = false;
}
void ACRifle::Begin_Fire()
{
CheckFalse(bEquipped);
CheckTrue(bEquipping);
CheckFalse(bAiming);
CheckTrue(bFiring);
//bFiring = true;
Firing();
}
void ACRifle::Firing()
{
// 총을 쏠 수 있는 캐릭터 일시 수행해야함
IIRifle* rifle = Cast<IIRifle>(OwnerCharacter);
CheckNull(rifle);
FVector start, end, direction;
rifle->GetLocationAndDirection(start, end, direction);
FCollisionQueryParams params;
params.AddIgnoredActor(this);
params.AddIgnoredActor(OwnerCharacter);
FHitResult hitResult;
if (GetWorld()->LineTraceSingleByChannel(hitResult, start, end, ECollisionChannel::ECC_WorldDynamic, params))
{
AStaticMeshActor* staticMeshActor = Cast<AStaticMeshActor>(hitResult.GetActor());
if (!!staticMeshActor)
{
UStaticMeshComponent* meshComponent = Cast<UStaticMeshComponent>(staticMeshActor->GetRootComponent());
if (!!meshComponent)
{
if (meshComponent->BodyInstance.bSimulatePhysics)
{
// 힘을 주는 방향을 만듬(Owner에서 쏘는 방향으로 방향벡터가 만들어짐)
direction = staticMeshActor->GetActorLocation() - OwnerCharacter->GetActorLocation();
// 방향벡터니까 정규화 시켜줌(크기를 1로 만듬)
direction.Normalize();
// AddImpulseAtLocation() : 지정된 위치에서 지정된 방향으로 나가는 힘을 주는 함수
// 2번 위치에서 1번 길이의 방향으로 힘을 주겠다라는 의미
meshComponent->AddImpulseAtLocation(direction * meshComponent->GetMass() * 100, OwnerCharacter->GetActorLocation());
return;
}
}//if(!!meshComponent)
}//if(!!staticMeshActor)
}
}
void ACRifle::End_Fire()
{
//bFiring = false;
}
CAnimInstance.h 추가된 내용
...
UCLASS()
class UONLINE_03_CPP_API UCAnimInstance : public UAnimInstance
{
GENERATED_BODY()
...
protected:
...
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Animation")
bool bAiming;
};
CAnimInstance.cpp 수정된 내용
...
void UCAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
...
Speed = OwnerCharacter->GetVelocity().Size2D();
// direction을 구함(1 : 속도, 2 : 캐릭터의 진행 회전값)
Direction = CalculateDirection(OwnerCharacter->GetVelocity(), OwnerCharacter->GetControlRotation());
// Aim을 위한 고개를 숙인 회전 값
Pitch = OwnerCharacter->GetBaseAimRotation().Pitch;
IIRifle* rifle = Cast<IIRifle>(OwnerCharacter);
if (!!rifle)
{
bEquipped = rifle->GetRifle()->GetEquipped();
bAiming = rifle->GetRifle()->GetAiming();
}
}
CUserWidget_CrossHair.h
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CUserWidget_CrossHair.generated.h"
UCLASS()
class UONLINE_03_CPP_API UCUserWidget_CrossHair : public UUserWidget
{
GENERATED_BODY()
public:
// 알아서 정의해서 쓰세요
UFUNCTION(BlueprintImplementableEvent)
void OnFocus();
UFUNCTION(BlueprintImplementableEvent)
void OffFocus();
};
결과
'Unreal Engine 4 > C++' 카테고리의 다른 글
<Unreal C++> 33 - Action RPG(Player & Animation Setting & Avoiding(State)) (0) | 2022.05.02 |
---|---|
<Unreal C++> 31 - Gun Shooting Mode (Fire Effect) (0) | 2022.05.02 |
<Unreal C++> 24 - Gun Shooting Mode(Rifle Equip) (0) | 2022.04.24 |
<Unreal C++> 22 - SweepTrace (0) | 2022.04.24 |
<Unreal C++> 20 - Line Trace / Dynamic Delegate (0) | 2022.04.15 |