23-04

Sandy·2024년 3월 6일

[Today I Learned]

목록 보기
4/18

230403_2048,스택,큐구현

2048 만들기

각 숫자 블럭 모델링하기

2빨 4주 8노 16파 32남 64보 128핑 256하 512은 1024금 2048투명

블록사이즈, 전체 판 사이즈 정하기

키보드 상하좌우 하면 전체 회전하도록 하기

마우스로 드래그 해서 회전, 때면 그 방향으로 회전하기

리셋버튼, 멈추기 버튼, 플레이 타임 기록

클리어하면 점수 기록 판 보이기


  1. 스택
    a. char 자료형을 입/출력하는 스택을 구현한다.
    b. 스택의 상태에 따른 예외처리할 것.
    c. (심화)스택의 사이즈를 변경할 수 있도록 할 것.

  2. a. char 자료형을 입/출력하는 큐를 구현한다.
    b. 큐의 상태에 따른 예외처리 할 것.
    c. 언제든 큐의 크기만큼 사용 가능할 것. (환형 큐 등)
    d. (심화)큐의 사이즈를 변경할 수 있도록 할 것.
/// 스택
/// 함수, 배열, 전역변수
/// 인덱스 예외처리, 타입 1개로 고정
/// 2023.03.01 Sandy

// 외부 라이브러리 헤더 포함
#include <iostream>
using namespace std;

int g_Stack[10];
int g_Index = 0; // 값을 넣을 수 있는 곳을 가리킨다

// 스택 초기화
void ResetStack()
{
	for (int i = 0; i < 10; i++) 
	{
		g_Stack[i] = -1;
	}

	return;
}

/// <summary>
/// 스택의 내용을 출력한다
/// </summary>
void PrintStack()
{

	for (int i = 0; i < 10; i++)
	{
		if (g_Stack[i] == -1)
		{
			cout << "[ ]" << " ";
		}
		else
			cout << "[" << g_Stack[i] << "]" << " ";
	}
	cout << "\n\n";

	return;
}

/// <summary>
/// 데이터 하나를 스택에 넣는다
/// </summary>
/// <param name="data"></param>
void PushDataToStack(int data)
{
	if (10 <= g_Index)
	{
		cout << "스택이 가득 찼습니다\n";
		return;
	}
	// 스택에 g_Index 이용해서 data 넣기
	g_Stack[g_Index] = data;
	
	g_Index++;

	PrintStack();
	return;
}

int PopDataFromStack()
{
	if (g_Index <= 0)
	{
		cout << "스택이 비었습니다\n\n";
		return 0;
	}

	int _result = 0;
	// idx 스택의 탑, -1 해서 그 데이터 가져오기
	_result = g_Stack[g_Index-1];
	g_Stack[g_Index-1] = -1;

	g_Index--;
	cout << "스택에서 " << _result << "뺐습니다\n\n";

	PrintStack();

	return _result;
}

int main() 
{
	ResetStack();
	PushDataToStack(10);

	PopDataFromStack();
	PopDataFromStack();
	PopDataFromStack();

	return 0;
}
/// 큐_v1
/// struct로 my_queue 선언
/// 할 일 : templete, circular
/// 2023.03.01 Sandy

// 외부 라이브러리 헤더 포함
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

/*
https://en.cppreference.com/w/cpp/container/queue
https://www.boost.org/doc/libs/1_81_0/doc/html/boost/circular_buffer_sp_idm5277.html

Element access
front();	// Access next element
back();		// Access last element

Capacity
empty();	// checks whether the underlying container is empty
size();		// returns the number of elements

Modifiers
push();		// inserts element at the end
pop();		// removes the first element
*/

#define MAX_QUEUE_SIZE 10
typedef struct
{
	int data[MAX_QUEUE_SIZE];
	int front;
	int rear;
}my_queue;

void init_queue(my_queue* q);

int front(my_queue* q);
int back(my_queue* q);

bool empty(my_queue* q);
int size(my_queue* q);

void push(my_queue* q, int data);
int pop_int(my_queue* q);
void pop_void(my_queue* q);

bool is_full(my_queue* q);
void print_queue(my_queue* q);

void init_queue(my_queue* q)
{
	q->front = 0;
	q->rear = 0;
	return;
}

int front(my_queue* q)
{// rear-1 idx에서 맨 앞 데이터 보기
	int ret;
	if (empty(q))
	{
		cout << "큐가 비었다\n";
		return -1;
	}
	ret = q->data[q->rear-1];
	return ret;
}

