공부/Unreal

24.08.09

월러비 2024. 8. 10. 16:52

타겟팅 시스템 - 전에 이어서

타겟팅 - 타겟 재선정 중 전방벡터 기준으로 수직거리와 객체 저장

  • 절댓값을 사용한다는것 : 왼쪽이든 오른쪽이든 가장 작은 값을 가까운 적이라고 판단한다.
  • 문제점 : 빠르게 타겟을 이동하면 원하는 타겟이 아니라 다른 적을 찾는 문제가 생긴다.
  • GetControlRotation() : 회전자(Rotator)를 반환한다.
    • Rotator는 벡터를 반환하지 못한다.
    • 해결법 : FQuat 를 사용한다. ⇒ 회전자를 쿼터니온으로 바꾸고, 쿼터니온의 전방벡터를 가져온다.
  • 두 방향 벡터의 외적 결과인 수직 벡터의 길이 = 평행한 벡터끼리의 거리와 일 대 일 관계이다.
  • 언리얼은 개발자가 풀지 않는 이상 ‘캐릭터가 겹치지 않으므로’ 같은 위치에 있을 수 없다.
  • CTargetComponent
    • CPP 파일 -’타겟 이동’ 함수 정의 - ‘오너 캐릭터’의 ‘액터 위치 가져오기’ 함수를 ‘위치’ 함수를 선언하고 저장한다. - 액터 배열 변수 ‘무시하는 객체들’ 변수 선언 - ‘무시하는 객체들’의 ‘추가’ 함수에 ‘오너 캐릭터’를 넣어서 오너 캐릭터 탐색을 무시하게 한다. - ‘무시하는 객체들’의 추자’ 함수’에 ‘타겟’ 변수를 넣고 호출한다. - ‘히트 결과들’ 배열 변수 선언 - ‘구 멀티 탐색’ 함수에 ‘요소들’을 넣고 호출한다. - ‘수직간 거리, 탐색된 적’을 저장할 TMap 클래스의 ‘맵’ 변수를 선언한다. - ‘히트 결과들’ 배열의 요소를 하나씩 꺼내서 ‘히트 결과’에 넣고 반복한다. : 히트된 결과가 캐릭터로 형변환 되는지 확인하기 위해 캐릭터 자료형을 넣은 ‘Cast’ 함수에 ‘히트 결과’의 ‘액터 가져오기’ 함수를 넣어 호출하고 ‘캐릭터’ 변수에 저장한다. - ‘캐릭터’ 변수가 비었다면 : 반복을 무시하고 벗어난다. - 플레이어에서 타겟을 바라보는 방향을 구하기 위해 ‘캐릭터 : 히트 탐색된 적’의 ‘액터 위치 가져오기’ 함수를 호출하고 저장하는 변수를 ‘위치 2’로 선언한다. - ‘오너 캐릭터’의 ‘컨트롤러 회전값 가져오기’함수 호출을 ‘FQuat’함수에 넣은 결과에서 ‘전방 벡터 가져오기’ 함수를 호출한 결과를 ‘전방’ 변수를 선언하고 저장한다. - ‘위치 2 : 적 위치’ - ‘위치 1 ; 플레이어 위치’의 결과를 저장할 ‘방향’ 변수를 선언하고 저장한다. - ‘방향’의 ‘일반화’ 함수를 호출한다. - ‘외적’ 함수에 ‘기준축인 전방 벡터, 뱡향’ 을 넣고 호출한 결과를 ‘외적’ 변수를 선언하고 저장한다. - ‘내적’ 함수에 ‘내적 벡터, 외적’을 넣고 호출한 결과를 ‘내적’ 변수를 선언하고 저장한다. - ‘맵’의 ‘추가’ 함수에 ‘내적, 캐릭터 : 탐색된 적’을 넣고 호출한다.
    //CPP
    //구 추적에서 탐지된 객체를 플레이어 전방벡터를 기준으로 거리와 적 객체를 저장하는 코드
    //KeyValue
    TMap<float, ACharacter*> map;
    
    for (const FHitResult& hitResult : hitResults)
    {
    	ACharacter* character = Cast<ACharacter>(hitResult.GetActor());
    	if (character == nullptr)
    	{
    		//캐릭터가 아니라면 건너뛴다.
    		continue;
    	}
    
    	//회전된 오너 캐릭터의 카메라 회전값의 전방벡터를 가져온다. => 타겟팅의 기준이 된다.
    	FVector forward = FQuat(OwnerCharacter->GetControlRotation()).GetForwardVector();
    
    	//히트된 캐릭터 위치
    	FVector location2 = character->GetActorLocation();
    
    	//오너가 적을 바라보는 방향
    	FVector direction = location2 - location;
    	direction.Normalize();
    
    	//외적
    	FVector cross = FVector::CrossProduct(forward, direction); //전방벡터가 기준이되니 매우 중요하다.
    
    	//수직간 거리는 '내적'을 이용해서 구할 수 있다.
    	float dot = FVector::DotProduct(FVector::UpVector, cross); 
    
    	map.Add(dot, character); //수직간거리(좌측, 우측 판단)와 캐릭터 저장
    }
    

