게임모드




GameMode를 상속받고 C++을 새롭게 만든다.



게임모드에서 설정할 수 있는 건 프로젝트에서 확인을 할 수 가 있다

 



우선 사용할 Default  Pawn을 만들자

 


기본캐릭터 설정

 

Pawn이나 Character을 상속하여 클래스를 작성을 한다
Chatacter으로 상속했을 경우에는 캡슐과 메시가 상속있어서 겟터함수를 이용해서 호출 할수 있다
.

Character.h

 

class KGAME_API AKCharacter : public ACharacter
{
	GENERATED_BODY()
public:
	AKCharacter();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void Tick(float DeltaTime) override;
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

public:
	//UPROPERTY(VisibleAnyWhere, Category = Collision)
	//	UCapsuleComponent* m_Capsule;
	//UPROPERTY(VisibleAnyWhere, Category = Visual)
	//	USkeletalMeshComponent* m_Mesh;
	
	UPROPERTY(VisibleAnywhere, Category = Camera)
		USpringArmComponent* m_SpringArm;

	UPROPERTY(VisibleAnywhere, Category = Camera)
		UCameraComponent* m_Camera;


캡슐과 메시는 이미 상속받앗기 떄문에 주석처리를 했다

 

AKCharacter::AKCharacter()
{
	PrimaryActorTick.bCanEverTick = true;

	//GetCapsuleComponent() = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule"));
	//m_Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
	m_SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("Spring"));
	m_Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));


	RootComponent = GetCapsuleComponent();
	GetMesh()->AttachTo(GetCapsuleComponent());
	m_SpringArm->SetupAttachment(GetCapsuleComponent());
	m_Camera->SetupAttachment(m_SpringArm);

	
	GetCapsuleComponent()->SetCapsuleHalfHeight(88.0f);
	GetCapsuleComponent()->SetCapsuleRadius(20.0f);
	GetMesh()->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, -88.0f), FRotator(0.0f, -90.0f, 0.0f));
	m_SpringArm->TargetArmLength = 200.0f;
	m_SpringArm->SetRelativeLocationAndRotation(FVector(0.0f,0.0f,40.0f),FRotator(-25.0f, 0.0f, 0.0f));



	static ConstructorHelpers::FObjectFinder<USkeletalMesh> PlayerModel(TEXT("SkeletalMesh'/Game/Sailor_01/Mesh/SK_Sailor01.SK_Sailor01'"));

	if (PlayerModel.Succeeded()) {
		GetMesh()->SetSkeletalMesh(PlayerModel.Object);
	}
}

 

	//GetCapsuleComponent() = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule"));
	//m_Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
	m_SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("Spring"));
	m_Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));


	RootComponent = GetCapsuleComponent();
	GetMesh()->AttachTo(GetCapsuleComponent());
	m_SpringArm->SetupAttachment(GetCapsuleComponent());
	m_Camera->SetupAttachment(m_SpringArm);


위와 같은 코드로 작성을 했는데, 먼저CreateDufalut로 생성을 하고
캡슐을 루트컴포넌트로 삼아서, 컴포넌트 관계를 구축했다. 
여기에 스트링암과 카메라를 연결 했다.


컴포넌트 관계 설정


먼저 메시를 호출 하고 맞춰 주어야 캐릭터가 호출이 된다

static ConstructorHelpers::FObjectFinder<USkeletalMesh> PlayerModel(TEXT("SkeletalMesh'/Game/Sailor_01/Mesh/SK_Sailor01.SK_Sailor01'"));

if (PlayerModel.Succeeded()) {
	GetMesh()->SetSkeletalMesh(PlayerModel.Object);
}


ConstructorHelpers 는 생성할떄 도와주는 함수로 생성할떄 사용하는 것이 좋고,
static을 사용하는 이유는 다른 곳에서 또 만들어서 사용하는 낭비를 줄이기 위해서 이다.
메시 경로는 우클릭 후 레퍼런스 복사로 쉽게 복사 할수 있다.
그리고 Succeeded함수를 이용해서 Null체크를 한수 스켈레톤 메시를 설정한다

그리고 컴파일 후 보면 C++ 미리보기에 캐릭터가 표시되어 있다

 

 


그리고 드래그를 해서 보면, 메시 캡슐 스트링 위치가 맞지가 않다.


BP로 만들어서 수정을 하는 방법이 있고, 여기서 코드로 맞추는 방법도 있다.

BP는 확장을 해서 편집이 필요한 경우에만 사용할 생각 이라서

그냥 코드로 함

 

안맞는 위치 




GetCapsuleComponent()->SetCapsuleHalfHeight(88.0f);
	GetCapsuleComponent()->SetCapsuleRadius(20.0f);
	GetMesh()->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, -88.0f), FRotator(0.0f, -90.0f, 0.0f));
	m_SpringArm->TargetArmLength = 200.0f;
	m_SpringArm->SetRelativeLocationAndRotation(FVector(0.0f,0.0f,40.0f),FRotator(-25.0f, 0.0f, 0.0f));