int back(my_queue* q)
{// front idx에서 맨 뒤 데이터 보기
	int ret;
	if (empty(q))
	{
		cout << "큐가 비었다\n";
		return -1;
	}
	ret = q->data[q->front];
	print_queue(q);
	return ret;
}

bool empty(my_queue* q)
{// front == rear
	bool ret;
	ret = q->front == q->rear;
	return ret;
}

int size(my_queue* q)
{// rear - front = size
	int ret;
	ret = q->rear - q->front;
	return ret;
}

void push(my_queue* q, int val)
{// rear idx에다가 val 넣기, rear++ 해서 idx 이동하기
	if (is_full(q))
	{
		cout << "큐가 찼다\n";
		return;
	}
	q->data[q->rear] = val;
	q->rear++;

	print_queue(q);
	return;
}

int pop_int(my_queue* q)
{// front idx에서 데이터 빼기, front++ 해서 idx 이동하기
	int ret;
	if (empty(q))
	{
		cout << "큐가 비었다\n";
		return -1;
	}
	ret = q->data[q->front];
	q->front++;

	print_queue(q);
	return ret;
}

void pop_void(my_queue* q)
{// front++ 해서 idx 이동하기
	if (empty(q))
	{
		cout << "큐가 비었다\n";
		return;
	}
	q->front++;
	print_queue(q);
	return;
}

bool is_full(my_queue* q)
{
	bool ret;
	ret = q->rear >= MAX_QUEUE_SIZE;
	return ret;
}

void print_queue(my_queue* q)
{
	cout << "\nfrontIdx : " << q->front << ", rearIdx : " << q->rear << "\n";
	for (int i = 0; i < MAX_QUEUE_SIZE; i++)
	{
		if (i < q->front || i >= q->rear)
			cout << "[ ] ";
		else
			cout << "[" << q->data[i] << "] ";
	}
	cout << "\n\n";
}

int main()
{
	my_queue q;
	init_queue(&q);
	print_queue(&q);
	push(&q, 0);
	push(&q, 1);
	push(&q, 2);
	push(&q, 3);
	push(&q, 4);
	push(&q, 5);
	push(&q, 6);
	push(&q, 7);
	pop_void(&q);
	int frontVal = front(&q);
	cout << "frontVal : " << frontVal << "\n";
	int backVal = back(&q);
	cout << "backVal : " << backVal << "\n";
	pop_int(&q);
	pop_int(&q);
	cout << "size : " << size(&q) << "\n";
	cout << "is empty : " << empty(&q) << "\n";
	pop_int(&q);
	cout << "is full : " << is_full(&q) << "\n";
	push(&q, 6);
	push(&q, 6);
	push(&q, 6);
	push(&q, 6);

	cout << "is full : " << is_full(&q) << "\n";

	return 0;
	
}

Doxygen

설명서 대신 문서 형태로 만들어준다

230411_테일러급수

Series (급수)

수열의 각 항을 순서대로 더한다


테일러 급수

미분가능한 함수 → 여러번 미분해서 다항식의 합으로 비슷하게 만들었다

로그함수 : 정의역에서 무한대로 발산한다

테일러 정리

접선을 통해 함수를 근사하는 선형근사 (linear approximation) 를 일반화한 다항함수 형태이다

로그함수의 테일러근사

x축에 접하지 않고 x축을 교차하지 않는다

→ 정의역에서 무한대로 발산한다

→ 함수값이 양의 방향으로 무한히 커지거나 작아진다

매클로린 급수

a = 0 일 때의 테일러 급수

멱급수

어떤 수를 자연수의 거듭제곱으로 계속해서 더한다

삼각함수의 테일러 근사

sin(x) = x - x^3/3! + x^5/5! - x^7/7! …

cos(x) = 1 - x^2/2! + x^4/4! - x^6/6! …

테일러 급수의 정확도

정의에 따라 찾는 근사값보다 테일러 급수를 이용한 것이 정확도가 높은 이유?

→ 테일러 급수는 무한항으로 이루어진다

arcos

이동을 하기 위해 회전을 한다, 회전각을 구해야 한다

삼각법

삼각형의 각도에 따라서 변의 길이가 특정 비율을 가진다

Trigonometric 삼각함수

삼각비의 정의역 예각에서 일반각으로 확장했다

