평생 공부하는 빠타박스 블로그 : Learning is Happiness
article thumbnail
SMALL

본 내용은 기존 헤더 파일에 의해 구동됨으로 따라하시기 힘듭니다. 

그러니 참고만 하여 확인 하길 바랍니다. 

 

이 내용은 Visual studio DirectX 10(11)기반 32bit로 만들었습니다.

 

 

 

 

절차 지향 언어에서 

지금은 다양한 분야에 쓰이고 있기 때문에 객체지향언어로 변경 되게 되었다. 

객체지향언어는 기존 컴퓨터 명령어의 목록으로 보는 시각에서 벗어나 여러 개의

독립된 단위, "객체"들의 모임으로 파악하고자 하는 것이다. 

 

각각의 객체는 메세지를 주고 받고, 데이터를 처리할 수 있다.

객체지향프로그래밍은 프로그램을 유연하고 변경이 쉽게 만들기 때문에 

대규모 소프트웨어 개발에 많이 사용된다. 

또한 개발과 유지보수를 간편하게 하며,

보다 직관적인 코드 분석을 가능하게 하는 장점이 있다. 

 

게임은

기획 -> 설계 -> 구현 -> 검증  -> 유지보수

등을 하게 되는데 

통상 우리가 구현하는 설계 부분에서 비용이 많이 들 줄 알았는데.

나중에 배포후 유지보수때 오히려 더 많은 비용이 발생 하게 된 것이다.

 

절차 지향 같이 처리속도와 실행속도가 빠른대신 

유지보수가 어렵고 실행 순서가 정해져 있어 코드의 순서가 

바뀌면 동일한 결과를 보장하기 어렵다 즉) 위 코드를 바꾸면 아래 코드 전부 바꿔야 할 수 있음

디버깅이 어려운 단점 이 있다.

 

즉 변하지 않고 유지보수를 잘 할 필요없고 구조나 순서가 잘 바뀌지 않는 곳에서는

C언어인 절차지향언어가 어울릴 수 있다. 

그러나 게임 과 같이 이벤트 아이템 버그 등을 잡기 위해서는 계속해서 수정이 가미되야 하기에

객체지향언어를 선호할 수 밖에 없다. 

-학문적으로 정리한 소프트웨어공학

 

 

 

 

가장 단순한 집계 데이터 유형 중 하나는 구조체 (struct) 

하나 이상의 변수를 그룹 지어서 새로운 자료형을 정의 하는 것이다. 

 

 

struct를 가지고 class가 만들어졌는데

단순 데이터 저장을 struct사용 (아이템 같은것들) 

복잡한 내용의 캐릭터나 고정되는 것을 Class를 사용

 

접근 지정자 (캡슐화) : 

-  Class  - 

내가 가진 데이터 한클래스가 가진 데이터를 클래스 내부에서만 사용하자

단일치기의 원칙 

한클래스의 기능을 해당 클래스에 대한 기능만을 제공해야 한다. 

ex) 플레이어 제작하는데 몬스터 기능까지 얹으면 관리가 어려워진다. 

복잡한 것을 분리 하자는 개념을 'Class'

 

 

 

::(콜론콜론) : 누구의 구역내에 있다 라는 것을 알려줌 

ex) void Text::RenderText  = Text 영역 내에 있는 RenderText 함수를 h에서 밖에서 정의 하겠다

밖이지만 이 영역내에 있다고 해줬으니 h안에 있는public 에 접근이 가능해진다. 

생성자(Constructor)는 객체 지향 프로그래밍에서 객체의 초기화를 담당하는 서브루틴을 가리킨다. 생성자는 객체가 처음 생성될 때 호출되어 멤버 변수를 초기화하고, 필요에 따라 자원을 할당하기도 한다. 객체의 생성 시에 호출되기 때문에 생성자라는 이름을 붙임  = Text.cpp 

 

3. 아래 정적할당과 동적할당 추가 설명 : 정적할당은 선언과 동시에 초기화 되고 메모리에 할당된다.

동적할당은 변수만 선언 해 놓고 내가 원하는 시점에 할당할 수 있다. 

NULL = 0번지는 없으니 0번지 라면 비어있는 포인터 다 라고 간주 

 

ex) 필요한 시점이 Update이면 아래 main.cpp 참고 

main.cpp 

#include "stdafx.h"
#include "System/Device.h"
#include "Text.h"

//#pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")