그래서 위치와 거리를 맞춰준다!

 

카메라에 표시된 것을 확인하니 설정한 위치가 맞다.
나중에 게임 하면서 안맞으면 다시 바꾸어 줄 생각


사용할 캐릭터를 만들었으니, 

마지막으로 게임모드에서 디폴트 폰을 설정한다

캐릭터 헤더를 게임모드 Cpp에 추가를 한후

디폴트 폰을 설정해 준다

방법은 아래처럼 2가지가 있다. (더 있을 수도 있음)

 

#include "KGameMode.h"
#include "KCharacter.h"

AKGameMode::AKGameMode()
{
	//방법1
    static ConstructorHelpers::FClassFinder<APawn> PlayerPawnClassFinder(TEXT("/Game/FirstPersonCPP/Blueprints/FirstPersonCharacter"));
	DefaultPawnClass = PlayerPawnClassFinder.Class;

	//방법2
	DefaultPawnClass = AKCharacter::StaticClass();
}

 

그리고 월드세팅에서 게임모드를 바꾸어 주면 된다

 

 

 

 

실행화면


캐릭터 좌 우 2개는 미리 배치해둔 캐릭터이다


아직 컨트롤러는 설정을 안했으므로 움직이지는 않는다.

'Unreal > Game 2 ' 카테고리의 다른 글

4.1 기존 바인딩 함수 이동  (0) 2019.06.18
4. 캐릭터 애니메이션  (0) 2019.06.17
3. 플레이어 컨트롤러 (바인딩 방법 2개)  (0) 2019.06.15
1. 게임준비 및 디버깅로그 세팅  (0) 2019.06.14
0. 게임 기획?  (0) 2019.06.14

솔루션 이름 : KGame

//KGame.h

//#include "CoreMinimal"
#include "EngineMinimal.h"

이 헤더는 여러 cpp 및  헤더에 연결을 해서 사용할 예정

Engine.h 는 내용이 많아서 무겁고, 여러 헤더에 연결을 해서 사용을 하면, 그만큼 비용을 들거라 예상

CoreMinimal.h은 기본적인 게임 구성에 포함하는 내용이 부족하므로

EngineMinimal.h 을 사용



사용할 디버그 로그 매크로 세팅

//h
DECLARE_LOG_CATEGORY_EXTERN(KGame, Log, All);
#define KLOG_CALLINFO (FString(__FUNCTION__) + TEXT("(") + FString::FromInt(__LINE__) + TEXT(")"))
#define KLOG_S(Verbosity) UE_LOG(KGame, Verbosity, TEXT("%s"), *KLOG_CALLINFO)
#define KLOG(Verbosity, Format, ...) UE_LOG(KGame, Verbosity, TEXT("%s %s"), *KLOG_CALLINFO, *FString::Printf(Format, ##__VA_ARGS__))
#define KCHECK(Expr, ...) {if(!(Expr)) {KLOG(Error, TEXT("ASSERTION : %s"), TEXT("'"#Expr"'")); return __VA_ARGS__;}}

//cpp
#include "KGame.h"
#include "Modules/ModuleManager.h"

DEFINE_LOG_CATEGORY(KGame);
IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, KGame, "KGame" ); 



사용예시

auto GameInstance = Cast<UGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
KCHECK(nullptr != GameInstance);


게임실행에 방해는 안하고
Null일 경우 오류 메시지가 출력이 된다.

'Unreal > Game 2 ' 카테고리의 다른 글

4.1 기존 바인딩 함수 이동  (0) 2019.06.18
4. 캐릭터 애니메이션  (0) 2019.06.17
3. 플레이어 컨트롤러 (바인딩 방법 2개)  (0) 2019.06.15
2. 기본 게임모드 및 기본캐릭터 설정  (0) 2019.06.14
0. 게임 기획?  (0) 2019.06.14

예상 게임 분위기

 

장르 : 멀티 2인 디펜스? or Stage 진행? 게임

시대 : 현대 좀비 아포칼립스?

시간 : 저녘 ~ 밤?

플로우 : 타이틀 -> 로비? 방? -> 게임 -> 결과


[리소스]
1. 남 모델
2. 여 모델
3. 총 모델
4. 상하좌우 이동, 총 애니메이션
5. HP UI?
6. 
7. 



[만들며 생각할점]

1. 남, 여 분류 방법?
2. 밤일 경우 라이트 장착?
3. 좀비 헤드샷 판정? 머리만 디스토블?



 

네트워크 연관성

 

액터가 특정 시간 특정머신에 연관성이 있는 가 결정하는 것이다

연광성이 있다면 업데이트 내용을 전송한다.


 ※ 항상 모든 머신에 모든 네트워크 데이터를 전송하지 않는 것이 중요


네트워크 연관성 이해

 