테일러급수전개를 활용한 전개


다형성에 대해 설명해라

virtual 함수에 대해 설명해라

소멸자에 virtual을 쓰는 이유는 무엇인가

volatile 키워드에 대해 설명해라

인터페이스 추상 클래스 차이

스마트 포인터?


객체가 여러 형태를 가질 수 있다는 것이다 상속을 하면 부모 클래스의 기능을 가져온다. 이 때 사용하는 함수가 달라질 수 있다. 그래서 런타임에서 달라질 수 있다. 오버로딩에서도 객체는 다형성을 가질 수 있는데 이것은 컴파일 타임에서 갖는 다형성이다.

상속을 할 때 부모에서 이 내용은 오버라이딩을 할 수 있다고 표현하는 것이다 새롭게 내용을 쓰면 그렇게 작동한다.

소멸자는 delete로 사라지는 것이다. virtual은 가상함수로 하기 위해 붙인다. 소멸자는 생성자와 같이 객체가 사용되는 동안에 호출되고 사용이 끝나면 호출된다. 추측하는 내용은 오버라이딩을 하기 위해서 기본적으로 들어가는 것인가...?

volatile 전혀 모른다

인터페이스는 기능을 추가하는 라이브러리 같은 것이고 추상클래스는 프레임워크 같은 것이다 인터페이스를 추가하면 이런 더해서 기능을 가질 것이라고 기대한다. 추상클래스에서는 부모의 내용을 베이스로 또 다른 객체를 만들 수 있도록 한다.

GC를 하기 위해 만들어진 객체이다. 다른 곳에서 사용하기 위해 쓰고 있으면 메모리에서 지우지 말라고 카운팅을 한다. malloc과 같이 메모리 관리를 해야하는 부분을 프로그래머가 하지 않을 수 있도록 해준다.

모르는 부분 : 가상함수, 가상함수 테이블, 함수포인터, 객체의 생성과 소멸, volatile 키워드, smart pointer 구현, GC, 멀티쓰레드,

230413_포인터,ref

참조자 Reference

함수에서 ref 키워드와 동일하게 & 을 붙이면 부른 변수의 메모리 주소를 갖고온다

const int* ptr = #

ptr이 담고있는 num 변수가 const되어서 변경 불가능하다 ptr 자체를 상수화 하려면 int* const ptr = # 과 같이 해야한다

arr[i][j] == ( (arr + i) + j)

배열에서 인덱스로 접근해서 값을 가져오는 []연산은 포인터 변수에 *해서 값을 가져오는 연산과 같다

Function Call

함수는 호출되어서 사용된다. 이 때 메모리에 스택 구조로 호출되고 사라진다.

Stack Frame

스택 영역에 저장되는 함수의 호출 정보이다

230414_StackFrame

Function Call

함수를 부른다. 코드 영역에 있던 내용을 주소값을 가져와서 데이터를 넣고 스택 구조로 실행한다

Stack Frame

함수를 부를 때 갖고있는 데이터이다. 매개변수, 로컬 변수들이 있다

함수포인터

함수를 포인팅 하는 것이다. 변수를 담는 주소가 있듯이 함수를 담는 주소가 있다

연산자 우선순위

컴파일러가 연산을 할 때 어떤 순서로 하는지이다. 실행순서와 우선순위가 같은 것이 아니다. a++에서는 ++ 연산을 먼저 하고 ++의 실행은 ; 이 끝난 후에 작동된다.

230415_Matcap

Matcap

Material Capture 물체의 표면의 빛, 색 등을 미리 제작된 텍스쳐 이미지로 표현한다

Raytracing

빛이 씬 내 객체들에서 반사, 굴절, 그림자 효과등을 거치며 발사된 광선과 교차점을 만들어 간다

씬 구성 → 광선 발사 → 교차점 계산 → 셰이딩 → 반복 → 이미지 생성

Viewnormal

객체의 표면 방향을 나타내는 벡터

UV 매핑

2D 이미지의 각 픽셀을 3D모델의 표면에 매핑한다

Viewnormal ↔ UV

-1~1 → 0~1로 변화시킨다

렌더링 파이프라인

Input Assembler → Vertex Shader → Rasterization → Pixel Shader

230417_2048

어제 : 기획서 작성

오늘 : 2048 백준 문제 풀이 / 프로젝트 생성하기 / 다른 사람 코드 이해하기

이슈 : Game.c, h, Main.c,h 파일 만들기