Text text; //이 함수는 public에 있는 Text();를 출력 
Text text2(100, 100, 255, 0, 0, "Class"); //이 파라미터에 맞는 public에 있는 float부분을 출력한다.
//위처럼 쓰인 것이 정적할당 방식 

Text* text3 = new Text();
Text* text4 = NULL;

void InitScene()
{
	//text.RenderText(100, 100, 255, 0, 0, "Class"); //한번만 값 세팅해줌 
}

void DestroyScene() //지워지는 곳 .마지막에 지정됨 
{
	delete text3; // 마지막에 이얘를 지우기로함 
	text3 = NULL; // 원칙적으로 NULL 시켜준다. 

	if (text4 != NULL)
	{
		delete text4;
		text4 = NULL; //
	}
}

void Update()
{
	if (Key->Press('D')) //Text.cpp 설정후 
		text2.MoveRight();
	else if (Key->Press('A'))
		text2.MoveLeft();

	if (Key->Press('W'))
		text2.MoveUp();
	else if (Key->Press('S'))
		text2.MoveDown();

	text3->MoveRight();

	if (text4 == NULL && Key->Press('P'))
		text4 = new Text(0, 200, 0, 0, 255, "New");
        // 처음에 NULL이였을때 text4를 할당 하고 그다음 Update실행시 NULL아니여서 PASS함  

	if (text4 != NULL && Key->Press('O')) 
	{
		delete text4; //원래 공간에 주소가 들어갈텐데 사라진 주소를 참조하고 있는데 이것을 허상포인트 라고함 
		text4 = NULL; // NULL로 초기화 한번 해야함 이것이 없으면  위 주소값이 NULL이 아니라고 판단함
	}

	if (text4 != NULL)
		text4->MoveRight();
}

void Render()
{
	text.Render();
	text2.Render();
	text3->Render();

	if (text4 != NULL)
		text4->Render();
}

 

stdafx.h -

Float : r, g, b, a ;

a = 투명도  0~1까지의 값만 저장 하는데 r을  r/255.0f 바이트 나누기 인트라서 플롯형이 안되서 이렇게 만듬 

rgb 설정해주고 a =는 없으면 불투명 1.0f 

 

예전 방식이였다면 Text::Text 함수 같은 것이 지금처럼 묶이지 않고 중구난방 이였을 것이다. 

지금은 구역을 묶어 줄 수 있는 개념이 Class이다. 

 

셋팅한 값을 쓰고 싶기도 하고 할때 중간에 임의로 변수의 값을 변경할때

어디선가 임의로 바꾸면 찾기 힘든데 그래서 private을 써서 외부에 접근이 불가능 해지는데

값을 변경하는 함수를 private를 통해서만 값을 변경하게 된다. 

값을 어디서 변경했는지 함수만 찾으면 되서 Class를 사용함으로써 편해진다(Text.h) 

 

 

생성자     

생성자는 클래스 이름으로 나타난다.

ex) public:

