무기시스템 - 활
보조 엑션 클래스 생성 및 준비
- Equipment, DoAction과 같이 UObject이하로 상속을 받아야지 ‘직렬화’가 가능하다.
- 데이터만 다루는 클래스들이다.
- DoAction과 SubAction은 생성 비율이 1 : N 관계이다.
- 무기별 또는 파쿠르 같은 보조 엑션들이 여러개 생성될 것이기 때문이다.
- CSubAction
- 생성
- 엑션과 같은 구조를 가진다.
- 무기별 스킬을 실행할 클래스다.
- 원래는 Attachment나 DoAction을 소유하면 안되지만 ‘개념’ 정도로 두기 때문에 소유할 수 있는 것이다.
- DoAction처럼 SubAction을 상속받아 각각의 보조 엑션 클래스를 생성하고, 또 그것으로 블루프린트 파일을 만들어 할당하는 것으로 사용된다.
- 헤더 파일 - 생성자 선언 - 임의의 BeginPlay 함수를 ‘가상화’ 시켜 선언하고 ‘오너 캐릭터, Attachment, DoAction’을 받는다. - ‘오너 캐릭터’ , ‘Attachment’ , ‘DoAction’ , 상태 컴포넌트 클래스의 ‘상태’ , 움직임 컴포넌트의 ‘움직임’ 변수를 선언한다. - ‘서브 엑션 확인’ 변수 선언 - ‘누름’ 함수와 ‘땜’ 함수 선언하고 ‘가상화’ 시킨다. - ‘서브 엑션 확인 가져오기’ 함수를 선언하고 ‘서브 엑션 확인’ 변수 반환으로 정의한다.
//header public: //외부에서 엑션 확인하는 변수 사용 FORCEINLINE bool GetInAction() { return bInAction; } public: UCSubAction(); public: virtual void BeginPlay(class ACharacter* InOwner, class ACAttachment* InAttachment, class UCDoAction* InDoAction); public: virtual void Pressed(); //누름 함수 virtual void Released(); //땜 함수 protected: bool bInAction; //엑션 중인지 확인 class ACharacter* Owner; class ACAttachment* Attachment; class UCDoAction* DoAction; class UCStateComponent* State; class UCMovementComponent* Movement;- CPP 파일 - 임의의 BeginPlay 함수 정의 - ‘오너 캐릭터’ , ‘Attachment’ , ‘DoAction’ , 상태 컴포넌트 클래스의 ‘상태’ , 움직임 컴포넌트의 ‘움직임’ 변수에 매개변수로 들어온 값과 ‘오너 캐릭터’의 ‘컴포넌트 가져오기’ 함수를 호출하여 저장한다. - ‘누름’ 함수와 ‘땜’ 함수 정의 - ‘서브 엑션 확인’ 변수에 true, false를 설정한다.
//CPP void UCSubAction::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction) { Owner = InOwner; Attachment = InAttachment; DoAction = InDoAction; State = CHelpers::GetComponent<UCStateComponent>(Owner); Movement = CHelpers::GetComponent<UCMovementComponent>(Owner); } void UCSubAction::Pressed() { bInAction = true; } void UCSubAction::Released() { bInAction = false; } - CWeaponAsset
- SubAction은 클래스 타입을 받아서 변수로 사용할 것이다.
- SubAction은 DoActionData와 HitData에 있을수도 있고, 없을 수도 있기 때문에 선언에 직접 할당하지 않고, 필요하면 ‘블루프린트 파일’을 만들어 할당할 것이다.
- 나중에는 SubAction을 여러개 만들것이니 ‘SubActionClasses’ ‘배열 변수’로 선언해야한다.
- 헤더 파일 - 클래스 변수로 ‘SubAction 클래스’ 변수 선언 - 서브 엑션 클래스의 ‘서브 엑션’ 변수 선언 - ‘서브 엑션 가져오기’ 함수를 선언하고 ‘SubAction’을 반환하는것으로 정의한다.
//header //여러개의 스킬일때는 서브엑션즈로 배열을 만들어라 UPROPERTY(EditAnywhere) TSubclassOf<class UCSubAction> SubActionClass; FORCEINLINE class UCSubAction* GetSubAction() { return SubAction; } UPROPERTY() class UCSubAction* SubAction;- CPP 파일 - BeginPlay 함수 확인 - ‘서브 엑션 클래스’ 변수가 비어있지 않다면 : ‘새 오브젝트 생성’ 함수를 서브 엑션 클래스로 지정하고 ‘관리할 클래스 : 웨폰 에셋, 생성할 클래스 : 서브 엑션 클래스’를 넣어 호출한 결과를 ‘서브 엑션’ 변수에 저장한다. - ‘서브 엑션’의 ‘BeginPlay’ 함수에 ‘오너 캐릭터, Attachment, DoAction’을 넣고 호출한다.
//CPP if (!!SubActionClass) { SubAction = NewObject<UCSubAction>(this, SubActionClass); SubAction->BeginPlay(InOwner, Attachment, DoAction); } - CWeaponComponent
- 헤더 파일 - ‘서브 엑션 가져오기’ 함수를 선언한다. - ‘서브엑션 눌림’ 함수와 ‘서브엑션 땜’ 함수를 선언한다.
//header class UCSubAction* GetSubAction(); public: void SubAction_Pressed(); void SubAction_Released();- CPP 파일 - ‘서브 엑션 가져오기’ 함수 정의 - GetDoAction과 같지만 ‘GetSubAction’ 반환으로 바꾼다. - ‘서브엑션 눌림’ 함수와 ‘서브엑션 땜’ 함수 정의 - ‘서브 엑션 가져오기’ 함수가 비어있지 않다면 : ‘서브 엑션 가져오기’ 함수 호출의 ‘눌림’ ‘땜’ 함수를 호출한다.
//CPP UCSubAction* UCWeaponComponent::GetSubAction() { CheckTrueResult(IsUnarmedMode(), nullptr); CheckFalseResult(!!DataAssets[(int32)Type], nullptr); return DataAssets[(int32)Type]->GetSubAction(); } void UCWeaponComponent::SubAction_Pressed() { if (!!GetSubAction()) GetSubAction()->Pressed(); } void UCWeaponComponent::SubAction_Released() { if (!!GetSubAction()) GetSubAction()->Released(); } - CPlayer
- CPP 파일 - ‘서브 엑션 활성’ 함수 확인 - ‘웨폰’의 ‘비 장착 모드 확인’ 함수가 true가 아니라면 : ‘상태’ 변수의 ‘기본 모드 확인’ 함수의 호출이 false라면 실행하지 않고, true 라면 ‘파쿠르’의 ‘파쿠르 실행’ 함수를 호출하고 반환한다. - 무기를 들고있는 상태라면 ‘웨폰’의 ‘서브엑션 누름’ 함수를 호출한다. - ‘서브 엑션 비활성’ 함수 확인 - ‘웨폰’의 ‘비 장착 모드 확인’ 함수를 호출하고 true라면 실행하지 않는다. - ‘웨폰’의 ‘서브 엑션 땜’ 함수를 호출한다.
//CPP void ACPlayer::OnSubAction() { if (Weapon->IsUnarmedMode()) { CheckFalse(State->IsIdleMode()); Parkour->DoParkour(); return; } //무기를 들고있다면 : 스킬 실행 Weapon->SubAction_Pressed(); } void ACPlayer::OffSubAction() { //무기를 안들고있다면 : 스킬 말고 파쿠르 실행 CheckTrue(Weapon->IsUnarmedMode()); Weapon->SubAction_Released(); } - CSubAction_Bow
- 생성
- 헤더 파일 - 생성자 선언 - ‘누름’ ‘땜’ 함수 재정의 선언
//header public: UCSubAction_Bow(); public: void Pressed() override; void Released() override;- CPP 파일 - ‘누름’ 함수 정의 - 부모 함수 호출 - ‘땜’ 함수 정의 - 부모 함수 호출 - 함수 호출 되는지 테스트
//CPP void UCSubAction_Bow::Pressed() { Super::Pressed(); } void UCSubAction_Bow::Released() { Super::Released(); } - BP_CSubAction_Bow
- 생성
- DA_Bow
- SubActionClass 할당
활 보조 엑션 - 조준 상태
- CAnimInstance
- 헤더 파일 - ‘활 조준중 확인’ 변수 선언 - 웨폰 타입이 바뀔때 바뀐것을 알려야 할때 필요한 함수인 ‘웨폰 타입 변경됨 활성’ 함수를 선언하고 ‘전 웨폰 타입, 새로운 웨폰 타입’을 넣고 선언한다. - 시점의 각도를 조절할 ‘피치’ 변수 선언
//header UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Animation") float Pitch; protected: UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Animation") bool bBow_Aiming; //활 조준중인지 확인 private: //웨폰 타입이 바뀔때 연결할 함수다. UFUNCTION() void OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType);- CPP 파일 - ‘웨폰’이 비어있는지 확인한다. : 비었으면 실행 안한다. - ‘웨폰’의 ‘서브 엑션 가져오기’ 함수 호출이 비어있지 않다면 : ‘활 조준중 확인’ 변수를 true로 설정한다. , ‘활 조준중 확인’ 변수에 ‘웨폰타입’과 ‘웨폰 타입 열거형 : 활’이 같다면 ‘1’ 아니면 ‘0’을 저장한다. , ‘활 조준중 확인’ 변수에 ‘웨폰’의 ‘서브 엑션 가져오기’ 함수 호출의 ‘서브 엑션 확인 가져오기’ 함수 호출결과를 저장한다. - ‘웨폰 타입 변경됨 활성’ 함수 정의 - ‘웨폰 타입’에 ‘새로운 타입’을 저장한다. - BeginPlay 함수 확인 - ‘웨폰’이 비어있지 않다면 : ‘웨폰’의 ‘웨폰 타입 변경됨 활성’ 함수의 함수 연결 함수에 (함수가 있는 클래스 : 애님 인스턴스 클래스, 연결할 함수 : 웨폰 타입 변경됨 활성’을 넣고 호출한다. - 키즈멧 메스 자료형의 ‘float 보간’ 함수에 ‘피치, 오너캐릭터의 에임 회전값 가져오기 함수 호출의 피치값, 보간 시간 : 델타 세컨즈, 보간 속도 : 25’을 넣고 호출하고 ‘피치’에 저장한다.
//CPP //FInterpTo : float값으로 보간(R은 회전값으로 보간) //조준 각도 설정 Pitch = UKismetMathLibrary::FInterpTo(Pitch, OwnerCharacter->GetBaseAimRotation().Pitch, DeltaSeconds, 25); if (!!Weapon) Weapon->OnWeaponTypeChanged.AddDynamic(this, &UCAnimInstance::OnWeaponTypeChanged); CheckNull(Weapon); if (!!Weapon->GetSubAction()) { bBow_Aiming = true; bBow_Aiming &= WeaponType == EWeaponType::Bow; bBow_Aiming &= Weapon->GetSubAction()->GetInAction(); } void UCAnimInstance::OnWeaponTypeChanged(EWeaponType InPrevType, EWeaponType InNewType) { WeaponType = InNewType; } - ABP_Character
- 하체는 ‘활’ 기본 이동 동작, 상체는 ‘활 조준’ 동작을 사용한다.
- 지금은 상체 하체 나누는 본을 ‘spine_02’로 했지만 나중에 더 자연스러운 본으로 바꿔도 된다.
- 뎁스 블렌딩 : 1 (1로 설정하면 두 동작이 완전히 섞인다.)
- 에임 오프셋의 Base Pose 연결 주의점 ; 에임 오프셋의 기준 애니메이션이 이전 노드에서 실행이 되어있어야한다.
- 애니메이션의 Alpha 값은 모두 ‘얼마만큼 애니메이션을 섞을지’를 나타내는 값이다.
- 1 : 애니메이션들을 완전히 섞는다는 의미이다.
- 기본 1로 놓고 안보이도록 디테일 - 알파 - ‘핀으로 노출’ 체크 해제한다.
- ‘활 레이어’ 확인 - ‘부울로 포즈 블렌딩’ 검색 - ‘활 조준중 확인’ 변수 검색 후 Active Value핀에 연결 - BS_Bow 노드는 조준중이 아닐때 실행될 노드이니 ‘False 포즈’ 핀에 연결 - BS_Bow 복사 후 ‘본 별로 레이어로 블렌딩’ 검색 후 ‘Base Pose’ 핀에 연결한다. : 조준 중 이동하면서 조준할 수 있도록 하기 위해서다. - 에임 오프셋의 기준 동작이 되는 애니메이션을 ‘Blend Pose’ 핀에 연결한다. - ‘본 별로 레이어로 블렌딩’ 노드의 디테일 , 레이어 설정 , 인덱스 , 분기 필터 추가 , 인덱스 , 본 이름 : 상체 하체 나뉘는 본 , 뎁스 블렌딩 : 1 (1로 설정하면 두 동작이 완전히 섞인다.) , 메시 스페이스 회전 : 체크 - 설정 끝난 ‘본 별로 레이어로 블렌딩’ 노드 핀을 ‘True 포즈’ 핀에 연결한다. - ‘활 에임 오프셋’ 노드 끌어다 놓고 ‘활 조준 동작’ 결과 노드를 ‘Base Pose’로 놓는다. - 에임 오프셋의 가로축 값인 ‘피치’ 핀에 넣을 ‘피치’ 를 검색하고 연결한다. - 최종 애니메이션 포즈 노드와 연결한다.
조준 시야각 제한
- 조준할때 -90과 90 까지 안가도록 설정한다.
- CAttachment_Bow
- Min값과 Max값을 따로따로 선언해도 좋지만, FVector2D로 X는 최솟값 ‘ Y는 최대값으로 설정하여 사용할 수도 있다.
- 헤더 파일 - ‘원본 피치 범위’ 변수 선언
- CPP 파일 - ‘장착 시작 활성’ 함수 확인 - ‘오너 캐릭터’의 ‘컨트롤러 가져오기’ 함수를 ‘플레이어 컨트롤러’로 지정하고 호출한 결과를 ‘컨트롤러’ 변수를 선언하고 저장한다. - ‘컨트롤러’가 비었는지 확인한다. - ‘원본 피치 범위’의 ‘X’에 ‘컨트롤러’의 ‘플레이어 카메라 메니저’의 ‘피치 최솟값’을 저장한다. - ‘원본 피치 범위’의 ‘Y’에 ‘컨트롤러’의 ‘플레이어 카메라 메니저’의 ‘피치 최대값’을 저장한다. - ‘컨트롤러’의 ‘플레이어 카메라 메니저’의 ‘피치 최솟값’에 ‘제한 피치 범위’의 ‘X’ 값을 저장한다. - ‘컨트롤러’의 ‘플레이어 카메라 메니저’의 ‘피치 최대값’에 ‘제한 피치 범위’의 ‘Y’ 값을 저장한다. - ‘장착 해제 활성’ 함수 확인 - ‘오너 캐릭터’의 ‘컨트롤러 가져오기’ 함수를 ‘플레이어 컨트롤러’로 지정하고 호출한 결과를 ‘컨트롤러’ 변수를 선언하고 저장한다. - ‘컨트롤러’가 비었는지 확인한다. - ‘컨트롤러’의 ‘플레이어 카메라 메니저’의 ‘피치 최솟값’에 ‘원본 피치 범위’의 ‘X’ 값을 저장한다. - ‘컨트롤러’의 ‘플레이어 카메라 메니저’의 ‘피치 최대값’에 ‘원본 피치 범위’의 ‘Y’ 값을 저장한다.
//CPP void ACAttachment_Bow::OnBeginEquip_Implementation() { Super::OnBeginEquip_Implementation(); AttachTo("Hand_Bow_Left"); //활 왼손에 장착 //시야각 제한 설정 APlayerController* controller = OwnerCharacter->GetController<APlayerController>(); CheckNull(controller); //카메라 Pitch값 최소 최대 저장 OriginViewPitchRange.X = controller->PlayerCameraManager->ViewPitchMin; OriginViewPitchRange.Y = controller->PlayerCameraManager->ViewPitchMax; controller->PlayerCameraManager->ViewPitchMin = ViewPitchRange.X; controller->PlayerCameraManager->ViewPitchMax = ViewPitchRange.Y; } void ACAttachment_Bow::OnUnequip_Implementation() { Super::OnUnequip_Implementation(); AttachTo("Holster_Bow"); //시야각 제한 설정 APlayerController* controller = OwnerCharacter->GetController<APlayerController>(); CheckNull(controller); controller->PlayerCameraManager->ViewPitchMin = OriginViewPitchRange.X; controller->PlayerCameraManager->ViewPitchMax = OriginViewPitchRange.Y; }
조준하면서 이동 설정
- CArrow
- CPP 파일 - ‘캡슐’의 ‘콜리전 활성화 설정’ 함수에 ‘콜리전 설정 : 충돌 안함’으로 설정한다.
//CPP //화살 충돌체 비활성화 Capsule->SetCollisionEnabled(ECollisionEnabled::NoCollision); - BP_CArrow
- 스테틱 메쉬 확인 - 디테일 - 콜리전 - 콜리전 프리셋 : NoCollision으로 설정한다.
줌 인, 줌 아웃
- 스프링 암
- 타깃 암 길이 : 캐릭터와 카메라가 떨어지는 거리다.
- 소켓 오프셋 : 스프링 암의 끝인 카메라의 위치를 조정한다.
- 회전 중심에 영향을 미치지 않고, 캐릭터와 일정 거리를 유지하게 된다.
- 릴레이티브 좌표다
- 타겟 오프셋 : 캐릭터를 바라보는 시점을 유지하고 현재 카메라 월드 위치에서 보고있는 위치를 조정할때 보정을 주는 값이다.
- 스프링 암의 뿌리, 대상에 부착되는 위치를 조정한다. (기본값은 캐릭터의 뒷목 아랫부분이다.)
- 즉, 캐릭터가 중심이 아니라 다른 중심이 있고, 그것을 기준으로 회전하는 요소다.
- 월드 좌표다.
- CSubAction_Bow
- 헤더 파일 - 에임 데이터를 모을 구조체 선언 - ‘타깃 암 길이’ 변수를 선언하고 100으로 초기화한다. - ‘소켓 오프셋’ 변수를 선언하고 (0, 30, 10)으로 초기화한다. - ‘카메라 레그 활성화 확인’ 변수 선언 - ‘카메라 위치’ 변수 선언 - 선언한 구조체 자료형을 사용하기 위해 ‘에임 데이터’ 변수 선언 - 에임 데이터의 원본값을 저장할 ‘원본 데이터’ 변수 선언 - 조정할 ‘스프링 암’ 변수와 ‘카메라’ 변수 선언 - ‘오너 캐릭터, Attachment, DoAction’을 매개변수로 받는 임의의 BeginPlay 함수 선언
//header USTRUCT() struct FAimData { GENERATED_BODY() public: UPROPERTY(EditAnywhere) float TargetArmLength = 100; //스프링 암 타깃 암 길이 조절 값 UPROPERTY(EditAnywhere) FVector SocketOffset = FVector(0, 30, 10); //카메라 소켓 오프셋(카메라 생성 위치) 보정값 UPROPERTY(EditAnywhere) bool bEnableCameraLag; //카메라 렉 활성화 여부 : 움직이면 조금 뒤에 따라가는 모션 설정 UPROPERTY(EditAnywhere) FVector CameraLocation; //카메라 위치 보정값 }; public: void BeginPlay(class ACharacter* InOwner, class ACAttachment* InAttachment, class UCDoAction* InDoAction) override; private: class USpringArmComponent* SpringArm; class UCameraComponent* Camera; private: FAimData OriginData; //원본 데이터 저장- CPP 파일 - 임의의 BeginPlay 함수 정의 - 부모 함수 호출 - ‘스프링 암’과 ‘카메라’의 컴포넌트를 ‘오너 캐릭터’에서 가져온다. - ‘누름’ 함수 확인 - ‘스프링 암’과 ‘카메라’ 변수의 값이 없으면 실행하지 않는다. - ‘땜’ 함수 확인 - ‘스프링 암’과 ‘카메라’ 변수의 값이 없으면 실행하지 않는다.
//CPP void UCSubAction_Bow::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction) { Super::BeginPlay(InOwner, InAttachment, InDoAction); SpringArm = CHelpers::GetComponent<USpringArmComponent>(InOwner); Camera = CHelpers::GetComponent<UCameraComponent>(InOwner); } void UCSubAction_Bow::Pressed() { CheckNull(SpringArm); CheckNull(Camera); Super::Pressed(); } void UCSubAction_Bow::Released() { CheckNull(SpringArm); CheckNull(Camera); Super::Released(); }
서브 엑션 별개 설정
- 서브 엑션은 현재 상태와는 무관하게 동작하는 기능이다.
- 워프 중 시점 변환 / 조준 중 발사 등
- 모든 게임의 원본 시야각은 ‘90’으로 설정되어있다.
- 가로 세로 비율에서 ‘세로가 1일때’ ‘90도’를 맞춰놓는다.
- CStateComponent
- 헤더 파일 - 서브 엑션 중인지 확인하기 위해서 ‘서브 엑션 확인’ 변수 선언 - ‘서브 엑션 모드 활성’ 함수 선언 - ‘서브 엑션 모드 비활성’ 함수 선언 - 외부에서 서브엑션중인지 확인하기 위해 ‘서브 엑션 확인’ 함수 선언하고 ‘서브 엑션 확인 변수’ 반환으로 정의한다.
//header FORCEINLINE bool IsSubActionMode() { return bInSubActionMode; } void OnSubActionMode(); void OffSubActionMode(); private: bool bInSubActionMode; //서브엑션은 아이들모드와 별개로 작동한다.- CPP 파일 - ‘서브 엑션 활성’ ‘서브 엑션 비활성’ 함수는 ‘서브 엑션 모드중 확인’ 변수를 true, false 설정으로 저장한다.
//CPP void UCStateComponent::OnSubActionMode() { bInSubActionMode = true; } void UCStateComponent::OffSubActionMode() { bInSubActionMode = false; } - CSubAction_Bow
- CPP 파일 - ‘누름’ 함수 확인 - ‘원본 데이터’의 ‘타겟 암 길이’에 ‘스프링 암’의 ‘타겟 암 길이’를 저장한다. - ‘원본 데이터’의 ‘소켓 오프셋’에 ‘스프링 암’의 ‘소켓 오프셋’를 저장한다. - ‘원본 데이터’의 ‘카메라 렉 활성화 확인’에 ‘스프링 암’의 ‘카메라 렉 활성화 확인’를 저장한다. - ‘원본 데이터’의 ‘카메라 위치’에 ‘카메라’의 ‘상대적 위치 가져오기’를 저장한다. - ‘스프링 암’의 ‘타겟 암 길이에 ‘에임 데이터’의 ‘타겟 암 길이’를 저장한다. - ‘스프링 암’의 ‘소켓 오프셋’에 ‘에임 데이터’의 ‘소켓 오프셋’을 저장한다. - ‘스프링 암’의 ‘카메라 렉 활성화 확인’에 ‘에임 데이터’의 ‘카메라 렉 활성화 확인’을 저장한다. - ‘카메라’의 ‘상대적 위치 설정’ 함수에 ‘에임 데이터’의 ‘카메라 위치’를 넣어 호출한다. - ‘카메라’의 ‘FOV’를 45로 설정한다. - ‘땜’ 함수 확인 - ‘스프링 암’의 ‘타겟 암 길이에 ‘원본 데이터’의 ‘타겟 암 길이’를 저장한다. - ‘스프링 암’의 ‘소켓 오프셋’에 ‘원본 데이터’의 ‘소켓 오프셋’을 저장한다. - ‘스프링 암’의 ‘카메라 렉 활성화 확인’에 ‘원본 데이터’의 ‘카메라 렉 활성화 확인’을 저장한다. - ‘카메라’의 ‘상대적 위치 설정’ 함수에 ‘원본 데이터’의 ‘카메라 위치’를 넣어 호출한다. - ‘카메라’의 ‘FOV’를 90으로 설정한다.
//CPP void UCSubAction_Bow::BeginPlay(ACharacter* InOwner, ACAttachment* InAttachment, UCDoAction* InDoAction) { Super::BeginPlay(InOwner, InAttachment, InDoAction); SpringArm = CHelpers::GetComponent<USpringArmComponent>(InOwner); Camera = CHelpers::GetComponent<UCameraComponent>(InOwner); } void UCSubAction_Bow::Pressed() { CheckNull(SpringArm); CheckNull(Camera); Super::Pressed(); State->OnSubActionMode(); OriginData.TargetArmLength = SpringArm->TargetArmLength; OriginData.SocketOffset = SpringArm->SocketOffset; OriginData.bEnableCameraLag = SpringArm->bEnableCameraLag; OriginData.CameraLocation = Camera->GetRelativeLocation(); SpringArm->TargetArmLength = AimData.TargetArmLength; SpringArm->SocketOffset = AimData.SocketOffset; SpringArm->bEnableCameraLag = AimData.bEnableCameraLag; Camera->SetRelativeLocation(AimData.CameraLocation); Camera->FieldOfView = 45; //시야각 설정 (실제 시야각의 반이다. => 45도) } void UCSubAction_Bow::Released() { CheckNull(SpringArm); CheckNull(Camera); Super::Released(); State->OffSubActionMode(); SpringArm->TargetArmLength = OriginData.TargetArmLength; SpringArm->SocketOffset = OriginData.SocketOffset; SpringArm->bEnableCameraLag = OriginData.bEnableCameraLag; Camera->SetRelativeLocation(OriginData.CameraLocation); Camera->FieldOfView = 90; //시야각 설정 (원래 시야각 : 90도) }
블렌드 스페이스와 에임 오프셋 차이점
- 블렌드 스페이스 : 핀에 연결하는 값이 첫 시작 값이다.
- 에임 오프셋 : 기준 애니메이션과 핀에 연결한 값이 섞이는 값이 첫 시작 값이다.