230418_2048,OS

어제 : 프로젝트 생성, 2048 알고리즘 고민

오늘 : 2048 알고리즘 고민 / 2048 프로토 만들기

이슈 : 내가 짜기보다 기존 로직 그냥 갖고와야겠다고 생각이 바뀌었다!

OS (Operating System)

하드웨어를 작동시키기 위한 소프트웨어

프로세스 관리

Virtual Memory

램 용량 부족할 때 second Memory 쓴다

각 프로세스가 독립적인 virtual memory를 쓴다 → 모든 프로그램이 메모리 0부터 쓰게 해준다

Process

프로그램을 메모리에 올린 상태이다

Multi Process, Multi Thread

스레드는 여러 코어를 쓰려면 스레드 프로그래밍을 해줘야 한다

프로세스는 여러 cpu에서 자동으로 나누어져서 실행이 된다

Context Switching

하나의 코어에서 여러 프로세스, 스레드를 교체하면서 바꾸는 것이다

thread : 각 스택 영역 변경 작업 해야한다

Process Scheduling

라운드로빈 : 프로세스를 일정 시간동안 실행하고 context switching으로 다른 프로세스로 바꾼다

priority : 높은 우선순위를 먼저 실행한다

Memory Leak

힙에 동적 메모리 할당하고 해제하지 않으면 발생한다

Cache Miss / Cache Hit

cpu가 요청한 것이 이미 캐시 메모리에 있다

Hit 이면 램에 다시 접근을 안해서 빨라진다

Memory Fragmentation

Internal : 할당된 메모리 공간이 필요보다 크다

External : 전체적으로 봤을 때 사용할 수 있는 메모리가 있는데 나누어져있어서 못 쓴다

FIFO / LRU / LFU

큐 / 최근 사 기반 least recently used / 사용 빈도 기반 least frequently used

230419_2048,Pointer

어제 : 2048 프로토타입 - move알고리즘, 화면에 출력하기

오늘 : 다 찼을 때 가로, 세로 키 입력이 안되는 문제 해결하기 / 프로토 완성해서 빌드파일 만들기

이슈 : GetAsyncKeyState() 때문인지 키 입력 여러 번 된다 / 게임 로직이 제대로 되고 있는지 확인하기

int (*fptr) (int);

int 반환하고 int 받는 함수 포인터 선언

(*fptr)(10);

void* ptr = nullptr;

void 포인터선언, nullptr 넣기

int(*p[3])(int, int) = { add, sub, mul };

int 반환하고 int,int 받는 함수 포인터를 배열로 선언

Dynamic allocation

new로 런타임에 메모리 공간을 받는다

Garbage Collection 장단점

동적으로 할당된 메모리 중 사용하지 않으면 해제한다

모든 쓰레드 일시중지한다

virtual machine이 해준다

Smart Pointer

객체의 소유권을 증명한다 → 객체의 라이프사이클 파악

Smart Pointer / GC

smartpointer : 객체의 참조 횟수를 추척해서 객체에 대한 참조가 모두 제거되면 객체 자동으로 해제

GC : 전부 다 돌면서 참조하는 객체 추적, 사용되지 않는 객체 자동으로 해제

Dangling Pointer

더 이상 유효하지 않은 메모리 주소를 가리키는 포인터

메모리에 남아있는데 포인팅하지 못하고 남아있는 공간

  • 그냥 덮어써지는 것 아닌가?

malloc /new delete 연산자

new delete는 생성자, 소멸자를 호출한다

230420_2048,SmartPointer

어제 : 프로토타입 bug fix, exe 생성하기, 알파 기능 추가할 내용 정하기

오늘 : 코드 파일 여러개로 분리해놓기 / 기능 우선순위대로 개발하기

이슈 : 포인터, 구조체 최대한 적게 써서 복잡도를 줄이는게 좋은지 고민하기

생성자 / 소멸자

클래스가 생성될 때 호출된다.

인자를 넣어서 정보 넣는다

클래스가 사라질 때 호출된다

사라질 때 어떻게 사라질지 정한다

객체가 생성, 삭제 될 때이다

SmartPointer 구현

ptr을 갖는다. * → 를 overloading 해서 객체가 연산하는 것을 지정한다

동적할당된 메모리 관리하는 객체이다

포인터를 감싸서 포인터가 가리키는 객체의 수명이 끝날 때 포인터가 자동으로 삭제된다

