[ 충돌 ]
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-콜리전
// Object Channels : 오브젝트에 관한 충돌처리.
// Trace Channels : 카메라와 플레이어를 잇는 직선 사이에 부딪히는 물체를 처리.
// Preset : 프로파일
// 충돌체들마다 사용하는 프로파일을 가지게 됨.
// 프로파일-BlockAll : 모든 물체와 블록 처리를 함.
// 프로파일-콜리전 켜짐-No Collision : 충돌 안함.
// 프로파일-콜리전 켜짐-Query Only(No Physics Collision)
// 프로파일-콜리전 켜짐-Physics Only(No Query Collision) : 물리적 처리만.
// 프로파일-콜리전 켜짐-Collision Enabled(Query and Physics) : 둘 다 처리.
// 프로파일-오브젝트 유형 : 이 프로파일이 기본으로 사용하는 채널.
// 프로파일-콜리전 반응-무시
// 프로파일-콜리전 반응-겹침 : 뚫고 지나갈 수 있음.
// 프로파일-콜리전 반응-블록 : 뚫고 지나가지 못함.
// 프로파일-트레이스 유형 : 다른 채널과 충돌처리를 어떻게 할 것인지 설정.
// C++ -> Config -> DefaultEngine.ini : 에디터의 설정 정보들이 들어가는 곳.
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-콜리전 -> Object Channels -> 새 오브젝트 채널-이름 : "PlayerAttack" 기본 반응 : "Ignore"
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-콜리전 -> Object Channels -> 새 오브젝트 채널-이름 : "Player" 기본 반응 : "Block"
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-콜리전 -> Object Channels -> 새 오브젝트 채널-이름 : "Monster" 기본 반응 : "Block"
// Preset이 모두 블록으로 표시됨.
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-콜리전 -> Preset -> 새 프로파일-이름 : "Player" 콜리전 켜짐 : "Collision Enabled" 오브젝트 유형 : "Player" 오브젝트 유형 : "PlayerAttack : 무시 / Player, Monster : 겹침 / 나머지 : 블록"
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-콜리전 -> Preset -> 새 프로파일-이름 : "Monster" 콜리전 켜짐 : "Collision Enabled" 오브젝트 유형 : "Monster" 오브젝트 유형 : "PlayerAttack, Player, Monster : 겹침 / 나머지 : 블록"
// 몬스터끼리 겹칠 때 해결방법 - 집단행동 알고리즘 사용. (일정 반경안에 부딪히지 않는 위치를 파악)
// 또는 "겹침" 사용.
(언리얼 에디터) 세팅 -> 프로젝트 세팅 -> 엔진-콜리전 -> Preset -> 새 프로파일-이름 : "PlayerAttack" 콜리전 켜짐 : "Collision Enabled" 오브젝트 유형 : "PlayerAttack" 오브젝트 유형 : "PlayerAttack : 무시 / Monster : 겹침 / 나머지 : 블록"
(언리얼 에디터) Preset -> BlockAll -> 오브젝트 유형 : "PlayerAttack : 무시 / 나머지 : 블록"
(언리얼 에디터) Preset -> OverlapAll -> 오브젝트 유형 : "PlayerAttack : 무시 / 나머지 : 겹침"
(언리얼 에디터) Preset -> OverlapAllDynamic -> 오브젝트 유형 : "PlayerAttack : 무시 / 나머지 : 겹침"
(언리얼 에디터) Preset -> IgnoreOnlyPawn -> 오브젝트 유형 : "Pawn, Vehicle, PlayerAttack, Player, Monster : 무시 / 나머지 : 블록"
(언리얼 에디터) Preset -> OverlapOnlyPawn -> 오브젝트 유형 : "PlayerAttack : 무시 / Pawn, Vehicle, Player, Monster : 겹침 / 나머지 : 블록"
(언리얼 에디터) Preset -> OverlapAll -> 오브젝트 유형 : "PlayerAttack : 무시 / 나머지 : 겹침"
- 충돌체 만들기 -
(언리얼 에디터-BPPlayerWukong) Mesh -> 디테일-콜리전-Can Character Step Up On ... : "No"
(언리얼 에디터-BPPlayerWukong) WeaponBox -> 디테일-콜리전-Can Character Step Up On ... : "No"
// Simulation Genertates Hit Events : hit 이벤트를 발생시킬 것인지.
// Generate Overlap Events : 겹침 처리를 할 때. 두 오브젝트 모두 true로 설정되면 오버랩으로 등록됨.
// Phys Material Override : 어떤 재질인지 구분하기 위해. 물리적인 처리를 하기 위한 재질.
- 충돌 체크 -
(언리얼 에디터-BPWukongAnim) Ground -> Ground -> NormalAttack -> Attack1
(언리얼 에디터-BPWukongAnim) Primary_Melee_A_Slow
(언리얼 에디터-Primary_Melee_A_Slow) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "AttackStart"
(언리얼 에디터-BPWukongAnim) Ground -> Ground -> NormalAttack -> Attack2
(언리얼 에디터-BPWukongAnim) Primary_Melee_B_Slow
(언리얼 에디터-Primary_Melee_B_Slow) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "AttackStart"
(언리얼 에디터-BPWukongAnim) Ground -> Ground -> NormalAttack -> Attack3
(언리얼 에디터-BPWukongAnim) Primary_Melee_C_Slow
(언리얼 에디터-Primary_Melee_C_Slow) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "AttackStart"
(언리얼 에디터-BPWukongAnim) Ground -> Ground -> NormalAttack -> Attack4
(언리얼 에디터-BPWukongAnim) Primary_Melee_D_Slow
(언리얼 에디터-Primary_Melee_D_Slow) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "AttackStart"
(언리얼 에디터-BPWukongAnim) Ground -> Ground -> NormalAttack -> Attack5
(언리얼 에디터-BPWukongAnim) Primary_Melee_E_Slow
(언리얼 에디터-Primary_Melee_E_Slow) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "AttackStart"
(언리얼 에디터-BPWukongAnim) Ground -> Ground -> NormalAttack -> Attack5
(언리얼 에디터-BPWukongAnim) Primary_Melee_E_Slow
(언리얼 에디터-Primary_Melee_E_Slow) 원하는 위치_노티파이 부분_우클릭_노티파이 추가-새 노티파이 : "AttackEnd"
- 로그 -
(언리얼 에디터) 창 -> 개발자 툴-출력 로그
- 데미지 처리 -
// BPMinionAnim
(언리얼 에디터-BPMinionAnim) Ground -> Idle : "Ground"로 바꿈.
(언리얼 에디터-BPMinionAnim) Ground -> Ground
(언리얼 에디터-BPMinionAnim) 우클릭_"Get Anim Type" -> "블렌드 포즈(EMinionAnim)" -> 우클릭_"Idle" "Run" "Attack" "Hit" "Death" 추가
(언리얼 에디터-BPMinionAnim) 블렌드 포즈(EMinionAnim)와 출력 애니메이션 포즈 Result와 연결
(언리얼 에디터-BPMinionAnim) 에셋 브라우저 : "Idle_A" -> Idle_A와 디폴트 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionAnim) 에셋 브라우저 : "Idle_A" -> Idle_A와 Idle 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionAnim) 에셋 브라우저 : "Jog_Fwd_Combat_A" -> Jog_Fwd_Combat_A와 Run 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionAnim) 에셋 브라우저 : "Attack_A" -> Attack_A와 Attack 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionAnim) 에셋 브라우저 : "HitReact_Front" -> HitReact_Front와 Hit 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionAnim) 에셋 브라우저 : "Death_A" -> Death_A와 Death 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
// BPMinionRangerAnim
(언리얼 에디터-BPMinionRangerAnim) Ground -> Idle : "Ground"로 바꿈.
(언리얼 에디터-BPMinionRangerAnim) Ground -> Ground
(언리얼 에디터-BPMinionRangerAnim) 우클릭_"Get Anim Type" -> "블렌드 포즈(EMinionAnim)" -> 우클릭_"Idle" "Run" "Attack" "Hit" "Death" 추가
(언리얼 에디터-BPMinionRangerAnim) 블렌드 포즈(EMinionRangerAnim)와 출력 애니메이션 포즈 Result와 연결
(언리얼 에디터-BPMinionRangerAnim) 에셋 브라우저 : "Idle_A" -> Idle_A와 디폴트 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionRangerAnim) 에셋 브라우저 : "Idle_A" -> Idle_A와 Idle 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionRangerAnim) 에셋 브라우저 : "Jog_Fwd_Combat_A" -> Jog_Fwd_Combat_A와 Run 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionRangerAnim) 에셋 브라우저 : "Attack_A" -> Attack_A와 Attack 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionRangerAnim) 에셋 브라우저 : "HitReact_Front" -> HitReact_Front와 Hit 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
(언리얼 에디터-BPMinionRangerAnim) 에셋 브라우저 : "Death_A" -> Death_A와 Death 포즈 연결 -> 디테일-세팅-Loop Animation : "끔"
// 디테일-Can be Damaged : false로 되어있으면, 부모에서 최종 데미지의 값이 0으로 나옴.
(언리얼 에디터-BPPlayerWukong) WeaponBox -> 디테일-콜리전-Collision Presets : "Custom" Collision Enabled : "No Collision"
(언리얼 에디터-BPPlayerWukong) WeaponBox -> 디테일-콜리전-Collision Presets : "PlayerAttack"
(언리얼 에디터-BPPlayerWukong) WeaponBox -> 이벤트-On Component Hit
(언리얼 에디터-BPPlayerWukong) 우클릭_Print String -> On Component Hit(WeaponBox)와 연결
(언리얼 에디터-BPMinions) CapsuleComponent -> 디테일-피직스-Simulate Physics : "체크"
// 스태틱 메쉬 만들기.
(언리얼 에디터) 콘텐츠 -> InfinityBladeWrapons -> Weapons -> Blade -> Swords -> Blade_BlackKnight -> SK_Blade_BlasckKinght
(언리얼 에디터-SK_Blade_BlasckKinght) 스태틱 메쉬 만들기 -> 위치 : "Meshes" 이름 : "BladeMesh"
- 충돌 체크 버그 해결 -
(언리얼 에디터-BPPlayerWukong) WeaponBox -> 디테일-Shape-Box Extent-X : "120.0" Y : "10.0" Z : "10.0"
(언리얼 에디터-BPPlayerWukong) WeaponBox -> 디테일-콜리전-Collision Presets : "PlayerAttack"
[ 파티클 ]
(에픽 게임즈 런처) "Infinity Blade:Effects" 프로젝트에 추가
(언리얼 에디터) 신규 추가-새폴더 : "Effect"
(언리얼 에디터) C++클래스 -> 우클릭_새 C++클래스 추가 -> 부모 클래스 : "Actor" -> 이름 : "EffectDestroy"
[ 소리 ]
언리얼에서 기본적으로 제공하는 오디오 포맷은 wav파일.
프로젝트 파일 -> Content -> Effect에 파일 넣어서 사용.
(C++-PlayerWukong.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "PlayerCharacter.h"
#include "PlayerWukong.generated.h"
/**
*
*/
UCLASS()
class PROJECT1005_API APlayerWukong : public APlayerCharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
APlayerWukong();
protected:
// UPROPERTY : 사용하지 않으면 언리얼 에디터에 공개가 되지 않음. 내부적인 변수로 사용할 수 있음.
// 언리얼 에디터에 연결하여 사용하려면 변수를 선언하기 전에 프로퍼티로 변수의 속성을 지정해줘야 함.
// Category : Camera로 설정.
// VisibleAnywhere : 다 보이지만 편집을 할 수 없음.
// EditAnywhere : 에디터에서도 편집 가능.
UPROPERTY(Category = Camera, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
UCameraComponent* Camera;
UPROPERTY(Category = Camera, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
USpringArmComponent* Arm;
UPROPERTY(Category = Collision, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
UBoxComponent* WeaponBox;
class UWukongAnim* WukongAnim; // 포인터 변수 선언.
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser);
private:
void MoveFront(float fScale); // 앞뒤로 이동.
void MoveSide(float fScale); // 좌우로 이동.
void RotationZ(float fScale); // 회전.
void JumpKey(); // 점프.
void NormalAttack(); // 공격.
void QuickSlot1();
void QuickSlot2();
void QuickSlot3();
public:
void EnableWeaponCollision(bool bEnable);
public:
virtual void NotifyHit(class UPrimitiveComponent* MyComp, AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit);
UFUNCTION()
void OnHit(UPrimitiveComponent* HitCom, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& result);
UFUNCTION()
void WeaponBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void WeaponEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
(C++-PlayerWukong.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerWukong.h"
#include "WukongAnim.h"
#include "Weapon.h"
#include "EffectDestroy.h"
#include "DrawDebugHelpers.h" // 디버깅 용도의 출력 기능.
// Sets default values
APlayerWukong::APlayerWukong()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); // 카메라 컴포넌트 생성. 생성자에서 생성해야 함.
Arm = CreateDefaultSubobject<USpringArmComponent>(TEXT("Arm")); // Sprint Arm 컴포넌트 생성.
// 셀카봉 같은 느낌.
Arm->SetupAttachment(GetMesh()); // Arm의 부로모 Mesh를 지정.
Camera->SetupAttachment(Arm); // 카메라의 부모로 Arm을 지정.
// 애니메이션 클래스 지정.
static ConstructorHelpers::FClassFinder<UWukongAnim> AnimAsset(TEXT("AnimBlueprint'/Game/Player/BPWukongAnim.BPWukongAnim_C'"));
if (AnimAsset.Succeeded())
GetMesh()->SetAnimInstanceClass(AnimAsset.Class);
Weapon = nullptr;
// 점프의 속도 조절.
// GetCharacterMovement()->JumpZVelocity // JumpZVelocity : 위로 올라가는 속도.
// 원하는 프로파일 세팅.
GetCapsuleComponent()->SetCollisionProfileName(TEXT("Player"));
WeaponBox = CreateDefaultSubobject<UBoxComponent>(TEXT("WeaponBox"));
WeaponBox->SetupAttachment(GetMesh(), TEXT("FX_Staff_Mid"));
WeaponBox->SetCollisionProfileName(TEXT("PlayerAttack"));
WeaponBox->SetBoxExtent(FVector(120.f, 10.f, 10.f)); // 박스의 크기 설정.
}
// Called when the game starts or when spawned
void APlayerWukong::BeginPlay()
{
Super::BeginPlay(); // 이 액터가 레벨에 입장할 때 배치되고 게임이 시작할 때 딱 한 번만 호출됨.
WukongAnim = Cast<UWukongAnim>(GetMesh()->GetAnimInstance()); // WraithAnim을 받아옴.
// 기본 무기 설정.
// GetWorld() : 월드 객체를 얻어올 수 있음. 액터를 월드에 배치할 때 사용.
// AlwaysSpawn : 무조건 생성.
// AdjustIfPossibleButAlwaysSpawn : 충돌되었을 때 충돌되지 않는 위치를 찾아 스폰하는 것.
// AdjustIfPossibleButDontSpawnIfColliding : 충돌안될 때만 스폰.
FActorSpawnParameters params;
params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
Weapon = GetWorld()->SpawnActor<AWeapon>(FVector::ZeroVector, FRotator::ZeroRotator, params);
// AttachToActor : 지정된 액터의 루트 컴포넌트에 붙게 됨.
// AttachToComponent : 원하는 컴포넌트 지정 가능.
// KeepRelativeTransform : 상대적인 정보를 그대로 유지.
// KeepWorldTransform : 월드 정보를 그대로 유지.
Weapon->AttachToComponent(GetMesh(), FAttachmentTransformRules::KeepRelativeTransform, TEXT("weapon_l_socket"));
Weapon->LoadMesh(TEXT("SkeletalMesh'/Game/InfinityBladeWeapons/Weapons/Blade/Swords/Blade_BlackKnight/SK_Blade_BlackKnight.SK_Blade_BlackKnight'"));
// 겹침이 시작될 때 1번만 호출.
WeaponBox->OnComponentBeginOverlap.AddDynamic(this, &APlayerWukong::WeaponBeginOverlap);
// 겹침이 되다가 빠져나갈 때 호출.
WeaponBox->OnComponentEndOverlap.AddDynamic(this, &APlayerWukong::WeaponEndOverlap);
// WeaponBox->OnComponentHit.AddDynamic(this, &APlayerWukong::OnHit);
WeaponBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
// Called every frame
void APlayerWukong::Tick(float DeltaTime)
{
Super::Tick(DeltaTime); // 게임이 동작되는 매프레임마다 호출되는 함수.
}
// Called to bind functionality to input
// UInputComponent : 입력받은 것을 연결해서 호출해줄 함수를 연결하는 바인딩 역할을 함.
void APlayerWukong::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent); // 플레이어 컨트롤러가 빙의가 된 후에 호출.
// 언리얼은 유니코드 문자열을 사용하기 때문에 TEXT("")를 사용해야 함.
// this : 어떤 객체를 쓸 것인지.
PlayerInputComponent->BindAxis(TEXT("MoveFront"), this, &APlayerWukong::MoveFront);
PlayerInputComponent->BindAxis(TEXT("MoveSide"), this, &APlayerWukong::MoveSide);
PlayerInputComponent->BindAxis(TEXT("RotationZ"), this, &APlayerWukong::RotationZ);
// EInputEvent::IE_Pressed : 눌렀을 때.
// EInputEvent::IE_Released : 눌렀다가 뗐을 때.
PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &APlayerWukong::JumpKey);
PlayerInputComponent->BindAction(TEXT("NormalAttack"), EInputEvent::IE_Pressed, this, &APlayerWukong::NormalAttack);
PlayerInputComponent->BindAction(TEXT("QuickSlot1"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot1);
PlayerInputComponent->BindAction(TEXT("QuickSlot2"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot2);
PlayerInputComponent->BindAction(TEXT("QuickSlot3"), EInputEvent::IE_Pressed, this, &APlayerWukong::QuickSlot3);
}
float APlayerWukong::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float fDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
return fDamage;
}
void APlayerWukong::MoveFront(float fScale) // 앞뒤로 이동.
{
if (!bStartAnimation)
return;
// GetActorForwardVector()와 fScale을 곱함.
// fScale이 0이면 움직이지 않고, 1이면 앞으로, -1이면 뒤로 가게 됨.
AddMovementInput(GetActorForwardVector(), fScale);
if (IsValid(WukongAnim)) // AnimInstance가 있을 때.
{
if (fScale > 0.f) // 앞으로.
WukongAnim->SetMoveDir(EDir::Front);
else if (fScale < 0.f) // 뒤로.
WukongAnim->SetMoveDir(EDir::Back);
}
}
void APlayerWukong::MoveSide(float fScale) // 좌우로 이동.
{
if (!bStartAnimation)
return;
// GetActorRightVector()와 fScale을 곱함.
// fScale이 0이면 움직이지 않고, 1이면 오른쪽으로, -1이면 왼쪽으로 가게 됨.
AddMovementInput(GetActorRightVector(), fScale);
if (IsValid(WukongAnim)) // AnimInstance가 있을 때.
{
if (fScale > 0.f) // 오른쪽으로.
WukongAnim->SetMoveDir(EDir::Right);
else if (fScale < 0.f) // 왼쪽으로.
WukongAnim->SetMoveDir(EDir::Left);
}
}
void APlayerWukong::RotationZ(float fScale) // 회전.
{
if (!bStartAnimation)
return;
AddControllerYawInput(fScale);
}
void APlayerWukong::JumpKey() // 점프.
{
if (!bStartAnimation)
return;
if (IsValid(WukongAnim))
WukongAnim->Jump();
Jump(); // Jump를 지원해줌.
}
void APlayerWukong::NormalAttack() // 공격.
{
if (!bStartAnimation)
return;
if (IsValid(WukongAnim))
WukongAnim->NormalAttack();
}
void APlayerWukong::QuickSlot1()
{
if (!bStartAnimation)
return;
if (IsValid(WukongAnim))
WukongAnim->Skill1();
}
void APlayerWukong::QuickSlot2()
{
if (!bStartAnimation)
return;
}
void APlayerWukong::QuickSlot3()
{
if (!bStartAnimation)
return;
}
void APlayerWukong::EnableWeaponCollision(bool bEnable)
{
if (bEnable)
WeaponBox->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
else
WeaponBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
void APlayerWukong::NotifyHit(class UPrimitiveComponent* MyComp, AActor* Other, class UPrimitiveComponent* OtherComp, bool bSelfMoved, FVector HitLocation, FVector HitNormal, FVector NormalImpulse, const FHitResult& Hit)
{
LOG(TEXT("Name : %s"), *MyComp->GetName());
}
void APlayerWukong::OnHit(UPrimitiveComponent* HitCom, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& result)
{
LOG(TEXT("Name : %s"), *OtherComp->GetName());
}
void APlayerWukong::WeaponBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
// UE_LOG(Project1005, Warning, TEXT("BeginOverlap"));
// LOG(TEXT("BeginOverlap"));
FDamageEvent DamageEvent;
float fDamage = OtherActor->TakeDamage(10.f, DamageEvent, GetController(), this);
// 충돌감지를 위한 소켓의 위치정보를 얻어옴.
FVector vStart = GetMesh()->GetSocketLocation(TEXT("FX_Staff_Tip_B"));
FVector vEnd = GetMesh()->GetSocketLocation(TEXT("FX_Staff_Tip_A"));
FVector vDir = vEnd - vStart;
vDir.Normalize();
FCollisionQueryParams tColParams(NAME_None, false, this);
// TArray : 언리얼 엔진에서 제공하는 배열. STL의 vector처럼 만들어짐.
TArray<FHitResult> HitArray;
// SweepSingleBy : 직선과 부딪히는 것을 만듦.
// SweepMultiBy : 부딪히는 것 여러 개 중에서 오버랩이랑 같을 것을 찾음.
bool bCollision = GetWorld()->SweepMultiByProfile(HitArray, vStart, vEnd, FQuat::Identity, TEXT("PlayerAttack"), FCollisionShape::MakeBox(FVector(120.f, 10.f, 10.f)), tColParams);
FVector vImpactPoint = FVector::ZeroVector; // ZeroVector로 초기화.
FVector vImpactNormal = FVector::ZeroVector; // ZeroVector로 초기화.
LOG(TEXT("Hit Count : %d"), HitArray.Num());
LOG(TEXT("Other Actor Name : %s"), *OtherActor->GetName());
// Num()함수는 현재 array가 가지고 있는 갯수를 반환해줌.
// 아래 for문과 같음.
/*for (int32 i = 0; i < HitArray.Num(); ++i)
{
}*/
for (auto hit : HitArray)
{
LOG(TEXT("Hit Actor Name : %s"), *hit.GetActor()->GetName());
if (hit.GetActor() == OtherActor) // 같을 경우, 부딪쳤을 경우
{
vImpactPoint = hit.ImpactPoint;
vImpactNormal = hit.ImpactNormal;
break;
}
}
#if ENABLE_DRAW_DEBUG
FVector vCenter = (vStart + vEnd) / 2.f; // Center는 start와 end 사이.
FColor DrawColor = HitArray.Num() > 0 ? FColor::Red : FColor::Green; // 충돌되면 빨강, 충돌 안되면 초록.
DrawDebugBox(GetWorld(), vCenter, FVector(120.f, 10.f, 10.f), vDir.ToOrientationQuat(), DrawColor, false, 2.f);
#endif // ENABLE_DRAW_DEBUG
// 파티클
FActorSpawnParameters tParams;
tParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
AEffectDestroy* Effect = GetWorld()->SpawnActor<AEffectDestroy>(vImpactPoint, vImpactNormal.Rotation(), tParams);
Effect->SetEffectPath(TEXT("ParticleSystem'/Game/InfinityBladeEffects/Effects/FX_Skill_Leap/P_Skill_Leap_Fire_Crushing_Impact.P_Skill_Leap_Fire_Crushing_Impact'"), TEXT("SoundWave'/Game/Effect/Lightsaber.Lightsaber'"));
Effect->SetActorScale3D(FVector(0.5f, 0.5f, 0.5f));
}
void APlayerWukong::WeaponEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
}
(C++-Monster.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "Monster.h"
// Sets default values
AMonster::AMonster()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
SpawnPoint = nullptr;
// 원하는 프로파일 세팅.
GetCapsuleComponent()->SetCollisionProfileName(TEXT("Monster"));
// Simulation Generate Hit를 체크한 것과 같음.
// GetCapsuleComponent()->SetNotifyRigidBodyCollision(true);
}
AMonster::~AMonster() // 소멸자. 몬스터가 죽었을 때
{
if (SpawnPoint)
SpawnPoint->Respawn();
}
// Called when the game starts or when spawned
void AMonster::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AMonster::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
(C++-GameInfo.h)
#pragma once
#include "EngineMinimal.h" // 추가.
UENUM(BlueprintType, Meta = (Bitflags))
enum class EDir : uint8 // 방향 설정.
{
Front,
Back,
Left,
Right,
Up,
Down
};
DECLARE_LOG_CATEGORY_EXTERN(Project1005, Log, All);
#define LOG_CALLINFO (FString(__FUNCTION__) + TEXT("{") + FString::FromInt(__LINE__) + TEXT("}"))
// 어떤 Function의 몇 번째 줄. FromInt() : 숫자를 문자열로 바꿔주는 함수.
#define LOG(Format, ...) UE_LOG(Project1005, Warning, TEXT("%s : %s"), *LOG_CALLINFO, *FString::Printf(Format, ##__VA_ARGS__))
// (LOG_CALLINFO + 출력할 문자열) 출력.
// TEXT("") : 2바이트 문자열을 만들어주는 매크로.
// 여러 나라의 문자를 사용하기 위해서는 유니코드 문자열을 사용함.
(C++-GameInfo.cpp)
#include "GameInfo.h"
DEFINE_LOG_CATEGORY(Project1005);
(C++-PlayerBaseAnim.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameInfo.h" // CoreMinimal.h를 GameInfo.h로 바꿈.
#include "Animation/AnimInstance.h"
#include "PlayerBaseAnim.generated.h"
UENUM(BlueprintType, Meta = (Bitflags)) // enum문을 사용할 때 사용.
enum class EPlayerBaseAnim : uint8 // uint8로 사용하겠다고 설정.
{
Idle,
Run,
Attack,
Hit,
Jump
};
UCLASS()
class PROJECT1005_API UPlayerBaseAnim : public UAnimInstance
{
GENERATED_BODY()
public:
UPlayerBaseAnim(); // 생성자.
protected:
uint8* BaseAnimType;
// 방향 설정.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EDir"))
uint8 Dir;
// 멈춰있는 지 확인.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool MoveStop;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool AttackEnable;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
uint8 NextAttackIndex;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool IsGround;
uint8 NextAttackMax;
bool NextAttack; // 다음 공격할 것인지.
bool NextAttackEnable; // 다음 공격을 할 것인지 말 것인지.
bool NextAttackInputEnable;
public:
void SetMoveDir(EDir eDir)
{
Dir = (uint8)eDir;
}
public:
// UAnimInstance에 가상함수로 정의되어 있으므로 재정의 하여 사용할 수 있음.
virtual void NativeInitializeAnimation(); // 초기화될 때 사용.
virtual void NativeUpdateAnimation(float DeltaSeconds); // 매 프레임마다 생성.
public:
UFUNCTION() // 노티파이를 호출하기 위해 사용. 언리얼 함수인 것을 알려줌.
void AnimNotify_MoveStop(); // AnimNotify_(노티파이 이름)으로 해야함.
UFUNCTION()
void AnimNotify_AttackEnd(); // AttackEnd 노티파이 추가.
UFUNCTION()
void AnimNotify_InIdle();
UFUNCTION()
void AnimNotify_NextAttackEnd(); // NextAttackEnd 노티파이 추가.
UFUNCTION()
void AnimNotify_ReturnIdle(); // jump후 idle로 돌아가는 노티파이.
UFUNCTION()
void AnimNotify_PlayerStart(); // 플레이어가 시작 모션을 끝내는 노티파이.
UFUNCTION()
void AnimNotify_AttackStart();
public:
void NormalAttack(); // 공격.
void Jump();
public:
virtual void InheritMoveStopNotify();
virtual void InheritAttackStartNotify();
virtual void InheritAttackEndNotify();
virtual void InheritInIdleNotify();
virtual void InheritNormalAttack();
};
(C++-PlayerBaseAnim.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "PlayerBaseAnim.h"
#include "PlayerCharacter.h" // 추가.
UPlayerBaseAnim::UPlayerBaseAnim() // 생성자.
{
Dir = (uint8)EDir::Front; // 기본으로 Front 설정.
MoveStop = true; // 처음에는 멈춰있으므로 true.
AttackEnable = true; // 처음에 공격 가능.
NextAttackEnable = false; // 처음에 다음 공격 불가능하게 설정.
NextAttack = false;
NextAttackInputEnable = false;
NextAttackMax = 0;
NextAttackIndex = 0;
}
void UPlayerBaseAnim::NativeInitializeAnimation() // 초기화될 때 사용.
{
Super::NativeInitializeAnimation();
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle;
}
void UPlayerBaseAnim::NativeUpdateAnimation(float DeltaSeconds) // 매 프레임마다 생성.
{
Super::NativeUpdateAnimation(DeltaSeconds);
// 언리얼에서는 Cast를 사용하여 형변환을 해야 함.
APlayerCharacter* pOwner = Cast<APlayerCharacter>(TryGetPawnOwner()); // 이 애니메이션 컴포넌트를 가지고 있는 폰을 얻어오는 함수.
if (IsValid(pOwner)) // IsValid : U오프젝트에 대한 유효성 검사를 해줌. 제대로 된 것인지 확인을 해줘서 더 안전함.
{
UCharacterMovementComponent* pMovement = pOwner->GetCharacterMovement(); // Movement를 얻어옴.
if (IsValid(pMovement))
{
IsGround = pMovement->IsMovingOnGround(); // IsMovingOnGround() : 땅을 밟고 있는 지 판단.
if (IsGround)
{
// Velocity.Size() : 이동속도의 크기
if (pMovement->Velocity.Size() > 0.f) // 0보다 크면 움직임.
{
if (*BaseAnimType == (uint8)EPlayerBaseAnim::Attack)
InheritAttackEndNotify();
MoveStop = false; // 이동 중에는 false.
NextAttackInputEnable = false;
NextAttackIndex = 0;
NextAttack = false;
*BaseAnimType = (uint8)EPlayerBaseAnim::Run;
}
else // 0이면 움직이지 않음.
{
MoveStop = true; // 멈췄을 때 true.
}
}
else
{
if (*BaseAnimType == (uint8)EPlayerBaseAnim::Attack)
InheritAttackEndNotify();
}
}
}
}
void UPlayerBaseAnim::AnimNotify_MoveStop() // 노티파이.
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle; // 동작이 끝나면 Idle로 돌아감.
InheritMoveStopNotify();
}
void UPlayerBaseAnim::AnimNotify_AttackEnd() // 노티파이.
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle; // 동작이 끝나면 Idle로 돌아감.
NextAttackInputEnable = false;
NextAttackIndex = 0;
NextAttack = false;
InheritAttackEndNotify();
}
void UPlayerBaseAnim::AnimNotify_InIdle() // 노티파이.
{
AttackEnable = true; // 공격 가능 상태로.
InheritInIdleNotify();
}
void UPlayerBaseAnim::AnimNotify_NextAttackEnd() // NextAttackEnd() 노티파이 추가.
{
if (NextAttack)
{
++NextAttackIndex;
if (NextAttackIndex >= NextAttackMax)
NextAttackIndex = 0;
NextAttack = false;
}
else
{
NextAttackInputEnable = false;
}
InheritAttackEndNotify();
}
void UPlayerBaseAnim::AnimNotify_ReturnIdle() // jump후 idle로 돌아가는 노티파이.
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Idle;
NextAttackInputEnable = false;
NextAttackIndex = 0;
NextAttack = false;
}
void UPlayerBaseAnim::AnimNotify_PlayerStart() // 플레이어가 시작 모션을 끝내는 노티파이.
{
APlayerCharacter* pOwner = Cast<APlayerCharacter>(TryGetPawnOwner()); // 이 애니메이션 컴포넌트를 가지고 있는 폰을 얻어오는 함수.
if (IsValid(pOwner))
pOwner->StartAnimation();
}
void UPlayerBaseAnim::AnimNotify_AttackStart()
{
InheritAttackStartNotify();
}
void UPlayerBaseAnim::NormalAttack() // 공격.
{
if (AttackEnable)
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Attack;
if (NextAttackEnable && NextAttackInputEnable)
{
NextAttack = true;
}
else if(!NextAttackEnable)
AttackEnable = false; // 공격 불가능 상태로.
NextAttackInputEnable = true;
}
InheritNormalAttack();
}
void UPlayerBaseAnim::Jump()
{
*BaseAnimType = (uint8)EPlayerBaseAnim::Jump;
}
void UPlayerBaseAnim::InheritMoveStopNotify()
{
}
void UPlayerBaseAnim::InheritAttackStartNotify()
{
}
void UPlayerBaseAnim::InheritAttackEndNotify()
{
}
void UPlayerBaseAnim::InheritInIdleNotify()
{
}
void UPlayerBaseAnim::InheritNormalAttack()
{
}
(C++-WukongAnim.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "PlayerBaseAnim.h"
#include "WukongAnim.generated.h"
UENUM(BlueprintType, Meta = (Bitflags)) // enum문을 사용할 때 사용.
enum class EWukongAnim : uint8 // uint8로 사용하겠다고 설정.
{
Idle,
Run,
Attack,
Hit,
Jump
};
UCLASS()
class PROJECT1005_API UWukongAnim : public UPlayerBaseAnim
{
GENERATED_BODY()
public:
UWukongAnim();
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EWukongAnim"))
uint8 AnimType;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EWukongAnim"))
UAnimMontage* Skill1Montage;
public:
// UAnimInstance에 가상함수로 정의되어 있으므로 재정의 하여 사용할 수 있음.
virtual void NativeInitializeAnimation(); // 초기화될 때 사용.
virtual void NativeUpdateAnimation(float DeltaSeconds); // 매 프레임마다 생성.
public:
virtual void InheritMoveStopNotify();
virtual void InheritAttackStartNotify();
virtual void InheritAttackEndNotify();
virtual void InheritInIdleNotify();
virtual void InheritNormalAttack();
public:
void Skill1();
};
(C++-WukongAnim.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "WukongAnim.h"
#include "PlayerWukong.h"
UWukongAnim::UWukongAnim() // 생성자.
{
BaseAnimType = &AnimType;
NextAttackEnable = true; // Wukong에서는 가능.
NextAttackMax = 5;
// 몽타주 에셋 읽음,
static ConstructorHelpers::FObjectFinder<UAnimMontage> Skill1Asset(TEXT("AnimMontage'/Game/Player/MTGWukongAttack.MTGWukongAttack'"));
if (Skill1Asset.Succeeded())
Skill1Montage = Skill1Asset.Object;
}
void UWukongAnim::NativeInitializeAnimation() // 초기화될 때 사용.
{
Super::NativeInitializeAnimation();
}
void UWukongAnim::NativeUpdateAnimation(float DeltaSeconds) // 매 프레임마다 생성.
{
Super::NativeUpdateAnimation(DeltaSeconds);
// 언리얼에서는 Cast를 사용하여 형변환을 해야 함.
APlayerWukong* pOwner = Cast<APlayerWukong>(TryGetPawnOwner()); // 이 애니메이션 컴포넌트를 가지고 있는 폰을 얻어오는 함수.
if (IsValid(pOwner)) // IsValid : U오프젝트에 대한 유효성 검사를 해줌. 제대로 된 것인지 확인을 해줘서 더 안전함.
{
UCharacterMovementComponent* pMovement = pOwner->GetCharacterMovement(); // Movement를 얻어옴.
if (IsValid(pMovement))
{
}
}
}
void UWukongAnim::InheritMoveStopNotify()
{
}
void UWukongAnim::InheritAttackStartNotify()
{
APlayerWukong* pOwner = Cast<APlayerWukong>(TryGetPawnOwner());
if (IsValid(pOwner))
pOwner->EnableWeaponCollision(true);
LOG(TEXT("AttackStart"));
}
void UWukongAnim::InheritAttackEndNotify()
{
APlayerWukong* pOwner = Cast<APlayerWukong>(TryGetPawnOwner());
if (IsValid(pOwner))
pOwner->EnableWeaponCollision(false);
LOG(TEXT("AttackEnd"));
}
void UWukongAnim::InheritInIdleNotify()
{
}
void UWukongAnim::InheritNormalAttack()
{
}
void UWukongAnim::Skill1()
{
if (!Montage_IsPlaying(Skill1Montage))
Montage_Play(Skill1Montage);
}
(C++-MinionRangerAnim.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameInfo.h"
#include "Animation/AnimInstance.h"
#include "MinionRangerAnim.generated.h"
UENUM(BlueprintType, Meta = (Bitflags))
enum class EMinionRangerAnim : uint8
{
Idle,
Run,
Attack,
Hit,
Death
};
UCLASS()
class PROJECT1005_API UMinionRangerAnim : public UAnimInstance
{
GENERATED_BODY()
public:
UMinionRangerAnim(); // 생성자.
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true", Bitmask, BitmaskEnum = "EMinionRangerAnim"))
uint8 AnimType;
// 멈춰있는 지 확인.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool MoveStop;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool IsGround;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
bool AttackEnable;
public:
// UAnimInstance에 가상함수로 정의되어 있으므로 재정의 하여 사용할 수 있음.
virtual void NativeInitializeAnimation(); // 초기화될 때 사용.
virtual void NativeUpdateAnimation(float DeltaSeconds); // 매 프레임마다 생성.
};
(C++-MinionRangerAnim.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "MinionRangerAnim.h"
#include "MinionRanger.h"
UMinionRangerAnim::UMinionRangerAnim() // 생성자.
{
MoveStop = true; // 처음에는 멈춰있으므로 true.
AttackEnable = true; // 처음에 공격 가능.
IsGround = true;
AnimType = (uint8)EMinionRangerAnim::Idle;
}
void UMinionRangerAnim::NativeInitializeAnimation() // 초기화될 때 사용.
{
Super::NativeInitializeAnimation();
}
void UMinionRangerAnim::NativeUpdateAnimation(float DeltaSeconds) // 매 프레임마다 생성.
{
Super::NativeUpdateAnimation(DeltaSeconds);
// 언리얼에서는 Cast를 사용하여 형변환을 해야 함.
AMinionRanger* pOwner = Cast<AMinionRanger>(TryGetPawnOwner()); // 이 애니메이션 컴포넌트를 가지고 있는 폰을 얻어오는 함수.
if (IsValid(pOwner)) // IsValid : U오프젝트에 대한 유효성 검사를 해줌. 제대로 된 것인지 확인을 해줘서 더 안전함.
{
UCharacterMovementComponent* pMovement = pOwner->GetCharacterMovement(); // Movement를 얻어옴.
if (IsValid(pMovement))
{
IsGround = pMovement->IsMovingOnGround(); // IsMovingOnGround() : 땅을 밟고 있는 지 판단.
if (IsGround)
{
// Velocity.Size() : 이동속도의 크기
if (pMovement->Velocity.Size() > 0.f) // 0보다 크면 움직임.
{
MoveStop = false; // 이동 중에는 false.
AnimType = (uint8)EMinionRangerAnim::Run;
}
else // 0이면 움직이지 않음.
{
MoveStop = true; // 멈췄을 때 true.
}
}
}
}
}
(C++-MinionRanger.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Monster.h"
#include "MinionRanger.generated.h"
/**
*
*/
UCLASS()
class PROJECT1005_API AMinionRanger : public AMonster
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMinionRanger();
protected:
class UMinionRangerAnim* MinionRangerAnim;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser);
};
(C++-MinionRanger.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "MinionRanger.h"
#include "MinionRangerAnim.h"
// Sets default values
AMinionRanger::AMinionRanger()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// static을 붙여서 1번만 읽어오도록 함.
// 미니언 에셋을 불러오기.
static ConstructorHelpers::FObjectFinder<USkeletalMesh> MeshAsset(TEXT("SkeletalMesh'/Game/ParagonMinions/Characters/Minions/Down_Minions/Meshes/Minion_Lane_Ranged_Dawn.Minion_Lane_Ranged_Dawn'"));
if (MeshAsset.Succeeded())
GetMesh()->SetSkeletalMesh(MeshAsset.Object);
// AnimInstance 설정.
// SetAnimInstanceClass()로 클래스 타입을 지정해주면 내부적으로 생성자가 지나고 나서 AnimInstance를 만들어냄.
// 생성자에서 AnimInstance를 얻어오는 방법은 없음.
static ConstructorHelpers::FClassFinder<UMinionRangerAnim> AnimAsset(TEXT("AnimBlueprint'/Game/Monster/BPMinionRangerAnim.BPMinionRangerAnim_C'"));
if (AnimAsset.Succeeded())
GetMesh()->SetAnimInstanceClass(AnimAsset.Class);
// 캡슐컴포넌트에 맞춰 위치 조절.
GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -70.f)); // 아래로 내림.
GetMesh()->SetRelativeRotation(FRotator(0.f, -90.f, 0.f)); // 회전.
}
// Called when the game starts or when spawned
void AMinionRanger::BeginPlay()
{
Super::BeginPlay();
// 생성자에서 AnimInstance를 얻어오지 못하므로 BeginPlay에서 얻음.
MinionRangerAnim = Cast<UMinionRangerAnim>(GetMesh()->GetAnimInstance());
}
// Called every frame
void AMinionRanger::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
float AMinionRanger::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float fDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
return fDamage;
}
(C++-Minion.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Monster.h"
#include "Minion.generated.h"
/**
*
*/
UCLASS()
class PROJECT1005_API AMinion : public AMonster
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMinion();
protected:
class UMinionAnim* MinionAnim;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser);
// AActor안에 TakeDamage() 함수가 있음.
};
(C++-Minion.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "Minion.h"
#include "MinionAnim.h"
// Sets default values
AMinion::AMinion()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
// static을 붙여서 1번만 읽어오도록 함.
// 미니언 에셋을 불러오기.
static ConstructorHelpers::FObjectFinder<USkeletalMesh> MeshAsset(TEXT("SkeletalMesh'/Game/ParagonMinions/Characters/Minions/Down_Minions/Meshes/Minion_Lane_Melee_Core_Dawn.Minion_Lane_Melee_Core_Dawn'"));
if (MeshAsset.Succeeded())
GetMesh()->SetSkeletalMesh(MeshAsset.Object);
// AnimInstance 설정.
// SetAnimInstanceClass()로 클래스 타입을 지정해주면 내부적으로 생성자가 지나고 나서 AnimInstance를 만들어냄.
// 생성자에서 AnimInstance를 얻어오는 방법은 없음.
static ConstructorHelpers::FClassFinder<UMinionAnim> AnimAsset(TEXT("AnimBlueprint'/Game/Monster/BPMinionAnim.BPMinionAnim_C'"));
if (AnimAsset.Succeeded())
GetMesh()->SetAnimInstanceClass(AnimAsset.Class);
// 캡슐컴포넌트에 맞춰 위치 조절.
GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, -70.f)); // 아래로 내림.
GetMesh()->SetRelativeRotation(FRotator(0.f, -90.f, 0.f)); // 회전.
}
// Called when the game starts or when spawned
void AMinion::BeginPlay()
{
Super::BeginPlay();
// 생성자에서 AnimInstance를 얻어오지 못하므로 BeginPlay에서 얻음.
MinionAnim = Cast<UMinionAnim> (GetMesh()->GetAnimInstance());
}
// Called every frame
void AMinion::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
float AMinion::TakeDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
float fDamage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
LOG(TEXT("Damage"));
return fDamage;
}
(C++-EffectDestroy.h)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameInfo.h"
#include "GameFramework/Actor.h"
#include "EffectDestroy.generated.h"
UCLASS()
class PROJECT1005_API AEffectDestroy : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AEffectDestroy();
protected:
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Meta = (AllowPrivateAccess = "true"))
UParticleSystemComponent* Particle;
public:
void SetEffectPath(const FString& strPath, const FString& strSoundPath);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
UFUNCTION()
void Finish(UParticleSystemComponent* Com);
};
(C++-EffectDestroy.cpp)
// Fill out your copyright notice in the Description page of Project Settings.
#include "EffectDestroy.h"
// Sets default values
AEffectDestroy::AEffectDestroy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Particle = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("Particle"));
SetRootComponent(Particle);
}
void AEffectDestroy::SetEffectPath(const FString& strPath, const FString& strSoundPath)
{
UParticleSystem* Asset = LoadObject<UParticleSystem>(nullptr, *strPath);
if (IsValid(Asset))
Particle->SetTemplate(Asset);
Particle->OnSystemFinished.AddDynamic(this, &AEffectDestroy::Finish);
USoundBase* SoundAsset = LoadObject<USoundBase>(nullptr, *strSoundPath);
UGameplayStatics::PlaySoundAtLocation(GetWorld(), SoundAsset, GetActorLocation());
// PlaySound2D : 보통 BGM에 사용.
// 감쇠 처리도 가능.
}
// Called when the game starts or when spawned
void AEffectDestroy::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AEffectDestroy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void AEffectDestroy::Finish(UParticleSystemComponent* Com)
{
Destroy();
}
'Study > Unreal' 카테고리의 다른 글
[Unreal/정리] 랜드 스케이프 레이어 (0) | 2020.10.23 |
---|---|
[Unreal/정리] 리타겟팅 (0) | 2020.10.21 |
[Unreal/정리] 몬스터 클래스 / Spawn시스템 (0) | 2020.10.16 |
[Unreal/정리] 무기 장착 (0) | 2020.10.15 |
[Unreal/정리] 애니메이션_Jump (0) | 2020.10.13 |
댓글