Const &char Class::Method (int* pt)

 

해당 메소드의 반환값(char)을 상수화시켜서 못바꾸게 하겠다는뜻.

 

이걸 그대로 받아서 변수로쓰면 못바꿈.

 

&char Class::Method (int* pt) Const

 

메소드 자체를 상수화 하겠다는뜻.

 

메모리스택에서 얘가 다 돌고 해제될때까지 

 

내부 데이터들이 다 상수화되서 안바뀜. 

 

스레드,동시성 프로그래밍할떄 유용할거같다.

 

&char Class::Method (Const int* pt) 

 

pt라는 포인터가 가리키는 매개변수의 주소값을 상수화시켜버리는것.

 

어디가리키는지는 못바꾸는데 가리키는곳의 데이터는 바꿀 수있다.

 

 

&char Class::Method (int* Const pt) 

 

pt라는 포인터가 가리키는 매개변수의 데이터를 상수화 시켜버림.

 

포인터가 가리키는 주소는 바꿀수있는데 데이터를 못바꿈

 

 

규칙성을 따져보면

const는 앞에 뭔가 있으면 그거 하나를 얼려버림.

그리고 앞에 아무것도 없고 뒤에 뭔가 있으면 그걸 다 얼려버림.

 

const를 어떻게 넣냐에 따라서 

프로그래머가 원치않게 변수조작하는것을 미연에 방지해줄수 있음

https://devblogs.nvidia.com/introduction-turing-mesh-shaders/

 

Introduction to Turing Mesh Shaders | NVIDIA Developer Blog

Turing introduces a new programmable geometric shading pipeline, mesh shaders,, enabling threads to cooperatively generate compact meshes on the chip.

devblogs.nvidia.com

영알못+그알못이라 개념만 이해한대로 보면.

 

 

지금까지 렌더링 파이프라인은

 

프레임마다

인접한 버텍스끼리 그거 다 연결해버리고 테셀레이션해서 나누고 굴곡준다음에

지오메트리로 다시 단위로 나눌때 거기서 중복되서 필요없는 정점들 지워서 최적화하는 방식으로

폴리곤 렌더링을하고 래스터라이징을 했다면

 

이제는 이거 안에 필요없는연산 너무 꾸역꾸역넣어서 느리고

넘 꾸진거같으니 이전 버텍스의 사용했던 중복되는 버텍스의 인덱스를 치환해서 재계산을 안하고

바로 병렬처리해서 빠르게 렌더링하겠다는 소리같은데.

 

 

 

그림보니까 파이프라인 자체가 바뀌어있다. 그아래 뭐 원리 설명하는 그림 있느거 같은데 아직 이해가안대고..

 

이거이러면 그래픽플머님들이랑 게임엔진회사들 난리날거같다.

 

외계인형님들이 나같은 빡머갈들을 위해 쓰기 쉬운 API 새로 설계해서 만들어주실거고

 

이전에쓰던 다렉이랑 오픈지엘은 옛날겜에만 쓸거고 

 

앞으로 무선디바이스 요구하는 VR이나 홀로렌즈, 더 그래픽쩌는 모바일게임성능을 내는데 쓰일건데

 

님들 갓겜 만들고싶으면 이전까지 공부한거 갖다버리고 우리가 만든거 새로공부하세요 ^^*

 

아 너무 무섭다.

 

저번처럼 바인딩할 버튼을 만들고 

인터페이스에 가상함수를 만들고.

 

 

상속받은 인터페이스를 가져오고.

 

 

 

인터페이스 기능을 구현. (핵심)

 

 

 

메뉴에서 인터페이스의 함수를 호출할 함수를 작성 .

그리고 버튼이벤트 바인딩.

 

 

 

 

 

 

 

UMG와 부모위젯헤더파일에 이렇게 바인딩시킨후.

 

클릭했을떄 함수 등록

 

마지막줄의 인터페이스함수를 호출하는 형식으로 동작하는데 구성은 이렇다.

인터페이스 선언 -> 인스턴스에서 다중상속 -> 구현  ->

메인메뉴에서 여기서 구현한 인터페이스를 받아서 호출함. 

 

결과

 

 

 

아직도 몇달째 고민하고있는 문제다.

 

내가 프로그래밍을 시작한 계기는 게임만드는게 재밌어서였고.

 