복사되거나 대입되면 cnt++

소멸되면 cnt—

stringstream

stream에서 >> << 연산으로 다음 stream 객체에 값을 전달한다

문자열을 스트림으로 만든다 → 문자열에 대한 입출력 연산 한다

enum

상수롤 모은다

230421_2048,new,delete

어제 : 파일 분리 / move마다 score → 현재 score 출력

오늘 : bestScore / 매 move 마다 추가되는 점수 출력 / 점수 추가 안되면 addTile 안하기

이슈 : double buffering 써야할지 고민중~

Reference / Pointer

ref : 그 객체의 주소공간 자체를 ref해서 이름을 갖는다

pointer : 주소를 저장할 메모리를 잡는다 원래 객체에 접근하기 위해서는 연산자 써야한다

ref 직접, pointer 간접

C++ Class new delete

new : 힙에 공간을 생성한다 메모리 블럭에 대한 포인터를 반환한다

delete : 힙에 메모리를 해제한다 전달된 포인터가 갖고있는 메모리 블럭을 해제한다

delete / delete[]

[]를 뒤에 붙히면 배열 타입을 delete 한다

constexpr constant expression

배열에 상수값 대신 컴파일 타임에 되는 값을 넣을 수 있다

  • 무슨 타입인지 잘 모르겠다

컴파일 시간인 상수와 함수를 표현한다 → 컴파일러가 런타임에 값이 변하지 않는다고 확신한다

Quantum bit

양자컴퓨팅에서 여러가지 값을 동시에 가질 수 있는 비트이다

230422_Locomotion

Locomotion

캐릭터의 움직임에 대해 설정한다

Root motion

애니매이션 위치와 캐릭터 위치를 맞춘다

Warping

변형시킨다

Pose Warping

움직일 때 본을 자연스럽게 한다

Orientation Warping

하체 방향을 자연스럽게 움직인다

Stride Warping

보폭 길이, 속도를 조절한다

Motion Warping

pose warping + root motion + orientation warping + stride warping

Distance Matching

거리 예측해서 애니매이션 짤라서 재생하기

Motion Matching 매칭 / Motion Trajectory 경로

모션을 맞춘다

matching : 실시간으로 움직임에 맞는 anim 재생한다

trajectory : 이전, 현재 위치 비교해서 경로를 계산한다

Root Bone

움직임에 대해서 큰 뼈대

본 구조에서 가장 상위에 있는 것 → 전체 움직임, 캐릭터 위치

230424_2048

어제 : 게임 로직 부분은 완료되었다

오늘 : 비주얼 적인 부분 출력 예쁘게 하기 / 사운드 추가하기

이슈 : 사운드 어떻게 넣지…? / 아스키아트 어떻게 하지…?

230425_2048,Rendering

어제 : BestScore 기능추가 / 헤더파일 구조 정리 / 인자전달→전역변수

오늘 : 더블 버퍼링 / 사운드 추가하기

이슈 : 더블 버퍼링 못하고있다 / 어떻게 예쁘게 해야할지 모르겠다

Draw Call

CPU가 GPU에게 그리라는 명령을 보낸다

Batching으로 묶어서 한번에 보낸다

Rendering

화면에 그리는 것이다 점과 정보를 받아서 3차원으로 만들고 2차원 화면에 그린다

Culling

카메라에서 보여지는 부분만 그린다

Frustum : 시야 범위 벗어나면 제외한다

Occlusion : 가려지는 Oject 제외한다

Level of Detail : 카메라에 멀수록 디테일 줄인다

230426_2048

어제 : greedy 하게 getNextMoveScore 함수로 cmd 추천하기

오늘 : 사운드 추가하기

이슈 : 오늘은 빨리 집가서 체력 회복해야겠다

230427_2048,Preprocessor

어제 : 사운드 추가하기

오늘 : 기능 완료, 코드 정리하기, readme 쓰기, 문서 정리하기, 빌드파일 만들기

이슈 : 내일 발표여서 오늘 모든 것을 끝내야 한다

#if / #endif

preprocessor compile 하기 전에 처리하는 내용이다. 코드가 대체된다

230429_Gameplay Ability System

GAS Gameplay Ability System

Gameplay abilities

Ability tasks

Gameplay attribute

Gameplay effects

Ability system component


delegate

event

Static 함수

Dedicated server

Data driven

Actor

Async task

Code review

Conflict 처리하는 방법

0개의 댓글