타겟팅 - 타겟 재선정 중 좌 우 타겟 변경

  • 0은 현재 설정된 타겟이니 0을 제외한 -와 +의 탐지된 적만 찾는다.
  • 왼쪽이든 오른쪽이든 ‘절댓값’을 씌우면 기준축에서 가까운 거리는 가장 작은 값이된다.
  • CTargetComponent
    • CPP 파일 - ‘타겟 이동’ 함수 정의 - ‘최솟값’ 변수를 선언하고 ‘float 최대값 메크로’를 저장한다. - 변경할 타겟을 저장할 ‘타겟 후보자’ 변수를 선언하고 Null로 초기화한다. - ‘맵’의 요소를 하나씩 꺼내 TPair 자료형의 ‘페어’ 변수에 저장한다. : ‘에어’의 ‘키 : 수직간 거리’를 ‘키’ 변수를 선언하고 저장한다. - ‘오른쪽 확인’ 변수가 True 라면 : ‘키’ 변수가 0.0f보다 작다면(왼쪽 객체들을 의미한다.) : 반복을 건너 뛴다. - 오른쪽이 아니라면 : ‘키’ 변수가 0.0f 보다 크다면(오른쪽 객체들을 의미한다.) : 반복을 건너뛴다. - ‘키’를 ‘절댓값’ 함수에 넣은 결과가 ‘최솟값’ 보다 작다면 : ‘최솟값’에 ‘키’를 ‘절댓값’ 함수에 넣은 결과를 저장하고, ‘페어’의 ‘결과 : 탐지된 객체’를 ‘타겟 후보자’ 변수에 저장한다. - ‘타겟 바꾸기’ 함수에 ‘타겟 후보자’ 변수를 넣고 호출한다.
    //CPP
    //타겟 이동 왼쪽, 오른쪽 구분
    //FLT_MAX : 매크로, float 의 가장 큰 값
    float minimum = FLT_MAX;
    ACharacter* candidate = nullptr;
    
    for (TPair<float, ACharacter*> pair : map)
    {
    	float Key = pair.Key; //키에 외적간 거리가 있다.
    
    	//오른쪽이라면 : 즉, 매개값이 1이라면
    	if (bRight)
    	{
    		//오른쪽이면 0보다 작은 왼쪽을 배제한다.
    		if (Key < 0.0f)
    		{
    			continue;
    		}
    	}
    	else
    	{
    		//왼쪽이라면 0보다 큰 오른쪽을 배제한다.
    		if (Key > 0.0f)
    		{
    			continue;
    		}
    	}
    
    	//최솟값보다 작다면 : 그 값이 다음 타겟이 된다.
    	if (FMath::Abs(Key) < minimum)
    	{
    		minimum = FMath::Abs(Key);
    		candidate = pair.Value;
    	}
    }
    
    //Change에서 null값이 들어간다면 : 타겟팅이 해제된다.
    Change(candidate);
    

2교시

  • 타겟팅 끝
  • 워프 시작

타겟팅 - 타겟 재선정 중 또 타깃 변경 안되게 막기

  • 타깃 변경중 또 타깃 변경을 누르게 된다면 원하는 타겟이 아닌 다른 적을 타겟팅 하는 경우가 생긴다.
  • CTargetComponent
    • 헤더 파일 - ‘타겟 토커스 움직임 확인’ 변수 선언
    //header
    private:
    	bool bMovingFocus; //타겟 변경중인지 확인
    
    • CPP 파일 - ‘틱 컴포넌트’ 함수 확인 - 타겟 근삿값 같은지 확인하는 코드 확인 - 회전값 설정 전 ‘타겟 토커스 움직임 확인’ 변수 false로 설정해서 타겟 변경 못하게 설정 - ‘타겟 이동’ 함수 확인 - ‘타겟 토커스 움직임 확인’ 변수가 True인지 확인하고 True라면 타겟 이동을 실행하지 못하게 한다. - ‘타겟 변경’ 함수 호출 전에 ‘타겟 토커스 움직임 확인’ 변수 True로 설정한다.
    //CPP
    bMovingFocus = false;
    
    //타겟 포커스 이동중이라면 실행하지 않는다.
    	CheckTrue(bMovingFocus);
    