물론 아예 대기업처럼 밑바닥부터 진행을 할것이면 디자이너와 TA도필요하지만.

 

모델링 에셋은 왠만하면 돈으로 구매할수있어 커버가 가능하고 거기서 조금조금씩 내가원하는스타일로 바꾸는것은

어렵지않게 가능하다.

 

하지만 프로그래밍은 돈으로 살수가 없다. 만약 외주를 구했다쳐도

수정이고 업데이트고 필요할때 그사람을 계속불러야하고 내가 맘대로 고쳤다간 터지는일이 발생할것이

불보듯 훤하기때문에 결국 코딩은 직접하는것이 고통을 감내하면서도 심적으로 편안하기때문에.

프로그래밍을 메인으로 공부하는것.

 

나는 이미 만들어져있는 툴이나 엔진을 활용하면 빠른시간내에 최적의 결과물을 낼수있고 그걸로 벌수있으면 

그게 최선이고 제일 효율적이라 생각한다.

 

예로들어 내가 학부시절에 완전 쌩 하드코딩으로 허접한 FPS를 만들었었는데.

유니티 엔진에서 이미 쓰라고 만든 스탠다드에셋이 있었고 그게 더 성능이 좋았을때만큼

허탈감오고 화나는일이 없었다.

 

아주 도움이 안된 경험은 아니지만. 쪽팔려서 포트폴리오로 쓰지않았다.

 

또, 3Dmax로 6개월동안 개고생하며 내가 만들고싶은 캐릭터 만들었는데 vroid가 그걸 다 씹어먹어버렸다.

 

나는 내가 원하는 게임만들고싶어서 프로그래밍 공부한것이며.

 

공부 열심히해서 고연봉 프로그래머로 인생 성공할거야! 라고 시작한것이 아니어서.

 

프로그래머와 개발자사이의 진로에서 아직 명확한 이정표를 못 꽂고있다.

 

항상 내가 의문을 느끼는게 한국의 네임드 프로그래머들이 왜 퇴직후 치킨집 고기집일까 싶다.

 

프로그래머는 진짜 공부만하면 웬만한거 다 만들 수있다고 생각하는데. 

 

고객 니즈 파악을 못해서 돈되는걸 못 만드는건가 싶은건가 생각이 들기도하고 오만가지 생각이 든다.

 

대기업 회사가 원하는 인재상을 보면

 

특화된 프로그래머를 원한다.

포트폴리오보다. 수학,자료구조,알고리즘,그래픽스 기초지식을 물어본다.

당연히 중요하다. 기초.  맞는말이다.

지원자도 많기 때문에 이를 한명한명 또 보기 어려워서 수백명의 지원자를 가려내기위해 코딩테스트가 필요한것이다.

그리고 지금의 대기업들은 피쳐폰시절부터 화면에 도트찍으면서 이루어낸 명성인만큼 로우레벨울 중요시한다.

내가 사장이어도 나보다 코딩 잘하는애 뽑아다 쓸거다.

 

근데 이것들을 시험치려고 공부하면 졸업하고서 3개월에서 길게는 1년 배웠던걸 달달 외워서 복습해야한다. 

솔직히 배웠던건 개념만 남아있지 디테일한건 안쓰면 다 까먹어서 시험볼때 끄내쓰기가 어렵다.

대기업 공채시험합격하는사람들은 정말 대단한거같다.

 

난 왠만한건 다 만들 수 있다고 생각하지만,

나보다 빨리 배우는 천재들을 주변에서 많이 봤기때문에 머리는 좋지않다고 생각한다. 

구현이 필요할때 이런게 있었지! 하면서 빼다가 다시 공부해서 쓰는게 보통이라고 난 생각한다.

 

솔직히 말해서 갑자기 양방향 링크드리스트로 큐 손코딩하라 그러면 못한다.

대충 흉내야 낼수는있겠지만 분명 안돌아가는 코드일것이다ㅠ.

#include <queue> 쓰고 나올거같다. 

 

여기저기 구글링하다보니

대기업 합격률을 자랑하며 코딩인터뷰 대용으로 알고리즘만 따로 가르치는 학원도있길래 헛웃음만 나왔다.

대기업 취직을 인생목표로해서 알고리즘 고시공부를 또 하라는건 좀 아니라 생각했다.

취직해서 뭐 회사에서 시키는거 하는게 인생의 장래희망이라 하기엔.. 절레절레.. 

 

