- 애니매이션 추가
- Die() 로직 작성 (애니매이션도 추가)
1) 스켈레톤 변환
- 마음에 드는 애니매이션 에셋을 찾았는데 언리얼 4 스켈레톤이라 적용시키면 모양이 뒤틀림
IK Retarget를 통해 스켈레톤을 변환시켜 적용시켜보기로 함.
Retarget로 source(UE4) target(UE5)로 지정해 스켈레톤을 5에 맞게 변환
-> 일단 자동적으로 맞춰졌음.
이제 애니매이션의 스켈레톤을 바꿔서 익스포트 실행
->파일 선택 후 익스포트
-> 정상적으로 변환 확인
이제 Idle, Walk, Run을 차례대로 변환 후 BS로 새로 생성
이랬던 친구가
스켈레톤에 맞게 정상 변환..!! 드디어 쓸만한것 구해서 적용 시켰다
이제 나머지 다 이렇게 적용하기..(공격 방식 변경 후)2) 공격 방식 변경 시도
- 여태까지는 공격을 하면 멈추고 AttackMontage를 실행한 후 다시 Player한테 붙어서 좀 밋밋했음.
그래서 공격을 할때 캐릭터가 뒤로 빠지면 계속 캐릭터에게 다가갈 수 있도록 수정.- 일단 MOVE_None을 MOVE_Walking으로 수정해서 움직임이 멈추지 않도록 수정.
- 가장 중요한건 AttackMontage가 움직이는 몽타주가 아니라 움직이는 몽타주로 수정하거나 공격을 하면서 계속 캐릭터에 달라 붙게 수정.
중간 진행 상황
- BTTaskNode_Attack
void UBTTask_Attack::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) { Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds); ANXAIController* AIController = Cast<ANXAIController>(OwnerComp.GetAIOwner()); ANXNonPlayerCharacter* NPC = Cast<ANXNonPlayerCharacter>(AIController->GetPawn()); if (!AIController || !NPC) { FinishLatentTask(OwnerComp, EBTNodeResult::Failed); return; } ANXPlayerCharacter* Player = Cast<ANXPlayerCharacter>(GetWorld()->GetFirstPlayerController()->GetPawn()); if (Player) { float DistanceToPlayer = FVector::Dist(NPC->GetActorLocation(), Player->GetActorLocation()); if (DistanceToPlayer > NPC->GetAttackRange()) { if (NPC->bIsNowAttacking) { AIController->MoveToActor(Player, NPC->GetAttackRange(), false, true, false); } } } if (!NPC->bIsNowAttacking) { NPC->bIsAttacking = false; FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded); } }
- 플레이어의 위치를 가져와서 거리를 계산 -> 공격 사거리 밖이면 이동 ->공격이 끝나면 완료
NonPlayerCharactervoid ANXNonPlayerCharacter::BeginAttack() { UNXAnimInstance* AnimInstance = Cast<UNXAnimInstance>(GetMesh()->GetAnimInstance()); checkf(IsValid(AnimInstance) == true, TEXT("Invalid AnimInstance")); GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking); GetCharacterMovement()->bOrientRotationToMovement = true; if (IsValid(AnimInstance)) { AnimInstance->SetRootMotionMode(ERootMotionMode::IgnoreRootMotion); } if (IsValid(AnimInstance) == true && IsValid(AttackMontage) == true && AnimInstance->Montage_IsPlaying(AttackMontage) == false) { AnimInstance->Montage_Play(AttackMontage, 1.0f, EMontagePlayReturnType::Duration, 0.1f); bIsNowAttacking = true; if (OnAttackMontageEndedDelegate.IsBound() == false) { OnAttackMontageEndedDelegate.BindUObject(this, &ThisClass::EndAttack); AnimInstance->Montage_SetEndDelegate(OnAttackMontageEndedDelegate, AttackMontage); } if (ANXAIController* AIController = Cast<ANXAIController>(GetController())) { if (ANXPlayerCharacter* Player = Cast<ANXPlayerCharacter>(GetWorld()->GetFirstPlayerController()->GetPawn())) { AIController->MoveToActor(Player, GetAttackRange()); UE_LOG(LogTemp, Warning, TEXT("AI is attacking and moving towards player!")); } } FVector Start = GetActorLocation(); FVector End = Start + GetActorForwardVector() * AttackRange; TArray<FHitResult> HitResults; FCollisionQueryParams CollisionParams; CollisionParams.AddIgnoredActor(this); bool bHit = GetWorld()->SweepMultiByChannel(HitResults, Start, End, FQuat::Identity, ECC_Pawn, FCollisionShape::MakeSphere(SphereRadius), CollisionParams); if (bHit) { for (const FHitResult& HitResult : HitResults) { ANXCharacterBase* TargetCharacter = Cast<ANXCharacterBase>(HitResult.GetActor()); if (TargetCharacter && TargetCharacter != this) { float DamageAmount = GetAttackDamage(); FPointDamageEvent DamageEvent(DamageAmount, HitResult, HitResult.ImpactPoint - Start, nullptr); TargetCharacter->TakeDamage(DamageAmount, DamageEvent, GetController(), this); UE_LOG(LogTemp, Warning, TEXT("AI Attack! Damage: %f"), DamageAmount); } } } else { UE_LOG(LogTemp, Warning, TEXT("Sphere Trace did not hit anything.")); } } }
- 이동 모드를 Walking으로 설정(공격 중 이동 가능) ->AI가 이동 방향을 향하도록 설정
GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking); GetCharacterMovement()->bOrientRotationToMovement = true;-> Root Motion을 비활성화해 이동을 애니매이션이 아닌 코드로 제어 하도록 설정
if (IsValid(AnimInstance)) { AnimInstance->SetRootMotionMode(ERootMotionMode::IgnoreRootMotion); }-> 공격 중 이동 가능하게 설정
if (ANXAIController* AIController = Cast<ANXAIController>(GetController())) { if (ANXPlayerCharacter* Player = Cast<ANXPlayerCharacter>(GetWorld()->GetFirstPlayerController()->GetPawn())) { AIController->MoveToActor(Player, GetAttackRange()); UE_LOG(LogTemp, Warning, TEXT("AI is attacking and moving towards player!")); } }중간 결과 : 이동하기는 하나 뭔가 찔끔찔끔 부자연스럽게 이동함
내일 시도 해볼 사항
1) 인지 범위 안에 들어오면 달려오면서 공격 모션을 취하게끔해 공격 모션이랑 동일하게 설정
2) 탐지 범위 안에 달려오는 로직이랑 공격 로직이랑 동일시 취급해 자연스럽게 연결