{

Text(); // 이 함수는 리턴이 불가능 하기에 void같은 것들이 아무것도 안들어감 

 

텍스트 구역내에 Text라는 이름의 함수를 정의 한다 

//생성자     
//생성자는 클래스 이름으로 나타난다. 

//ex) 

public:
{
	Text(); // 이 함수는 리턴이 불가능 하기에 void같은 것들이 아무것도 안들어감 
public:
..
.
private: 
	D3DXVERTOR2 Location;
    . .
    . .
}//text.h

" --------------------------------------------------------"

//text.cpp

//텍스트 구역내에 Text라는 이름의 함수를 정의 한다 
Text::Text() // 생성자 함수는 이곳에 선언될때 자동으로 호출 한다. 
{//이렇게 클래스 타입으로 부터 만들어진 변수를 객체(object==instance) 라고 부른다. 
	Location = {0, 0};
    Color ={ 0, 0, 0, 1};
    Content = "";
	//보통 초기값은 어떻게 해야 될지 몰라서 초기화를 해둠
}

 

Text.cpp

#include "stdafx.h"
#include "System/Device.h"
#include "Text.h"

Text::Text()
{
	Location = { 0, 0 };
	Color = { 0, 0, 0, 1 };
	Content = "Text";
}

Text::Text(float x, float y, BYTE r, BYTE g, BYTE b, string content)//생성자로 Text::로 표시 
{
	Location = { x, y };
	Color = { r / 255.0f, g / 255.0f , b / 255.0f, 1.0f };
	Content = content;
}

void Text::MoveRight()
{
	Location.x += 0.1f;
}//라이트

void Text::MoveLeft()
{
	Location.x -= 0.1f;
}//레프트

void Text::MoveUp()
{
	Location.y -= 0.1f;
}//업

void Text::MoveDown()
{
	Location.y += 0.1f;
} //다운

void Text::Render()
{
	RenderImGuiText(Location.x, Location.y, (BYTE)Color.r * 255, (BYTE)Color.g * 255, (BYTE)Color.b * 255, Content);
} // BYTE형으로 들어가야 한다.(설명으로인해 복잡해보임)

 

public: 어디서든 접근 가능(클래스에서 접근가능한) 

private: 클래스 내( 클래스 내에 정의된 함수)에서만 접근 허용(외부접근 할 수 없음) 멤버 변수들이 들어감 

protected: 상속관계에 놓여있을때, 유도 클래스에서의 접근 허용 

 

private에서 들어간 함수나 변수를 멤버함수 멤버 변수라고 부른다. 

 

구조체 에서는 키워드 안써도 멤버에 접근 할 수 있었는데. 즉 Public 이였는데

클래스는 키워드를 안쓰면 외부에서 접근이 불가능 이다. 

헤더파일 지정 을 키워드 지정 안하면 cpp에서 접근이 불가능 하다. 

 

일반적으로 

멤버변수는 private에다 넣고

함수들이 접근해서 어떤 행동들을 하기에 public에 넣는다.

 

 

ragacy code : 마이클 패더스의 정의 

'The main thing that distinguishes legact code from non-legact code is test, or rather a lack of tests,'

레거시 코드란 테스트가 불가능 하거나 기능이 정상적이지 않거나, 난해한(가독성이 떨어지는)코드를 의미한다. 

흔하게 1인 개발자의 특수한 경우를 제외하고는 협업을 하게되는데

과정 종종 난감한 상황이 있다. 흔히 "똥 싸놨다"라고 표현 하는데 

코드의 가독성이 떨어짐, 코드의 규약이 없음, 코드의 결함도가 높음, 시간이 없어서 땜빵 코드작성, 여러가지 

원인들로 인해서 화석 처럼 굳어진 코드를 흔히 '레거시 코드'라고 표현 한다. 

 

 

ragacy code : 옛날 DX초창기 옛날 코드를 유지 안하면 왠만하면 유지해둠(수정하기 어렵기 때문) 

옛날 문법을 유지하기에 포인터 기반 

 

D3DXVECTOR2 : 헤더에 구조체로 선언된 파일 x, y를 따로 사용할 필요가 없는 함수 

D3DXCOLOR : 색 값을 불러들임 

D3DX : DirectX 3D Extention 

 

 

선을 그리거나 하는 것을 Text.h 에 기능을 추가하게 되면 관리가 힘들어질 것이다. 

하나에 여러기능을 관리하기는 힘들다.

Class 는 단일기능만을 가진다. 

객체 지향 설계원칙 SOLID원칙 한 클래스는 하나의 역할 만을 갖는다. 

 

클릭 하면 링크 나옴

 

//.h에서 typedef struct D3DXVECTORR2 에대한 설명 

//옛날 방식 
struct A
{
   ...
};
struct A ob; //쓰기가 귀찮아짐 

//그래서 변경된게 

typedef struct A // typedef가 'A'를 
{
  ...
} A; //이렇게 줄이겠다는 역할을 해준다. 
A ob;

 

 

 

Text.h

#pragma once

class Text
{
public:
	Text();
	Text(float x, float y, BYTE r, BYTE g, BYTE b, string content); //원래 아래있던 public에 있었음 
    //여기 위치함으로써 생성자가 됨

public:
	void MoveRight(); //함수정의 만들기 (하나만들때)
	void MoveLeft(); //여러개 만들때는 선언 정의만들기 
	void MoveUp();
	void MoveDown();
	
public:
	void Render();

private:
	D3DXVECTOR2 Location;
	D3DXCOLOR Color;
	string Content;
};

 

단축키 

Ctlr + . = > 텍스트 정의 만들기 or 선언 정의 만들기 

 

---------------

컴파일 과정 중에 어딘가 에 할당 된다. 

1. 정적 메모리 할당 : 메모리의 크기가 하드 코딩되어 있기 떄문에 프로그램이 실행 될때 이미 해당 메모리의 크기가 결정되는 것이 특징

장점 : 헤제하지 않음으로 인한 메모리 누수와 같은 문제를 신경쓰지 않아도 된다. 실행 도중에 해제되지 않고, 프로그램이 종료할 때 알아서 운영체제가 회수한다.

단점 : 메모리의 크기가 하드 코딩되어 있어서 나중에 조절 할 수 없다. 스택에 하당된 메모리이므로 동적 할당에 비해 할당 받을 수 있는 최대 메모리에 제약을 받는다. 

 

동적 메모리 할당 : 컴퓨터 프로그래밍에서 실행 시간 동안 사용할 메모리 공간을 할당하는 것을 말한다. 사용이 끝나면 운영체제가 쓸 수 있도록 반납 하고 다음에 요구가 오면 재 할당을 받을  수 있다. 

프로그램이 실행하는 순간 프로그램이 사용할 메모리 크기를 고려하여 메모리의 할당이 이루어지는 정적 메모리 할당과 대조적 이다. 

 

장점 : 상활에 따라 원하는 크기만큼의 메모리가 할당 되므로 경제적이며, 이미 할당된 메모리라도 언제든지 크기를 조절할 수 있다. 

단점 : 더 이상 사용하지 않을 때 명시적으로 메모리를 해제해 주어야 한다. 

 

추가 ) 