내 성격에는 그렇게 공부하면 지식을 제대로 흡수하지 못했다.

 

나쁜말로 프로그래밍에 집중 안하고 딴짓하면서  합리화했다고 들어도 나는 수긍할수밖에 없다.

이 고민을 교수님이나 청강대 교수님을 포함해 꽤 여러분께 털어놨는데.

프로그래머가 되고샆냐. 크리에이터가 되고싶냐 라는 말이 되돌아왔다.

 

나는 모니터에서 0과 1이 바뀌는것보다 뭔가 더 크게 변하는것을 좋아한다고 생각하기때문에,

조금 고민하다가 크리에이터라고 대답했었고 지금도 그렇다고 생각한다.

 

그러자 교수님은 나는 한 방향에 특화되어있어서 모르는 지식은 도와줄수있지만

너에게 가르쳐 줄 수있는것이 별로없다. 라고 하셨다.

 

그래서 지금은 그냥 지금 내가 좋아하는것을 열심히 추진하면 뭔가 기회가 딱 오지 않을까 싶어서.

그냥 마음가는걸 열심히 하자 생각했다.

프로젝트 파일로 가서 source -> 프로젝트이름 폴더 -> 프로젝트이름 .build.cs 라는 c#문서를 열어서 UMG를

추가해준다.

 

에디터에서 마우스오른클 ->유저 인터페이스 -> 위젯 블루프린트를 만들고 대충 저런 모양 나오게 

셋팅한다 (c++보는사람은 블루프린트 이미 알고있을거라 생각하니 사용법은 생략)

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "PuzzlePlatformsGameInstance.generated.h"

/**
 * 
 */
UCLASS()
class TEST_API UPuzzlePlatformsGameInstance : public UGameInstance
{
	GENERATED_BODY()
		//c++ 생성자 단에서 초기화 
		UPuzzlePlatformsGameInstance(const FObjectInitializer& ObjectInitializer);
	
public:

	//언리얼 게임인스턴스 단에서 초기화 
	virtual  void Init();

	UFUNCTION(Exec)
		void Host(); //호스트

	UFUNCTION(Exec) //조인 + 접속아이피
		void Join(const FString& Address);

	UFUNCTION(BlueprintCallable)//메뉴불러오는 함수
		void LoadMenu();

private:
	//위젯가져오기
	TSubclassOf<class UUserWidget> MenuClass;
	//메인메뉴 클래스 포인터
	class UMainMenu* Menu;
	
};

위젯을 다룰 인스턴스 소스의헤더파일에 블루프린트에서 사용할수있도록 위와같이 함수선언 +

위젯클래스를 가져올수 있도록 해준다.

 

void UPuzzlePlatformsGameInstance::LoadMenu()
{
	if (!ensure(MenuClass != nullptr)) return;

	UUserWidget* Menu = CreateWidget<UUserWidget>(this, MenuClass);
	if (!ensure(Menu != nullptr)) return;

	Menu->AddToViewport(); //뷰포트에 나타내기
}

그리고 cpp파일에서 이렇게 코딩해준후 

 

레벨블루프린트에서 다음과 같이 스크립트를 짜준다.

 

게임화면이 이같이 뷰포트에 덮어씌워진다.

 

 

위와같이 나오는데. 캐릭터 asdw로 움직이고 회전 그대로되면서 

 

버튼을 누르고싶은데 마우스커서가 안나옴.

 

그러니까 포커스가 위젯에 맞춰져야한다.

 

블루프린트로는 이런거.

 

 

그러니까 다음과같이 코딩.

 

void UPuzzlePlatformsGameInstance::LoadMenu()
{
	if (!ensure(MenuClass != nullptr)) return;

	UUserWidget* Menu = CreateWidget<UUserWidget>(this, MenuClass);
	if (!ensure(Menu != nullptr)) return;

	Menu->AddToViewport(); //뷰포트에 나타내기

	//현제 이용중인 플레이어 컨트롤러를 얻어옴.
	APlayerController* PlayerController = GetFirstLocalPlayerController();
	if (!ensure(PlayerController != nullptr)) return;

	//사용자 입력을 처리해줄 라이브러리
	FInputModeUIOnly InputModeData;
	//사용랗 위젯을 지정
	InputModeData.SetWidgetToFocus(Menu->TakeWidget());
	//마우스를 뷰포트에 고정할건지 자유롭게 놔둘건지 지정
	InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);

	//위에서 구현한사항을 플레이어 컨트롤러에서 지정
	PlayerController->SetInputMode(InputModeData);
	//마우스커서 보이게하기
	PlayerController->bShowMouseCursor = true;
}