무기 시스템 - 워프

워프 액션 입력 및 생성 및준비

  • 크기를 바꿀때 오른쪽에 자물쇠 모양 : 세 축의 크기중 하나만 바꿔도 첫 비율에 맞게 자동으로 다른 크기들을 보정해주는 기능이다.
  • 워프는 무기 장착과는 다른점 : 캐릭터가 액션 입력 방향으로 회전하는것을 허용해야한다.
  • 액션에서 ‘데칼’을 처리한다.
    • Attachment에서 처리해도 되지만, 위치를 구해서 액션을 할것이기 때문에 DoAction의 Tick에서 그것을 처리할 것이다.
  • 파일 생성
    • 콘텐츠 브라우저 - 우클릭 - 기타 - 워프 ‘데이터 에셋’ 생성
    • 콘텐츠 브라우저 - 우클릭 - 블루프린트 - 블루프린트 CAttachment_Warp 생성
    • 데칼용 메테리얼 가져오기 - 메테리얼 인스턴스 생성
    • CDoAction - 우클릭 - 파생 C++ 클래스 생성 - CDoAction_Warp 생성
  • BP_Attachment_Warp
    • 컴포넌트 - 추가 클릭 - ‘데칼 컴포넌트’ 검색 - 디테일 - 지면에 비출것이니 y축 -90도 입력 - 데칼 메테리얼 : 데칼 메테리얼 인스턴스 할당
    • ‘Set Visibility 검색 - ‘데칼 컴포넌트’ 끌어다가 연결 - ‘On Begin Equip’에 보이도록 연결하고, ‘OnUnequip’에는 이전의 Set Visibility 노드 순서 핀에 연결한다.
  • BP_CPlayer
    • WeaponComponent - 디테일 - 데이터 에셋 - 워프 데이터 에셋 할당
  • DA_Warp
    • Attachment Class 할당
    • Equipment Data - ‘컨트롤 회전 사용’ 체크 해제 : 캐릭터의 회전이 마우스 뿐만 아니라 액션 입력 방향으로도 회전할 수 있게 한다.
  • CWeaponComponent
    • 헤더 파일 - ‘워프 모드 설정’ 함수 선언
    //header
    void SetWarpMode();
    
    • CPP 파일 - 기존의 설정 함수를 복붙해서 워프로 바꾼다.
    //CPP
    void UCWeaponComponent::SetWarpMode()
    {
    	CheckFalse(IsIdleMode());
    
    	SetMode(EWeaponType::Warp);
    }
    
  • CPlayer
    • CPP 파일 - 워프 액션 연결
    //CPP
    PlayerInputComponent->BindAction("Warp", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetWarpMode);
    
  • CDoAction_Warp
    • 컴포넌트를 가져오는것은 BeginPlay 함수에서 처리한다.
    • 파생 클래스에서 부모의 함수를 사용하기 위해서 그 함수를 ‘가상화’ 시켜야한다.
    • 헤더 파일 - 생성자 선언 - 데칼 컴포넌트 자료형으로 ‘데칼’ 변수 선언 - 부모에서 가져온 BeginPlay 함수를 오버라이드 한다. : 오너 캐릭터, DoActionData 배열, HitData 배열을 받는다.
    //header
    public:
    	UCDoAction_Warp();
    
    public:
    	void BeginPlay
    	(
    		class ACharacter* InOwner,
    		const TArray<FDoActionData>& InDoActionDatas,
    		const TArray<FHitData>& InHitDatas
    	) override;
    
    private:
    	class UDecalComponent* Decal;
    
    • CPP 파일 - BeginPlay 정의 - 부모 BeginPlay 호출 -

데칼

  • 마법진같은거 그릴때 쓰는 이펙트

기능 설계 팁

  • 하나의 클래스의 이름을 정한다. ⇒ 만들 기능을 하나로 합칠 이름으로 한다.
  • 어떤 기능을 가지고 있는지 쓴다.
  • 이벤트나 델리게이트가 있을 경우 화살표로 어느 것을 연결했는지 연결한다.

'공부 > Unreal' 카테고리의 다른 글

24.08.13  (0) 2024.08.16
24.08.12  (0) 2024.08.16
24.08.08  (0) 2024.08.09
24.08.07  (0) 2024.08.09
24.08.06  (0) 2024.08.09