* 언리얼 TopDown 예시 살펴보기
- 원인
눌럿다떼면 복제기능이 없는 simpleMove가 실행되서 안되는거임
즉, 멀티플에이어인경우 클라의경우 계속눌르고있어야 이동가능함
* 우리의 Click to move설계
AddMove를 써야함 && 장애물처리 구현해야함
* 설계
* 언리얼을 배껴서 변수생성
PC
FVector CachedDestination=FVector::ZeroVector; //클릭된 목적지 저장
float FollowTime=0.f; //놓기전에 얼마나 오랫동안 마우스 눌렀는지 저장
float ShortPressThreshold = 0.f; //짧게눌렀는지 판단하는 기준
bool bAutoRunning=false;
UPROPERTY(EditDefaultsOnly)
float AutoRunAcceptanceRadius = 50.f; //자동이동 가능 범위
UPROPERTY(VisibleAnywhere)
TObjectPtr<USplineComponent> Spline; //부드러운 자동이동위한 스플라인, 생성자에서 초기화
};
스플라인 초기화
AAuraPlayerController::AAuraPlayerController()
{
bReplicates = true; // 해당 컨트롤러가 네트워크 상에서 복제될 수 있도록 함
Spline=CreateDefaultSubobject<USplineComponent>("Spline");
}
* 쭉누르면 이동 구현
추가적으로, 적을 타겟팅하고 있는지 아닌지에 따라 분기해줘야함
bool bTargeting = false; //적을 타겟팅하고 있는지
이동구현 : (처음누름, 뗌, 누르는중) 구분 && 타겟팅중인지 구분
void AAuraPlayerController::AbilityInputTagPressed(FGameplayTag InputTag) //처음누름
{
//LMB인 경우
if(InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))
{
//ThisActor 가있으면 타겟팅중임
bTargeting = ThisActor ? true : false;
bAutoRunning=false;
}
}
void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag) //뗌
{
if(GetASC()==nullptr) return;
GetASC()->AbilityInputTagHeld(InputTag);
}
void AAuraPlayerController::AbilityInputTagHeld(FGameplayTag InputTag) //누르는중
{
//LMB가 아닌 일반태그인 경우, 그냥 능력을 활성화하고 끝냄
if(!InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))
{
if(GetASC())
{
GetASC()->AbilityInputTagHeld(InputTag); //ASC의 함수호출
}
return;
}
//LMB인경우, 달리는 문제를 해결해야함
//타겟팅중인 적이 있는 경우
if(bTargeting)
{
if(GetASC())
{
GetASC()->AbilityInputTagHeld(InputTag); //ASC의 함수호출
}
}
else //타겟팅중인 적이 없는경우
{
FollowTime+=GetWorld()->GetDeltaSeconds(); //몇초눌렀는지 저장
FHitResult Hit;
if(GetHitResultUnderCursor(ECC_Visibility,false,Hit))
{
CachedDestination = Hit.ImpactPoint; //커서눌린위치를 저장
}
//이동, 이동하려면 폰이필요함
if(APawn* ControlledPawn = GetPawn())
{
const FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()).GetSafeNormal(); //b-a 하면 방향이나옴
ControlledPawn->AddMovementInput(WorldDirection); //그 방향으로 이동
}
}
}
* 짧게누르면 이동구현
void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag) //뗌
{
//LMB가 아닌 일반태그인 경우, 그냥 능력을 활성화하고 끝냄
if(!InputTag.MatchesTagExact(FAuraGameplayTags::Get().InputTag_LMB))
{
if(GetASC())
{
GetASC()->AbilityInputTagReleased(InputTag); //ASC의 함수호출
}
return;
}
if(bTargeting)
{
if(GetASC())
{
GetASC()->AbilityInputTagReleased(InputTag); //ASC의 함수호출
}
}
else //짧게누른경우 거기로 부드럽게 이동 구현
{
APawn* ControlledPawn = GetPawn();
//짧게누른경우
if(FollowTime<=ShortPressThreshold && ControlledPawn)
{
//(시작위치, 끝위치)
UNavigationPath* NavPath =
UNavigationSystemV1::FindPathToLocationSynchronously(this, ControlledPawn->GetActorLocation(),CachedDestination);
if(NavPath)
{
Spline->ClearSplinePoints();
for(const FVector& PointLoc : NavPath->PathPoints) //목적지로가는 경로들에 대해
{
Spline->AddSplinePoint(PointLoc, ESplineCoordinateSpace::World); //스플라인 지점 추가
DrawDebugSphere(GetWorld(),PointLoc,8.f,8,FColor::Green, false); //디버깅용
}
bAutoRunning=true; //오토러닝 켜주기
}
}
FollowTime=0.f; //팔로우타임리셋
bTargeting=false; //타게팅여부 리셋
}
}
- 모듈추가 해줘야됨
결과 : 아무일도안일어남
해결 : NavMeshBoundsVolume 추가해야함
* 장애물 추가 실험
* 틱마다 점들로 이동하면 되는거임
void AAuraPlayerController::PlayerTick(float DeltaTime)
{
Super::PlayerTick(DeltaTime);
CursorTrace();
if(APawn* ControlledPawn = GetPawn())
{
//캐릭이 스플라인위에 없을수도있음 -> 캐릭에서 스플라인에 가까운 위치찾기
const FVector LocationOnSpline = Spline->FindLocationClosestToWorldLocation(ControlledPawn->GetActorLocation(), ESplineCoordinateSpace::World);
//방향찾기
const FVector Direction = Spline->FindDirectionClosestToWorldLocation(LocationOnSpline, ESplineCoordinateSpace::World);
ControlledPawn->AddMovementInput(Direction);
//자동이동 범위밖에 클릭된경우 오토런을 꺼주기
const float DistanceToDestination = (LocationOnSpline - CachedDestination).Length();
if(DistanceToDestination<=AutoRunAcceptanceRadius)
{
bAutoRunning=false;
}
}
}
- 함수로 리팩토링
void AAuraPlayerController::AutoRun()
{
if(APawn* ControlledPawn = GetPawn())
{
//캐릭이 스플라인위에 없을수도있음 -> 캐릭에서 스플라인에 가까운 위치찾기
const FVector LocationOnSpline = Spline->FindLocationClosestToWorldLocation(ControlledPawn->GetActorLocation(), ESplineCoordinateSpace::World);
//방향찾기
const FVector Direction = Spline->FindDirectionClosestToWorldLocation(LocationOnSpline, ESplineCoordinateSpace::World);
ControlledPawn->AddMovementInput(Direction);
//자동이동 범위밖인경우 오토런을 꺼주기
const float DistanceToDestination = (LocationOnSpline - CachedDestination).Length();
if(DistanceToDestination<=AutoRunAcceptanceRadius)
{
bAutoRunning=false;
}
}
}
void AAuraPlayerController::PlayerTick(float DeltaTime)
{
Super::PlayerTick(DeltaTime);
CursorTrace();
AutoRun(); //리팩토링
}
- 원인 : 무조건 AutoRun하고있음
-해결 : AutoRun이 아니면 return 하도록 fix
* 멀티플레이 Test
* 버그발견
- 원인 : nav mash에 없는 항목(ex : 기둥 자체) 을 클릭해서 그럼
-해결1 : 기둥 콜리전 > 가시성을 무시하면, 클릭이 무시되는듯?
- 문제2 : navmash 볼륨자체를 클릭하면, 마찬가지로 무한이동 버그가생김
- 해결 : 클릭한지점을 PathPoint위의 지점으로 강제로 변경 => 항상 도달가능한 목적지로 달려감
void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag) //뗌
{
...
CachedDestination = NavPath->PathPoints[NavPath->PathPoints.Num()-1]; //이상한곳 클릭방지, 클릭지점을 PathPoint 위의 점으로 강제설정
이제 우리는 아무곳이나 클릭해도 됨!
'UE5 > Gameplay Abilities' 카테고리의 다른 글
[UE5] 파이어볼 생성 구현 (0) | 2024.06.09 |
---|---|
[UE5] PC 리팩토링, 클라에서 포션먹음 메시지 안뜨는 버그수정, 클라이언트 RPC (0) | 2024.06.09 |
[UE5] 태그에 맞는 능력 활성화 구현 (0) | 2024.06.09 |
[UE5] Input바인딩용 클래스 생성, 클릭이벤트 발생 테스트 (0) | 2024.06.09 |
[UE5] 태그-입력 연결 구현, 런타임에 입력변경 구현준비 (0) | 2024.06.09 |