이렇게하고 컴파일하면 키보드입력이 안먹고 마우스커서가 나타나서 버튼을 누를 수 있게된다.

 

그러나 아직 버튼을 눌러도 아무 동작을 하지 않는다 

 

당연히 바인딩을 안해줬으니까.

 

 

준비물.

 

 

usetWidget을 부모로한 c++클래스를 

다음과같은 이름으로 생성해준다.

 

 

 

 

 

 

 

 

 

 

저번에 만든 umg에서 

1.그래프탭 선택.

2.클래스세팅

3.부모클래스를 아까 만든 c++클래스로 설정해준다.

헤더파일에 바인딩할 버튼들을 스샷처럼 코딩하는 방식.

 

주의. 이름똑같이 해줄것

 

mainmenu의 헤더파일

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"

#include "MainMenu.generated.h"


/**
 * 
 */
UCLASS()
class TEST_API UMainMenu : public UUserWidget
{
	GENERATED_BODY()

public:
	
protected:
	//초기화 + 유무를 검출하기위해 bool반환
	virtual bool Initialize();

	



private:

	//UMG의 버튼과 코드를 바인딩하기위한 버튼선언.

	UPROPERTY(meta = (BindWidget))
		class UButton* Host;

	UPROPERTY(meta = (BindWidget))
		class UButton* Join;

	UFUNCTION() // 호스트가 되는 함수
		void HostServer();

	
};

 

mainmenu의 소스파일.

bool UMainMenu::Initialize()
{
	bool Success = Super::Initialize();
	if (!Success) return false;

	if (!ensure(Host != nullptr)) return false;

	UE_LOG(LogTemp, Warning, TEXT("succecess!!!"));
	//호스트 버튼이 눌렸을때 HostSever 함수가 호출되도록 바인딩.
	Host->OnClicked.AddDynamic(this, &UMainMenu::HostServer);

	return true;
}

void UMainMenu::HostServer()
{
	UE_LOG(LogTemp, Warning, TEXT("I'm gonna host a server!"));

	
}

 

이제 호스트 버튼을 누를때마다 로그가 뜨는것을 확인 할 수있다.

 

 

 

include <memory.h> 헤더파일을 포함시켜야함

유니크포인터.

unique_ptr -->이 포인터가 한 인스턴스를 가지면 다른 포인터가 얘를 가리키려고할때 컴파일에러로 막는다.

또 유니크포인터가 스코프를 탈출할때 소멸자단에서 메모리를 해제해준다.

순수c++11 --> std::unique_ptr<타입> 이름(new 타입(매개변수))

c++14--> std::unique_ptr<타입> = make_unique<타입>(매개변수)

 

언리얼c++ -->TUniquePtr

https://api.unrealengine.com/INT/API/Runtime/Core/Templates/TUniquePtr/index.html

 

 

공유포인터.

c++14이후 나왔다.

유니크 포인터와 달리 얘는 여러포인터가 나를 참조할수있다.

다만 내가 가지고있는 데이터와

내가 몇개의 포인터한테 공유되고있는지 카운팅한다.

강한참조횟수와 약한참조횟수를 카운팅함. 이외에 잡다한기능 몇개 있음.

 

 

Uobject가 이에 해당된다.

참조횟수가 카운팅되고 GC가 메모리를 회수해간다.

Newobject< >로 메모리할당이 된경우

Uobject::ConditionalBeginDestroy() 멤버함수로 수동 메모리해제도 가능하다.

이 이하는

이미 c++절에서 설명했고

언리얼 레퍼런스보다 더 정리를 잘할수 없어서 그냥 링크남기고 ㅌㅌ 하겠따.

주의사항 짧게하자면 공유포인터는 선언할때 초기화 안하면 안되고

isvalid로 유효성 검사를 할수있다.

공유레퍼런스는 널포인터를 가리키는게 안되서 안전하니까.

왠만하면 공유 레퍼런스 쓰란다.

http://api.unrealengine.com/KOR/Programming/UnrealArchitecture/SmartPointerLibrary/SharedPointer/

 

약한포인터.