2. 동적할당은 : 컴파일 완료 되서 실행 시켰을때 (런타인) 상황하에 할당 함 (실시간으로) 

 

정적할당 : 그냥 변수 그 함수가 끝날때 메모리에서 제거됨 (값들이) 

전역변수라면 (Text) 프로그램이 종료 될때 소멸 된다. 

 

동적할당 : 우리가 소멸 시키지 않는한 거의 영원에 가깝에 있다.

운영체제가 시간이 지나면 알아서 제거 해주긴 한다. 

ex)어느 프로그램중에 컴퓨터를 느리게 하는 프로그램이 있는데. 메모리를 차지 하고 있는 프로그램이라서

시간이 지나서 운영체제가 필요없음을 느끼고 메모리에서 할당을 없애 버림.

 

그러니 우리가 필요한 때에 포인터를 지워줘야 한다.

delete text; 

-------------------------------------------------------------------------------

new연산자 = 뒤에 Text를 보고

1.이공간의 크기 만큼 메모리의 어딘가에 만든다.

2. 생성자 Text(); 생성자 함수로 호출을 해준다.

3. 주소안에 text안에 변수로 할당을 해주고 

4. Text* 에 포인터로 받는다 (주소를 받는것) 

 

text의 변수의 크기는? 4바이트 (32비트 안에서)  

4바이트 어딘가에 할당된 곳에 이 주소를 갖고 있고

포인터를 이용한 이공간에 접근할 수 있다.

 

Text* text = new Text();

//지워주고 싶을때 
//delete text;

//일반적으로 delete를 사용하여 메모리가 제거 됬느냐는 확인이 안된다.
//회사에는 추적하기위한 Tool들이 있다 (프로파일러)

 

게임 프로그래밍은 지우고 추가 하는것이 자유로워야 한다.

메모리 사용량이 꽉차기 전에 임의로 제거해줘야 한다. 

맵에서 보이는 곳만 렌더링 해주고 안보이는 곳은 없앤다 (메모리 최적화를 위함)


C#은 제거나 이런게 자유롭지 않음 (다루기가 쉬움) 임의로 제거할 수 없음 시점은 C#이 결정한다. 

제거하는 동안 렉이 걸린다. (유니티는 왜.. C#일까? 다루기 쉬워서? ) 

 

C++ 이용하는 이유는 프로그래머가 제어가 쉽다. 

언리얼은 알아서 제거하는 기능도 있음 (게임에 특화된 엔진) 

 

 

연산자 오버라이딩 : 개발 편의를 위해 생성된 인스턴스 끼리, 혹은 인스턴스와 다른 변수간 연산자를 통해 연산할 수 있도록 하는 것. 

ex) Point라는 클래스 안에 int형 변수 x, y가 있고 point1,과 point2간 덧셈 연산 혹은 곱셈등 각종 연산을 하고 싶을때 연산자 오버로딩을 통해 가능 하다. +를 오버로딩 하면아래 처럼 사용가능 

point pos1(3,4);
point pos2(10,20);

point pos3 = pos1 + pos2;

 

수정이 필요한 부분이 있다면 피드백 해주시길 바랍니다. 

728x90
728x90
LIST
profile

평생 공부하는 빠타박스 블로그 : Learning is Happiness

@공부하는 PPATABOX

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!