[UE] 워프 구현하기
마우스가 지정한 위치에 플레이어를 이동하는 워프 스킬을 구현해볼 것이다. 마우스가 가리키는 곳의 위치에 데칼을 표시해준다. 데칼 위치를 받아온 후 마우스 좌클릭을 하면 그 곳으로 이동하는 워프 스킬을 만들어보자.
목차
Plugins |
||||
Weapon |
||||
Resource |
||||
Icon128.png weapon_thumbnail_icon.png |
||||
Source |
||||
Weapon | ||||
SWeaponCheckBoxes.h .cpp SWeaponDetailsView.h .cpp SWeaponDoActionData.h .cpp SWeaponEquipmentData.h .cpp SWeaponHitData.h .cpp SWeaponLeftArea.h .cpp Weapon.Build.cs WeaponAssetEditor.h .cpp WeaponAssetFactory.h .cpp WeaponCommand.h .cpp WeaponContextMenu.h .cpp WeaponModule.h .cpp WeaponStyle.h .cpp |
||||
Source | ||
U2212_06 | ||
Characters | ||
CAnimInstance.h .cpp CEnemy.h .cpp CPlayer.h .cpp ICharacter.h .cpp |
||
Components | ||
CMontagesComponent.h .cpp CMovementComponent.h .cpp CStateComponent.h .cpp CStatusComponent.h .cpp CWeaponComponent.h .cpp |
||
Notifies | ||
CAnimNotifyState_BeginAction.h .cpp CAnimNotify_CameraShake.h .cpp CAnimNotifyState_EndAction.h .cpp CAnimNotify_EndState.h .cpp CAnimNotifyState.h .cpp CAnimNotifyState_CameraAnim.h .cpp CAnimNotifyState_Collision.h .cpp CAnimNotifyState_Combo.h .cpp CAnimNotifyState_Equip.h .cpp CAnimNotifyState_SubAction.h .cpp |
||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Weapons | ||
CAura.h .cpp CCamerModifier.h .cpp CGhostTrail.h .cpp CDoAction_Combo.h .cpp CDoAction_Warp.h .cpp 생성 CSubAction_Fist.h .cpp CSubAction_Hammer.h .cpp CSubAction_Sword.h .cpp CAttachment.h .cpp CDoAction.h .cpp CEquipment.h .cpp CSubAction.h .cpp CWeaponAsset.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp U2212_06.Build.cs |
||
U2212_06.uproject | ||
워프 스킬 구현하기
Warp_Montage 생성
Begin_DoAction과 End_DoAction을 설정해준다.
BP_CAttachment_Warp 생성
블루프린트 클래스 - CAttachment - BP_CAttachment_Warp 생성
Decal를 추가
- 트랜스폼
- 회전: 0.0, -90.0, 0.0 설정
- Decal
- Decal Material: M_Cusor_Inst 설정
- 데칼 크기: 10.0, 64.0, 64.0 설정
Event Graph
CPlayer.cpp - 키 맵핑 (Warp)
CPlayer.cpp
#include "Characters/CPlayer.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/InputComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
#include "Components/CWeaponComponent.h"
ACPlayer::ACPlayer()
{
CHelpers::CreateComponent<USpringArmComponent>(this, &SpringArm, "SpringArm", GetMesh());
CHelpers::CreateComponent<UCameraComponent>(this, &Camera, "Camera", SpringArm);
CHelpers::CreateActorComponent<UCWeaponComponent>(this, &Weapon, "Weapon");
CHelpers::CreateActorComponent<UCMontagesComponent>(this, &Montages, "Montages");
CHelpers::CreateActorComponent<UCMovementComponent>(this, &Movement, "Movement");
CHelpers::CreateActorComponent<UCStateComponent>(this, &State, "State");
GetMesh()->SetRelativeLocation(FVector(0, 0, -90));
GetMesh()->SetRelativeRotation(FRotator(0, -90, 0));
USkeletalMesh* mesh;
CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Mesh/SK_Mannequin.SK_Mannequin'");
GetMesh()->SetSkeletalMesh(mesh);
TSubclassOf<UCAnimInstance> animInstance;
CHelpers::GetClass<UCAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_Character.ABP_Character_C'");
GetMesh()->SetAnimClass(animInstance);
SpringArm->SetRelativeLocation(FVector(0, 0, 140));
SpringArm->SetRelativeRotation(FRotator(0, 90, 0));
SpringArm->TargetArmLength = 200;
SpringArm->bDoCollisionTest = false;
SpringArm->bUsePawnControlRotation = true;
SpringArm->bEnableCameraLag = true;
GetCharacterMovement()->RotationRate = FRotator(0, 720, 0);
}
void ACPlayer::BeginPlay()
{
Super::BeginPlay();
Movement->OnRun(); //Movement의 기본을 Run으로 설정
Movement->DisableControlRotation();//Movement의 기본을 DisableControlRotation으로 설정
State->OnStateTypeChanged.AddDynamic(this, &ACPlayer::OnStateTypeChanged);
}
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
PlayerInputComponent->BindAxis("MoveForward", Movement, &UCMovementComponent::OnMoveForward);
PlayerInputComponent->BindAxis("MoveRight", Movement, &UCMovementComponent::OnMoveRight);
PlayerInputComponent->BindAxis("VerticalLook", Movement, &UCMovementComponent::OnVerticalLook);
PlayerInputComponent->BindAxis("HorizontalLook", Movement, &UCMovementComponent::OnHorizontalLook);
PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Pressed, Movement, &UCMovementComponent::OnSprint);
PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Released, Movement, &UCMovementComponent::OnRun);
PlayerInputComponent->BindAction("Avoid", EInputEvent::IE_Pressed, this, &ACPlayer::OnAvoid);
PlayerInputComponent->BindAction("Fist", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetFistMode);
PlayerInputComponent->BindAction("Sword", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetSwordMode);
PlayerInputComponent->BindAction("Hammer", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetHammerMode);
PlayerInputComponent->BindAction("Warp", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetWarpMode);
PlayerInputComponent->BindAction("Action", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::DoAction);
PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SubAction_Pressed);
PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, Weapon, &UCWeaponComponent::SubAction_Released);
}
void ACPlayer::OnStateTypeChanged(EStateType InPrevType, EStateType InNewType)
{
switch (InNewType)
{
case EStateType::BackStep: BackStep(); break;
}
}
void ACPlayer::OnAvoid()
{
CheckFalse(State->IsIdleMode());
CheckFalse(Movement->CanMove());
CheckTrue(InputComponent->GetAxisValue("MoveForward") >= 0.0f);//뒷방향을 입력했다면
State->SetBackStepMode();//State을 BackStepMode로 변경한다.
}
void ACPlayer::BackStep()
{
Movement->EnableControlRotation();//정면을 바라본 상태로 뒤로 뛰어야하기 때문에 EnableControlRotation으로 만들어준다.
Montages->PlayBackStepMode();//PlayBackStepMode()를 통해 몽타주 재생.
}
void ACPlayer::End_BackStep()
{
Movement->DisableControlRotation();//Backstep이 끝나면 원래대로 돌려준다.
State->SetIdleMode();//Idle상태로 돌려줌.
}
키 맵핑 void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
- PlayerInputComponent->BindAction("Warp", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetWarpMode);
CDoAction.h
CDoAction.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Weapons/CWeaponStructures.h"
#include "CDoAction.generated.h"
UCLASS(Abstract)//DoAction 그 자체로는 객체화되면 안 되기 때문에 Abstract을 붙여준다.
class U2212_06_API UCDoAction : public UObject
{
GENERATED_BODY()
public:
UCDoAction();
virtual void BeginPlay //재정의 할 수 있도록 virtual로 만든다.
(
class ACAttachment* InAttachment,
class UCEquipment* InEquipment,
class ACharacter* InOwner,
const TArray<FDoActionData>& InDoActionDatas,//CWeaponStucture내의 FDoActionData
const TArray<FHitData>& InHitDatas //CWeaponStucture내의 FHitData
);
virtual void Tick(float InDeltaTime) { }
public:
//재정의 할 수 있도록 virtual로 만든다.
virtual void DoAction();
virtual void Begin_DoAction();
virtual void End_DoAction();
public:
UFUNCTION()
virtual void OnAttachmentBeginCollision() {}
UFUNCTION()
virtual void OnAttachmentEndCollision() {}
UFUNCTION()
virtual void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther) { }
UFUNCTION()
virtual void OnAttachmentEndOverlap(class ACharacter* InAttacker, class ACharacter* InOther) { }
protected:
bool bInAction;
bool bBeginAction;
class ACharacter* OwnerCharacter;
class UWorld* World;
class UCMovementComponent* Movement;
class UCStateComponent* State;
TArray<FDoActionData> DoActionDatas;
TArray<FHitData> HitDatas;
};
CDoAction_Warp에서 재정의 할 수 있도록 상위 클래스인 CDoAction에서 Tick 함수를 만든다.
- virtual void Tick(float InDeltaTime) { }
변수 추가
- bool bInAction;
- Action이 들어왔는지 true, false 체크해주는 변수를 추가한다.
CDoAction.cpp
#include "Weapons/CDoAction.h"
#include "Global.h"
#include "CAttachment.h"
#include "CEquipment.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
UCDoAction::UCDoAction()
{
}
void UCDoAction::BeginPlay(ACAttachment* InAttachment, UCEquipment* InEquipment, ACharacter* InOwner, const TArray<FDoActionData>& InDoActionDatas, const TArray<FHitData>& InHitDatas)
{
OwnerCharacter = InOwner;
World = OwnerCharacter->GetWorld();
State = CHelpers::GetComponent<UCStateComponent>(OwnerCharacter);
Movement = CHelpers::GetComponent<UCMovementComponent>(OwnerCharacter);
DoActionDatas = InDoActionDatas;
HitDatas = InHitDatas;
}
void UCDoAction::DoAction()
{
bInAction = true;
State->SetActionMode();
}
void UCDoAction::Begin_DoAction()
{
bBeginAction = true;
}
void UCDoAction::End_DoAction()
{
bInAction = false;
bBeginAction = false;
State->SetIdleMode();
Movement->Move();
Movement->DisableFixedCamera();
}
추가한 bInAction 변수를 DoAction()과 End_DoAction()에 넣어 Action의 시작과 끝을 알려준다.
- void UCDoAction::DoAction()
- bInAction = true;
- void UCDoAction::End_DoAction()
- bInAction = false;
CWeaponComponent.cpp - Tick 함수 추가
CWeaponComponent.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CWeaponComponent.generated.h"
UENUM(BlueprintType)
enum class EWeaponType : uint8
{
Fist, Sword, Hammer, Warp, Around, Bow, Max,
};
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FWeaponTypeChanged, EWeaponType, InPrevType, EWeaponType, InNewType);
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class U2212_06_API UCWeaponComponent : public UActorComponent
{
GENERATED_BODY()
private://DataAsset을 받아온다.
UPROPERTY(EditAnywhere, Category = "DataAsset")
class UCWeaponAsset* DataAssets[(int32)EWeaponType::Max];
public: //무기 Type이 맞는지 확인해주는 함수들
FORCEINLINE bool IsUnarmedMode() { return Type == EWeaponType::Max; }
FORCEINLINE bool IsFistMode() { return Type == EWeaponType::Fist; }
FORCEINLINE bool IsSwordMode() { return Type == EWeaponType::Sword; }
FORCEINLINE bool IsHammerMode() { return Type == EWeaponType::Hammer; }
FORCEINLINE bool IsWarpMode() { return Type == EWeaponType::Warp; }
FORCEINLINE bool IsAroundMode() { return Type == EWeaponType::Around; }
FORCEINLINE bool IsBowMode() { return Type == EWeaponType::Bow; }
public:
UCWeaponComponent();
protected:
virtual void BeginPlay() override;
public:
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
private:
bool IsIdleMode();//StateComponent, WeaponComponent 둘 다 같은 레벨이다. 서로 소유할 수 없는 관계이기 때문에 참조만해서 리턴받기 위해 IsIdleMode를 사용한다.
public:
class ACAttachment* GetAttachment();
class UCEquipment* GetEquipment();
class UCDoAction* GetDoAction();
class UCSubAction* GetSubAction();
public: //무기 세팅
void SetUnarmedMode();
void SetFistMode();
void SetSwordMode();
void SetHammerMode();
void SetWarpMode();
void SetAroundMode();
void SetBowMode();
void DoAction();
void SubAction_Pressed();
void SubAction_Released();
private:
void SetMode(EWeaponType InType);
void ChangeType(EWeaponType InType);
public: //무기가 바뀌었을때 통보해줄 delegate
FWeaponTypeChanged OnWeaponTypeChange;
private:
class ACharacter* OwnerCharacter;
EWeaponType Type = EWeaponType::Max;
};
변경사항 없음.
CWeaponComponent.cpp
#include "Components/CWeaponComponent.h"
#include "Global.h"
#include "CStateComponent.h"
#include "GameFramework/Character.h"
#include "Weapons/CWeaponAsset.h"
#include "Weapons/CAttachment.h"
#include "Weapons/CEquipment.h"
#include "Weapons/CDoAction.h"
#include "Weapons/CSubAction.h"
UCWeaponComponent::UCWeaponComponent()
{
//Tick을 실행시켜주는 코드
PrimaryComponentTick.bCanEverTick = true;
}
void UCWeaponComponent::BeginPlay()
{
Super::BeginPlay();
OwnerCharacter = Cast<ACharacter>(GetOwner());
for (int32 i=0; i < (int32)EWeaponType::Max; i++)
{
if (!!DataAssets[i]) //DataAssets[i]이 있다면(=무기가 할당되어 있다면)
DataAssets[i]->BeginPlay(OwnerCharacter);//BeginPla y 시 OwnerCharacter에 Spawn시켜준다.
}
}
void UCWeaponComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (!!GetDoAction())//DoAction이 있다면
GetDoAction()->Tick(DeltaTime);//DoAction의 Tick을 콜 해준다.
if (!!GetSubAction())//SubAction이 있다면
GetSubAction()->Tick(DeltaTime);//SubAction의 Tick을 콜 해준다.
}
bool UCWeaponComponent::IsIdleMode()
{
return CHelpers::GetComponent<UCStateComponent>(OwnerCharacter)->IsIdleMode();
}
ACAttachment* UCWeaponComponent::GetAttachment()
{
CheckTrueResult(IsUnarmedMode(), nullptr);
CheckFalseResult(!!DataAssets[(int32)Type], nullptr);
return DataAssets[(int32)Type]->GetAttachment();
}
UCEquipment* UCWeaponComponent::GetEquipment()
{
CheckTrueResult(IsUnarmedMode(), nullptr);
CheckFalseResult(!!DataAssets[(int32)Type], nullptr);
return DataAssets[(int32)Type]->GetEquipment();
}
UCDoAction* UCWeaponComponent::GetDoAction()
{
CheckTrueResult(IsUnarmedMode(), nullptr);
CheckFalseResult(!!DataAssets[(int32)Type], nullptr);
return DataAssets[(int32)Type]->GetDoAction();
}
UCSubAction* UCWeaponComponent::GetSubAction()
{
CheckTrueResult(IsUnarmedMode(), nullptr);
CheckFalseResult(!!DataAssets[(int32)Type], nullptr);
return DataAssets[(int32)Type]->GetSubAction();
}
void UCWeaponComponent::SetUnarmedMode()
{
GetEquipment()->Unequip();
ChangeType(EWeaponType::Max);
}
void UCWeaponComponent::SetFistMode()
{
CheckFalse(IsIdleMode());
SetMode(EWeaponType::Fist);
}
void UCWeaponComponent::SetSwordMode()
{
CheckFalse(IsIdleMode());
SetMode(EWeaponType::Sword);
}
void UCWeaponComponent::SetHammerMode()
{
CheckFalse(IsIdleMode());
SetMode(EWeaponType::Hammer);
}
void UCWeaponComponent::SetWarpMode()
{
CheckFalse(IsIdleMode());
SetMode(EWeaponType::Warp);
}
void UCWeaponComponent::SetAroundMode()
{
CheckFalse(IsIdleMode());
SetMode(EWeaponType::Around);
}
void UCWeaponComponent::SetBowMode()
{
CheckFalse(IsIdleMode());
SetMode(EWeaponType::Bow);
}
void UCWeaponComponent::SetMode(EWeaponType InType)
{
if (Type == InType)
{
SetUnarmedMode();
return;
}
else if (IsUnarmedMode() == false)
{
GetEquipment()->Unequip();
}
if (!!DataAssets[(int32)InType])
{
DataAssets[(int32)InType]->GetEquipment()->Equip();
ChangeType(InType);
}
}
void UCWeaponComponent::ChangeType(EWeaponType InType)
{
EWeaponType prevType = Type;
Type = InType;
if (OnWeaponTypeChange.IsBound())
OnWeaponTypeChange.Broadcast(prevType, InType);
}
void UCWeaponComponent::DoAction()
{
if (!!GetDoAction())
GetDoAction()->DoAction();
}
void UCWeaponComponent::SubAction_Pressed()
{
if (!!GetSubAction())
GetSubAction()->Pressed();
}
void UCWeaponComponent::SubAction_Released()
{
if (!!GetSubAction())
GetSubAction()->Released();
}
Tick함수에서 DoAction이 있다면 DoAction의 Tick을 콜 해준다.
- void UCWeaponComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
- if (!!GetDoAction())
GetDoAction()->Tick(DeltaTime);
- if (!!GetDoAction())
CDoAction_Warp 생성
CDoAction_Warp.h
#pragma once
#include "CoreMinimal.h"
#include "Weapons/CDoAction.h"
#include "CDoAction_Warp.generated.h"
UCLASS(Blueprintable)
class U2212_06_API UCDoAction_Warp : public UCDoAction
{
GENERATED_BODY()
public:
UCDoAction_Warp();
virtual void BeginPlay
(
class ACAttachment* InAttachment,
class UCEquipment* InEquipment,
class ACharacter* InOwner,
const TArray<FDoActionData>& InDoActionData,
const TArray<FHitData>& InHitData
);
void Tick(float InDeltaTime) override;
public:
void DoAction() override;
void Begin_DoAction() override;
private:
bool GetCursorLocationAndRotation(FVector& OutLocation, FRotator& OutRotation);
private:
class APlayerController* PlayerController;
class UDecalComponent* Decal;
private:
FVector MoveToLocation;
};
블루프린트로 만들 수 있게 Blueprintable를 적어준다.
- UCLASS(Blueprintable)
CDoAction_Warp.cpp
#include "Weapons/DoActions/CDoAction_Warp.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerController.h"
#include "Components/CStateComponent.h"
#include "Components/DecalComponent.h"
#include "Components/CapsuleComponent.h"
#include "Weapons/CAttachment.h"
UCDoAction_Warp::UCDoAction_Warp()
{
}
void UCDoAction_Warp::BeginPlay(ACAttachment* InAttachment, UCEquipment* InEquipment, ACharacter* InOwner, const TArray<FDoActionData>& InDoActionData, const TArray<FHitData>& InHitData)
{
Super::BeginPlay(InAttachment, InEquipment, InOwner, InDoActionData, InHitData);
Decal = CHelpers::GetComponent<UDecalComponent>(InAttachment);
PlayerController = OwnerCharacter->GetController<APlayerController>();
}
void UCDoAction_Warp::Tick(float InDeltaTime)
{
Super::Tick(InDeltaTime);
FVector location = FVector::ZeroVector;
FRotator rotation = FRotator::ZeroRotator;
//GetCursorLocationAndRotation이 false면 hit가 안 된 것이다.
if (GetCursorLocationAndRotation(location, rotation) == false)
{
Decal->SetVisibility(false);
return;
}
//Warp 실행 중에는 Cursor가 움직이지 않도록 만든다.
if (bInAction)//Action이 실행중이라면 실행을 할 필요가 없으므로
return;//리턴
Decal->SetVisibility(true);
//Decal이 그려지는 위치와 회전값을 설정해준다.
Decal->SetWorldLocation(location);
Decal->SetWorldRotation(rotation);
}
void UCDoAction_Warp::DoAction()
{
CheckFalse(DoActionDatas.Num() > 0);
CheckFalse(State->IsIdleMode());
Super::DoAction();
FRotator rotation;
if (GetCursorLocationAndRotation(MoveToLocation, rotation))
{
//땅에 뭍히는것을 방지하기 위해 CapsuleHalfHeight만큼 높이를 보정해준다.
float height = OwnerCharacter->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
MoveToLocation = FVector(MoveToLocation.X, MoveToLocation.Y, MoveToLocation.Z + height);
float yaw = UKismetMathLibrary::FindLookAtRotation(OwnerCharacter->GetActorLocation(), MoveToLocation).Yaw;
OwnerCharacter->SetActorRotation(FRotator(0, yaw, 0));
}
else
return;
DoActionDatas[0].DoAction(OwnerCharacter);
}
void UCDoAction_Warp::Begin_DoAction()
{
Super::Begin_DoAction();
OwnerCharacter->SetActorLocation(MoveToLocation);//DoAction에서 설정한 MoveToLocation 위치로 이동한다.
MoveToLocation = FVector::ZeroVector;//이동 후에 MoveToLocation 위치를 ZeroVector로 초기화해준다.
}
bool UCDoAction_Warp::GetCursorLocationAndRotation(FVector& OutLocation, FRotator& OutRotation)
{
CheckNullResult(PlayerController, false);//PlayerController가 없으면 실행하면 안 되니 체크해준다.
FHitResult hitResult;
PlayerController->GetHitResultUnderCursorByChannel(ETraceTypeQuery::TraceTypeQuery1, false, hitResult);
CheckFalseResult(hitResult.bBlockingHit, false);//부딪히는게 없다면 false 리턴.
OutLocation = hitResult.Location;//hit된 위치
OutRotation = hitResult.ImpactNormal.Rotation();//hit된 Normal의 회전값
return true;
}
BP_CDoAction_Warp
CDoAction_Warp 기반 블루프린트 클래스 생성 - BP_CDoAction_Warp 생성
DA_Warp 생성
DA_Warp 생성
BP_CPlayer - Weapon에 DA_Warp 할당하기
BP_CPlayer
실행화면
'⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글
[UE] Around 공격 구현하기 (0) | 2023.07.03 |
---|---|
[UE] 워프 Top View 만들기 (0) | 2023.06.30 |
[UE] 해머 스킬 만들기 (0) | 2023.06.27 |
[UE] 일섬 스킬 충돌, 해머 스킬 만들기 (0) | 2023.06.26 |
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기 (0) | 2023.06.23 |
댓글
이 글 공유하기
다른 글
-
[UE] Around 공격 구현하기
[UE] Around 공격 구현하기
2023.07.03 -
[UE] 워프 Top View 만들기
[UE] 워프 Top View 만들기
2023.06.30 -
[UE] 해머 스킬 만들기
[UE] 해머 스킬 만들기
2023.06.27 -
[UE] 일섬 스킬 충돌, 해머 스킬 만들기
[UE] 일섬 스킬 충돌, 해머 스킬 만들기
2023.06.26