공유포인터가 지들끼리 강한참조로 서로 공유하고있으면 서로 참조할 경우.

가비지컬렉터가 돌때 참조횟수를 기준으로 검열을하는데

이때 서로 공유하고있는 애들끼리 무한으로 참조하고 앉아있으면 가비지컬렉터는 얘는 쓰레기가 아닌줄알고

메모리에 계속 냅둔다 이것의 순환참조의 문제다. .

그래서 약한 포인터가 나왔다.

무조건 공유포인터 하나를 주인으로 참조하고있어야 하는데.

약한포인터는 공유포인터가 없어지면 주인따라서 같이 죽어버린다. 때문에 메모리에 남는일이 없다.

그치만 , 그 이유때문에 약한포인터는 참조한다고했을때 언제 없어질지몰라서 위험하다.

떄문에 lock으로 잠가서 넘겨주는것이 있다.

아래코드는 예들들어 설명.

 

http://api.unrealengine.com/KOR/Programming/UnrealArchitecture/SmartPointerLibrary/WeakPointer/index.html

세팅하기

  이렇게 c++기반 게임인스턴스 하나 만들어요

  맨마지막거가 게임인스턴스입니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

서드퍼슨맵을 복사해서 로비맵을 생성.

둘이 서로 알아먹기만 할수있게 표시하면됨 

 

 

 

 

 

맵 &모드에서 게임시작하면 맨처음나오는 맵과 서버가 맨처음 나오는맵을 설정

 

  

생성자초기화와 언리얼에서 제공하는                   게임 인스턴스 초기화의 차이.

 

#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "PuzzlePlatformsGameInstance.generated.h"

/**
 * 
 */
UCLASS()
class TEST_API UPuzzlePlatformsGameInstance : public UGameInstance
{
	GENERATED_BODY()
		//c++ 생성자 단에서 초기화 
		UPuzzlePlatformsGameInstance(const FObjectInitializer& ObjectInitializer);

	//언리얼 게임인스턴스 단에서 초기화 
	virtual  void Init();

	UFUNCTION(Exec)
		void Host(); //호스트

	UFUNCTION(Exec) //조인 + 접속아이피
		void Join(const FString& Address);

	
};

 

 

 

// Fill out your copyright notice in the Description page of Project Settings.

#include "PuzzlePlatformsGameInstance.h"

#include "Engine/Engine.h"

UPuzzlePlatformsGameInstance::UPuzzlePlatformsGameInstance(const FObjectInitializer & ObjectInitializer)
{
	UE_LOG(LogTemp, Warning, TEXT("GameInstance Constructor"));//생성자 초가화
}

void UPuzzlePlatformsGameInstance::Init()
{
	UE_LOG(LogTemp, Warning, TEXT("GameInstance Init")); //인스턴스 초기화
}

void UPuzzlePlatformsGameInstance::Host()
{
	UEngine* Engine = GetEngine(); //게임엔진의 현재 인스턴스를 가져움

	if (!ensure(Engine != nullptr)) return;

	Engine->AddOnScreenDebugMessage(0, 2, FColor::Green, TEXT("Hosting")); //로그띄워줌

	UWorld* World = GetWorld(); // 레벨의 현재 레벨을 가져옴

	if (!ensure(World != nullptr)) return;
	//서버전용 .  서버를 입력한 경로의 맵으로 이동시킴, 클라이언트랑 같이감 서버가 접속중인 클라이언트들의
	//플레이어 컨트롤러에서 ClientTravel을 호출함.
	World->ServerTravel("/Game/ThirdPersonCPP/Maps/ThirdPersonExampleMap?listen");
}

void UPuzzlePlatformsGameInstance::Join(const FString& Address)
{
	UEngine* Engine = GetEngine();

	//현재 클라의 플레이어컨트롤러의 첫번째 플레이어 컨트롤러 가져옴
	APlayerController* PlayerController = GetFirstLocalPlayerController();

	if (!ensure(Engine != nullptr)) return;
	//로그
	Engine->AddOnScreenDebugMessage(0, 5, FColor::Green, FString::Printf(TEXT("Joining %s"), *Address));

	//아이피가 유효할때 호출되면 입력된 아이피주소의 서버로 이동함.  
	//인텔리센스 빨간줄 무시하셈.
	PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute);

	
}

 

결과.

 

 

 

+ Recent posts