1. 함수실행 (서버)


서버에서만 상자가 열리고, 이펙트가 재생된다.

 

2. 함수리플리케이션 - 멀티캐스트

 

둘다 근접에서 실행한 결과


서버 - 클라 둘다 상자가 열리고, 이펙트가 재생된다.
(모든 네트워크 데이터를 전송)
(거리 상관 없이 열림)




3. 함수리플리케이션 - 멀티캐스트 (거리에 따라서 네트워크 연관성을 없앤 경우)

 

클라이언트는 변화가 없음

거리가 멀어서
클라이언트에서는 네트워크 업데이트를 진행 안함

 

근접해서 확인하면, 상자는 닫혀있음 (동기화 깨짐)

그래서 근접해서 확인하면 서버에선 상자라 열려있지만,

업데이트가 안됐으므로 클라이언트는 상자가 그대로 이다.

동기화 오류

 

 

4.  변수 리플리케이션 (거리에 따라서 네트워크 연관성을 없앤 경우)


리플리케이션 되는 변수

 

거리가 멀어서 네트워크 업데이트를 진행 안함
그러나 변수는 리플리케이션 되어 있는 걸 전달 받음

 

클라이언트가 앞으로 이동 중에 상자가 열린다.

변수는 바뀌어 있고
인식 거리 안으로 들어가면 상자가 열린다.

 

5. 변수 리플리케이션+ 함수 리플리케이션

상태는 변수리플리케이션, 이펙트 재생은 멀티캐스트를 사용

변수가 바뀌고, 함수로 리플리케이션 한다

상태가 저장되는 변수를 이용해서,  지속되는 상태가 관한 것만 제어 또는 변경함



거리 밖

상자 상태 변수가 바뀜-> 변수 리플리케이트 -> 업데이트됨
이펙트 재생 -> 비신뢰성 멀티캐스트 -> 업데이트 안되고 재생도 안됨

 

클라이언트 접근 중 상자가 열림
거리 안


상자 상태 변수는 업데이트가 되어 있으므로, 
인식 거리 안에 들어가면 상자가 열려 있는 것을 확인 할 수 있다.

1. 변수 리플리케이션 -  함수 리플레케이션 선택

- 일회성 이벤트가 발생할 때라면, 함수 리플리케이션이 좋다

- 변한 다음 유지되며, 클레이언트에 잠깐 보여야 하는 경우, 변수 리플리케이션이 좋다 (ex::신호등)

 

OO를 작동하면, 클라이언트 보단 서버에서 결정하는 것이 좋다. 즉 서버만이 발동 여부를 결정한다 (좋음)


2. 함수호출 리플리케이트

 

함수 호출 역시 리플리케이트 가능합니다

리플리케이트되는 함수는 크게 세 가지 유형이 있습니다:
Multicast (멀티캐스트), Server (서버), Client (클라이언트) 입니다. 

멀티캐스트 함수는 실행되는 곳인 서버에서 호출된 이후, 클라이언트에 자동으로 전송됩니다. 

서버 함수는 클라이언트에서 호출되어 서버에서만 실행됩니다. 

클라이언트 함수는 서버에서 호출되어 소유중인 클라이언트에서만 실행됩니다.

서버/클라이언트 리플리케이션 함수에는 Net Owner (네트 소유자)가 있는 액터에만 사용할 수 있다는 추가적인 제약이 있습니다. 네트 소유자가 있는 액터라 함은, 플레이어 컨트롤러이거나 거기에 소유된 경우입니다. 
예를 들어 플레이어 컨트롤러에 빙의된 폰에는 서버/클라이언트 리플리케이트되는 함수를 가질 수 있습니다.



Not Replicated - 로컬 머신이외에는 호출이 안된다.

Mutilcast - 로 등록된 함수가 호출 되면, 이 뒤에 일어나는 모든 스크립트를 실행하고,
               실행한 것을 모든 클라이언트에서도 호출한다.

※ Mutilcast는 전달량이 많을 경우, 보호하는 엔진 기능이 있다.
같은 프레임에서 두번 이상 발생한 경우, 이후 다음 프레임까지 호출을 거절한다.
(네트워크가 가득차지 않도록하기 위해서)



3. 신뢰성 (Reliable)

 

신뢰성


Replicated Function Calls
 (리플리케이트된 함수 호출)은 
Reliable(신뢰성) 또는 Unreliable (비신뢰성) 설정이 가능합니다.

신뢰성 호출은 반드시 실행이 보장되는 반면, 비신뢰성 호출은 트래픽이 심한 경우 실행되지 않을 수가 있습니다. 

비신뢰성 일떄 - 순수 장식성, 대개 장식성인 작업을 할떄 비신뢰성으로 둔다
신뢰성 일떄 - 게임플레이에 영향을 끼치는 경우. 및 네트워크 오가는 내용이 많으면 신뢰성을 체크해서 전달.

+ Recent posts