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

ImGui 활용한 DirectX 11 3D를 이용한 2D를 만드는 내용입니다.
본 내용은 똑같이 사용할 수 없음을 알립니다. (참고 및 공부자료로 만들어진 내용임을 밝힙니다.)
전 과정에 대해 이해를 해야 다음 이 부분에 대한 이해를 할 수 있음을 밝힙니다

이전 자료) https://ppatabox.tistory.com/48

 



각주참고 하단이동[각주:1]

 

(과제 있음)

코드에 주석이 좀 정신없음 (천천히 읽으시길) 

이번시간에 나올 문제는 포폴에 사용하기 좋다 


어제 이전 링크에서 배웠던 것에서 부터 시작하겠다

 

처음 갈 곳은 Sprite.hlsl 에서 cbuffer를 넣어주자

cbuffer PS_Color : register(b0)
{
    float4 Color;
}

이 color를  이곳에 곱해줄 것이다. 

float4 PS(PixelInput input) : SV_TARGET
{
    return Texture.Sample(Sampler, input.Uv) * Color;
}

 

Sprite.h color 기본값 1 

 

 

 

 

main.cpp 

main.cpp 에서 컬러 계열에 붉은색으로 해주고 실행해보면

마리오가 실행되는데 붉은색 느낌으로 보이게 된다. 

그런데 잘보면 외곽이 좀.. 지저분 하다. 

 

이럴때에는 states.cpp로 가자 

 

desc.AlphaToCoverageEnable = true;//외곽선 지저분 한거 지워주는 것 (알파블렌딩때문에생긴문제를 없애기)

 

BlendState에다 이것을 넣어주면 

desc.AlphaToCoverageEnable = true;[각주:2]

Before / After

외곽선이 깔끔해 진 것을 볼 수 있다. 

 

 

다음으로 시간을 관리하는 클래스를 만들 것이다. 

System -> 추가 새항목 -> Time.cpp/h

 


시간을 여러 용도로 사용하는데

1) 전체시간 (Total Time) 토탈타이머 [각주:3]

 

2) 델타타임(DeltaTime)[각주:4]

   일렙시드 타임(Elapsed Time) [각주:5]

 

이전프레임에서 현재프레임 까지 걸린 시간차 : 어떤 컴퓨터는 빠르고 어떤 컴퓨터는 느리다 느린컴퓨터는 느리고 빠른컴퓨터는 빠르게 될 것이다. 그럼 느린컴퓨터는 시간차가 커지고 빠른컴퓨터는 시간차가 적어지는데 그 값을 곱해서 일정하게 만들어 주는것 일정한 속도로 움직일 수 있게. 이걸 델타타임 혹은 일렙시드 타임이라고 부른다. 

 

FPS(Frame Per Second) : 초당 프레임 수 

 

INT64(정수형)[각주:6]

 

예시) 정확하지 않음 -

short int or int >??? = 2^32 = 4,294,967,296s / 60m / 60m = h / 24 / 8(비트여서 바이트로만들어줘야함) 

= 6,213.7~ / 100? 정도 나눠주고 = 62일 ?? 실제로는 약 30일 정도 쓸 수 밖에 없다.

그래서 30일이 지나면 서버 리부트 해야한다. (서버, 클라이언트) 

 

서버나 클라이언트나 우리들이 접속 할때 

 

사용자 -> 웹페이지 (로그인 / 다운로드) - 플랫폼 팀 (본사) 홈페이지 담당  -> 로그인 완료되고 게임 클라이언트 뜨고 인증까지 (여기까지 플랫폼 팀에서 관리 ) -> 유저에 대한 키를 개발자에게 간다. (유저 정보는 개발자가 못본다) -> 키가 넘어오면 -> 클라이언트 통해서 서버쪽으로 키를 넘겨준다 -> 캐릭터 정보등을 찾아낸다음 (승인시키고) -> 서버가 클라이언트에게 보내는 정보(세션 (2개의 동기화를 유지하기위한 정보))-> 

1) 현재시간을 동기화 시킬 기한 클라이언트와 서버가 0초부터 시작을 동시에 

-> 그렇게 하고 랜덤 키 를 준다 (srand(    )할때  이 사이에 seed값이 들어가는데(현재시간을 넣을 것이고)  )

seed값을 임의로 서버에 생성시킨다. 

 

그런다음 씨드 값을 넣고 서버도 해당 클라이언트에 대해서 랜덤 초기화를 한다. 

클라이언트도 이 씨드값을 받아서 똑같이 씨드값을 srand로 초기화 한다. 

그런다음 양쪽에서 서버가 10번 콜하고 클라이언트도 10번 콜해서 같이 같은 값이 나온다.

항상 랜덤하게 그렇게 맞춰준다. 

 

그래야 아이템 정보 같은 것을 서로 싱크를 맞출 수 있다. 

이런 것 뿐만 아니라 여러가지 데이터를 공유하는데

가장 중요한게 시간이다. 

 

그래서 서버가 10초 흘렀을때 클라이언트 쪽에서도 10초가 흘러 있어야 한다. 

이렇게 안하면 핵이나 그런 버그에 대응을 못한다. 

 

이렇게 중앙에서 서버를 통제하는 것을

데디케이트 서버(Dedicated Server)[각주:7]라고 한다. 

 

흔히 MMORPG는 데디케이트 방식 

P2P 방장이나 누구하나가 서버를 내고  중앙서버는 그런 것들을 관리만 해준다. 

이것은 클라이언트쪽에 핵이 들어오면 방어가 안된다

(Battle Ground초창기에 p2p로 개발하였었다 그래서 핵이슈가 많았다. 지금은 바꿈)

 

 

시간을 짧게 Int형으로 잡으면 30일 며칠 밖에 못 버틴다. 그때 마다 서버랑 클라이언트를 리부트 해줘야한다.


 

그래서 INT64는 큰 자료형을 사용한다. 

64비트 INT형 

또한 UINT형으로 바뀌면 소수점이 사라짐 

 

TIme.h

#pragma once

class Timer
{
public:
	UINT Fps() const { return framePerSecond; }
	float Running() const { return runningTime; }
	float ElapsedTime() const { return elapsedTime; }

public:
	Timer();
	~Timer();

	void Update(); // 렌더나 업데이트나 


private:
	//정보를 만들기 위해 사용하는 값들 
	INT64 tickPerSecond; //초당 틱카운트//시간 30일 정도 ? 64비트 인트형 사용
	INT64 currentTime; //현재시간 
	INT64 lastTime; //마지막으로 기록된 시간
	
	INT64 lastFPSUpdate; //마지막 FPS 업데이트 시간 (기록하기 위한 시간)
	INT64 fpsUpdateInterval; // fps 업데이트 간격 (일정시간 동안 몇번의 간격) 
	
    
    //실제로 사용될 값들 
	UINT frameCount; // 초당 프레임수
	float runningTime; //게임 시작으로부터 경과 시간
	UINT framePerSecond; //FPS
	float elapsedTime; //이전 프레임에서 현재 프레임 시간의 차이
};

 

만약에 이 2개를 분리하면 

UINT frameCount; 
float runningTime;



UINT framePerSecond; //위 2개를 분리하면 이것은 Render로 가야한다.

FramePerSecond는 렌더로 가야한다. 

 

렌더랑 업데이트 타임이 횟수가 다른데 지금 현재는 동일하게 사용하고 있지만 

실제로는 게임에서는 다르게 흘러간다. 

다음에 언리얼에서 다룰 것 임 

 

 

public:
	UINT Fps() const { return framePerSecond; }
	float Running() const { return runningTime; }
	float ElapsedTime() const { return elapsedTime; }

이런 식으로 값만을 return 해주는 것은 함수 뒤에 const(상수) 를 붙여 줄 수 있다.

const가 상수화 라는 의미가 있는데 

함수 뒤에 붙은 const 의 경우  {    }이 안에서는 (이 구역내에서는) 저기  (const위치는 여러개의 방법으로 쓰임) 

이 멤버 변수를 수정 할 수 없다 라는 의미가 된다. 

 

그러니까 값만 return해줄 것인데 이것들을 건드릴 필요가 없다. 

값만 가져다 쓰는 거니까. 이런식으로 const를 많이 쓴다.

 

 

 

 


그다음 생성자 부터 만들어주자 

 

Time.cpp 

#include "stdafx.h"
#include "Timer.h"

Timer::Timer()
	:tickPerSecond(0),
	currentTime(0),
	lastTime(0),
	lastFPSUpdate(0),
	fpsUpdateInterval(0),
	frameCount(0),
	runningTime(0.0f),
	framePerSecond(0),
	elapsedTime(0)
{
	//word 2byte dword 4byte
	//GetTickCount(); //클럭을 사용해서 시간이 일정 게임에서는 아에 사용할 수 없다. //윈도우 프로그램개발자들 사용 느려지는걸 체크 할때 윈도우
	//timeGetTime(); //CPU타임

	QueryPerformanceFrequency((LARGE_INTEGER *)&tickPerSecond);//INT64형 시간을 쓰겠다
	fpsUpdateInterval = tickPerSecond >> 1;//1을 낮추는 1초에 맞는 진동수 1초
	//frequency 1초당 진동수? 

	QueryPerformanceCounter((LARGE_INTEGER *)&lastTime); //시간차 크게 기록되서 여기서 2개를 빼서 차를 계산 
}

Timer::~Timer()
{

}

void Timer::Update() //현재시간 업데이트를 매 프레임마다. 업데이트 전에 먼저 콜 
{
	QueryPerformanceCounter((LARGE_INTEGER *)&currentTime);//현재시간기록 업데이트시간
	elapsedTime = (float)(currentTime - lastTime) / (float)tickPerSecond; //tickper을 나눠줘야함 
	runningTime += elapsedTime; //현재까지 실행한 시간 

	frameCount++;//매프레임 마다 시간을 올려준것 시스템의 퍼포먼스를 결정함 (게임의성능을 측정하는 첫번째 숫자) 수직동기화를 풀었을때  몇번이 되느냐를 불리고 framePerSecond가 FPS를 출력 
	if ((currentTime - lastFPSUpdate) >= fpsUpdateInterval) // 현재시간에서 - 마지막 업데이트된 시간 이전 1초 전 크거나 같을때 1초가 흘렀다  만약 흘렀다면 프레임카운트 초기화 
	{
		float tempCurrentTime = (float)currentTime / (float)tickPerSecond; // 모든시간을 이걸로 나워야 정확한 시간이 나옴
		float tempLastTime = (float)lastFPSUpdate / (float)tickPerSecond;
		framePerSecond = (UINT) ((float)frameCount / (tempCurrentTime - tempLastTime));// 1초 동안 몇번이 됬는가 비율을 찾아야함 1초동안 나온 실제로 나타날 FPS 
		
		lastFPSUpdate = (INT64)currentTime;
		frameCount = 0;
	}
	lastTime = currentTime; //현재시간 을 기록하고 lasttime이전프레임  

}

 

 

 

 

일단 이곳에 있는 값을 다 초기화 시켜 줄 것이다. 

이니셜 라이즈를 쓸 것이기 때문에 

(길어 지니까 내리자) 

 

Timer::Timer()
	:tickPerSecond(0),
	currentTime(0),
	lastTime(0),
	lastFPSUpdate(0),
	fpsUpdateInterval(0),
	frameCount(0),
	runningTime(0.0f),
	framePerSecond(0),
	elapsedTime(0)
{

(언리얼에서는 자동으로 처리해줌...) 

(Keyboard 빠져있어서 넣어줌) 

Timer 생성해주자

 

 

 

 

 

 

 

 

게임이 실행되면 이 클래스를 가장 먼저 생성하고 실행할 것이다. 

Device.cpp(DX관련 내용 파일) ->

들어가보면 게임을 실행하는 메인 루프 이게 끝나면 게임이 종료 된다. 

게임 시작 부분에서 

main.cpp에서 볼 수 있듯이 우리가 

InitScene에다 정의하는데 이것의 시작지점이 

 

이곳Device.cpp에서  InitScene의 함수가 시작을 호출 해 주는 역할을 한다. 

 

 

	Key = new Keyboard();
	Time = new Timer();

이렇게 만들어 준 것을  Device.cpp / Running 에 넣어주고 

 

 이게 다 끝나면 

여기서 끝나는 부분 그래서 다 끝나면 필요없는 것을 제거 

 

	SAFE_DELETE(Key);
	SAFE_DELETE(Time);

그러고 나서 맨위쪽에 extern 일때는 이곳에 하나 추가 해줘야 한다. 

 

 

 

 

 

그러면 이 Time이라는 클래스가 언제 만들어 질까?

게임이 시작될때 생성 되는 것이다.

 

Timer는 업데이트가 될때 (가장 먼저 시간을 먼저 갱신하고 시간에 따라 움직여야 하니까) 

가장 먼저 업데이트(호출)_ 해준다. 

 

 

 

 

 

기억할 것 !

1) 프로그램 시작 지점 2) 실행 후 계속 도는 곳 업데이트도 렌더도 이때 한다 3) 2번이 끝나면 게임종료 

 

 

Time,cpp로 가자 

dword (double word) = 4byte

	//word 2byte dword 4byte
	GetTickCount(); //클럭을 사용해서 시간이 일정 게임에서는 아에 사용할 수 없다. //윈도우 프로그램개발자들 사용 느려지는걸 체크 할때 윈도우
	timeGetTime(); //CPU타임

GetTickCount(); 게임 에서는 아에 사용 할 수 가 없다. 

 

 

CPU가 공간을 처리하기 위한 시간단위를 클럭이라고 하는데

한단위 하나 한칸의 단위가  0 1 0 4.2Gherz가 1초의 4.2g번에 이걸 처리 한다라는 의미 

timeGetTime(); 이것은 이 클럭을 사용하기 때문에 시간이 항상 일정하다 

 

GetTickCount는 (윈도우 프로그램 개발자들이 사용하는 것인데. 윈도우가 느려지면 비디오 플레이어도 느려져야 하는데

영상 같은 것이 그만큼 느려져야 하는데 

(그래야 싱크가 맞으니까)

그래서 영상 보다가 버퍼링 되면 멈추는 데 (같이 느려지는 것을 체크 할때 쓰는 게 GetTickCount이다) 

윈도우 타임 사용-

 

그래서 위처럼 사용 하지 않는다..

 

더 정밀한 타이머를 쓴다. 

QueryPerformanceFrequency((LARGE_INTEGER *)&tickPerSecond);//INT64형 시간을 쓰겠다

TickPerFrame은 INT64형이다. 

 

LARGE_INTERGER에서 포인터로 달라고 한다. 포인터는 주소 쓰고 

(현재 사용하는 것은 윈도에 만들어둔 자료형이다) 

 

정의 한 이것이 최초의 수행할 시간을 가져오는 역할을 한다. (최초 시간 기록) 

- 현재 부터 나는 시간 체크를 하겠다 라고 알려준 것 

 

	QueryPerformanceFrequency((LARGE_INTEGER *)&tickPerSecond);//INT64형 시간을 쓰겠다
	fpsUpdateInterval = tickPerSecond >> 1;//1을 낮추는 1초에 맞는 진동수 1초
	//frequency 1초당 진동수? 

	QueryPerformanceCounter((LARGE_INTEGER *)&lastTime); //시간차 크게 기록되서 여기서 2개를 빼서 차를 계산 
}

 

이 Frequency는 1초당 주기 진동수 

>> 낮추는데 

진동수가 너무 커서 

1초에 맞게 진동수를 조절해준 것 

이 것을 1초에 값이 들어간다고 생각하면 됨

 

 

Timer.cpp

	QueryPerformanceFrequency((LARGE_INTEGER *)&tickPerSecond);//INT64형 시간을 쓰겠다
	fpsUpdateInterval = tickPerSecond >> 1;//1을 낮추는 1초에 맞는 진동수 1초
	//frequency 1초당 진동수? 

	QueryPerformanceCounter((LARGE_INTEGER *)&lastTime); //시간차 크게 기록되서 여기서 2개를 빼서 차를 계산 
}

Timer::~Timer()
{
 //메모리 할당 할게 없어서 특별히 할 일 없음
}
///////////////////////////
////현재 라스트 타임은 0 이다.처음에는 한 프레임 정도는 의미가 없기 때문에 그냥 라스트타임을 0으로 기록
////원래는 라스트타임에 현재시간 하나 구해서 둘다 0초를 만들어 놓고 시작함 
//////////////////////////
////0 프레임하고 1프레임 차(-) 하고, 1프레임과 2프레임 차의 계속 기록해두면 2프레임까지 걸린시간하고 같다
/////////////////////////

void Timer::Update() //현재시간 업데이트를 매 프레임마다. 업데이트 전에 먼저 콜 
{
	QueryPerformanceCounter((LARGE_INTEGER *)&currentTime);//현재시간기록 업데이트시간
	elapsedTime = (float)(currentTime - lastTime) / (float)tickPerSecond; //tickper을 나눠줘야함 
	runningTime += elapsedTime; //이전시간하고 현재시간의 차를 계속 더해가는 것 계속 누적하면 현재 실행한 시간 

	frameCount++;//매프레임 마다 시간을 올려준것 시스템의 퍼포먼스를 결정함 (게임의성능을 측정하는 첫번째 숫자) 수직동기화를 풀었을때  몇번이 되느냐를 불리고 framePerSecond가 FPS를 출력 
	if ((currentTime - lastFPSUpdate) >= fpsUpdateInterval) // 현재시간에서 - 마지막 업데이트된 시간 이전 1초 전 크거나 같을때 1초가 흘렀다  만약 흘렀다면 프레임카운트 초기화 
	{
		float tempCurrentTime = (float)currentTime / (float)tickPerSecond; // 현재 시간기록 /모든시간을 이걸로 나워야 정확한 시간이 나옴
		float tempLastTime = (float)lastFPSUpdate / (float)tickPerSecond;
		framePerSecond = (UINT) ((float)frameCount / (tempCurrentTime - tempLastTime));// 1초 동안 몇번이 됬는가 비율을 찾아야함 1초동안 나온 실제로 나타날 FPS 
		
		lastFPSUpdate = (INT64)currentTime;//현재시간을 기록 이제 1초가 지남 /다시 현재시간으로부터 1초를 변환 시킴 
		frameCount = 0;//시간이 초기화 됬으니까 0으로 
	}
	lastTime = currentTime; //마지막 시간에는 현재시간 을 기록하고 lasttime이전프레임  

}

 

 

위에 대해 설명 부분  -그대로 읽으시오 


0 프레임하고 1프레임 차(-) 하고, 1프레임과 2프레임 차의 계속 기록해두면 2프레임까지 걸린시간하고 같다

예시 runningTIme += elapsedTime; 부분에서 

 

0~1 까지 3초

1~2 까지 4초

2~3 까지 2초 

걸렸다고 쳐보자

0 + 1 + 3 + 2 + 4 + 3 + 2 다 더하면

현재까지의 시간   

 

 

if ((currentTime - lastFPSUpdate) >= fpsUpdateInterval) 

currentTime과 lastFPSUpdate를 뺀 결과가 1초당 fpsUpdateInterval 보다 크다면 1초가 경과한 것 

(현재시간에서 - 마지막 FPS업데이트된 시간 ) 이것들 보다 크거나 같다면 1초가 경과 한 것이다. 

 

이전 1초 전 크거나 같을때 1초가 흘렀다  만약 흘렀다면 프레임카운트 초기화 

 

 

 

나누기면 플롯이 되야 소수점이 안사라진다. 현재 UINT형으로 바뀌어서 소수점이 사라지기 때문에 

미리 나눠 두고   

//괄호 안에 거 부터 (tempCurrentTime - tempLastTime) = (float - float)임 그럼 float형이 나오고 

frameCount 이게 INT형이면 계산이 제대로 안되고 소수점이 사라진다. 

그래서 frameCount 이거까지 나눈 결과 값을 float소수점으로 돌린다. 

그런데 최종적으로는 framePerSecond 얘한테 들어가는데 float4했으니까. 소수점이 필요없다. 

그래서 최종적으로 framePerSecond 얘한테 들어갈때는 UINT형으로 바뀐다. 

그래서 연산한 결과에서 소수점을 제거 할 것이다. (연상중에 들어가는게 아님)

 

framePerSecond = (UINT) ((float)frameCount / (tempCurrentTime - tempLastTime));

 

tickPerSecond[각주:8]

fpsUpdateInterval = tickPerSecond >> 1;//오른쪽 쉬프트 1초동안의 간격(공식처럼생각) 

fpsUpdateInterval : 1초 시간 

 

현재시간 업데이트가 (update 매 프레임마다 호출하게 끔 넣어둠)

QueryPerformanceCounter((LARGE_INTEGER *)&currentTime);

처음 업데이트가 되면 currentTime 현재업데이트 된 시간을 기록한 것 

\

lastTime = currentTime; 현재 시간을 라스트 타임에 기록을 해두었다. 

그러면 다음 한바퀴를 돌아서 이전프레임 시간이 되고

다시 현재 시간을 구한 것   

 

그렇다면 lastTime 과 currentTime현재시간의 차를 구하면 

이전프레임에서 현재 프레임 까지 걸린 차 (시간) 

=> 이게 elapsedTime 

 

그래서 elapsedTime 를 보면 

elapsedTime = (float)(currentTime - lastTime) / (float)tickPerSecond; 

currentTime - lastTime 을 빼준것 

 

tickPerSecond가 진동주기라고 했는데 이것을 나눠줘야 정확히 

1초 시간이 된다. 

 

 

runningTime  이전 시간하고 현재 시간 까지 다 통합하면 현재 까지 프레임한 시간. 


그다음 매 프레임마다 업데이트가 일어날 것이기에 

frameCount++; 매프레임 마다 시간을 올려주는 것 

이것이 그릴 횟수 (시스템의 퍼포먼스를 결정한다) 

 

그런데 framePerSecond라고 했는데 1초가 지나면 초기화가 되어야 하는데 

그래야 내가 1초 동안 몇번을 업데이트 했는지 수를 알 수 있을 것이다. 

 

 게임에서 수직동기화 라는게 있다. 

모니터 60Hz면 60번 깜빡임 

그것에 게임프레임을 맞춰주는것 

 

144hz는 더 부드러울 것이다. 그러면서 모니터도 깜빡인다.

우리가 프레임 수를 실제 게임에서는

업데이트는 최대한 부드럽게 움직일려고  CPU가 허용한다고 하고

렌더링은 모니터에 맞추기 위해 1초에 60번정도로 고정시킨다. 

보통 평균 60 프레임 이다. 

 

오래된 게임 같은경우  보통 30프레임정도 쓰는데

모니터가 60번 깜빡이지만 

2번 중에 한번은 안그리는 것이다. 

 

그래서

frameCount++; 이것이 그릴 횟수 (시스템의 퍼포먼스를 결정한다) 

Vsync를 풀면 60이 아니라. 시스템이 허용하는 한 그린다. 

컴퓨터 사양에 따라 더 올라갈 수도 있고 더 낮아 질 수도 있다 

 

그래서 frameCount가 게임의 성능을 측정하는 첫번째  숫자 이다. 


 

if ((currentTime - lastFPSUpdate) >= fpsUpdateInterval) 

현재시간에서 - 마지막 업데이트된 시간

 

lastFPSUpdate = (INT64)currentTime;

마지막 업데이트 된 시간하고 현재시간을 기록해두는데 

그러니까 마지막 업데이트 된 시간  이전 1초전 

 

currentTime(현재시간)하고 lastFPSUpdate(마지막 업데이트 된 시간) 을 뺐을때 

 

fpsUpdateInterval = tickPerSecond >> 1; 1초를 나타낸 진동수로 

이것보다 크거나 같으면 1초가 흘렀다는 얘기 

 

1초가 흘렀을때 frameCount = 0;초기화 해줘야 하고 

그다음에 lastFPSUpdate 시간에currentTime 현재시간을 기록한다. 

맵 다음에서는 lastFPSUpdate 위에서 쓰게 된다면 이게 아직 이전시간 일테니까 


float tempCurrentTime = (float)currentTime / (float)tickPerSecond;

모든시간을 tickPerSecond로 나눠야 정확한 시간이 나온다. 

현재시간을 tickPerSecond로 나눠서 tempCurrentTime 기록해 놓고

 

float tempLastTime = (float)lastFPSUpdate / (float)tickPerSecond;

 

lastFPSUpdate 마지막 업데이트된 시간도 tickPerSecond나눠줘서 

tempLastTime 이곳에 넣어놓고 

 

framePerSecond = (UINT) ((float)frameCount / (tempCurrentTime - tempLastTime));

(tempCurrentTime - tempLastTime) 2개를 빼것에 frameCount를 나누고 

그동안에 frameCount 가 1초동안  framePerSecond 몇번이 됬는가? 비율을 찾아야 한다. 

framePerSecond (1초 동안 나온 프레임수(비율)) 

 

framePerSecond 실제로 나타날 FPS이다. 

1초동안 몇번의 프레임이 업데이트가 됬느냐 

그래서 비율을 만들려고 나온 것 

 

frameCount이건 몇번이 됬느냐 이고 

framePerSecond 이건 1초 동안 

 

나누기의 최댓값이 1이라면 비율이 된다.  

 

 

추가로 

QueryPerformanceCounter((LARGE_INTEGER *)&lastTime);

currentTime - lastTime하고 차 에서 최초 시간차가 너무 크게 기록되서

,

.

.

elapsedTime = (float)(currentTime - lastTime) / (float)tickPerSecond;

 


 

 

main.cpp에서 

#include "stdafx.h"

Rect* rect = NULL;
Sprite* sprite = NULL;
void InitScene()
{
	rect = new Rect();
	rect->Position(200, 200);
	rect->Scale(100, 100);
	rect->Color(0, 0, 1);

	sprite = new Sprite(L"SingleMario.png");
	sprite->Position(400, 400);
	sprite->Scale(100, 100);
	sprite->Color(1, 0.5f, 0.5f, 1); //붉은색 계열 

}

void DestroyScene()
{
	SAFE_DELETE(rect);
}


D3DXVECTOR2 position(400, 400);

void Update()
{
	rect->Update();
	sprite->Update();
}

void Render()
{	
	ImGui::Text("FPS : %d", Time->Fps());
	ImGui::Text("Elapsed : %f", Time->ElapsedTime());
	ImGui::Text("Running : %f", Time->Running());

	rect->Render();
	sprite->Render();
}

 

 

 

 

 


생각해보자! 

sin이든 cos이든 그래프가 일정 주기로 간다. 

 

이것을 한구간을 끊어서 보면 

 

 

 

 

 

원이 그려지는데 

어떤 각이 들어오든 

계속해서 원을 그린다.

 

-1 부터 1까지 

 

이걸 이용해서 왔다갔다

라이트 켜졌다 꺼졌다 하는 것을 만들 수 있다. 

 

 

자 한번 만들어보자 

position만 sprite에 간단히 지정해주자 (리턴만들어주기) 

 

Sprite.h

void Position(D3DXVECTOR2* vec);

Sprite.cpp

void Sprite::Position(D3DXVECTOR2* vec)
{
	*vec = position;
}

이러면 이제 리턴이 될 것이다. 

 

main.cpp에서 

예를 들어

 

여기서 200,200, 400,400 에 출력을 할 것이다.(position)

원래는 위치를 받아서 해야하는데 지금은 임의의로 출력

 

위치를 받아야하는데 임의로 

D3DXVECTOR2 position(400, 400);

 

 

 

D3DXVECTOR2 position(400, 400);

void Update()
{
	rect->Update();

	float x = position.x + sin(Time->Running()) * 100;
	float y = position.y;
	sprite->Position(D3DXVECTOR2(x, y));

	sprite->Update();
}

float x = position.x + sin(Time->Running()) * 100;

(x가 position에 누적되니까 400,400지정해준게 값이 변해서 안나올 수 있음 ))

 

float y = position.y; 이건 그대로 두자 

 

sprite->Position(D3DXVECTOR2(x, y));

position이 기준값 만든값을 넣어주자 

 

계속 돌아오는 값이 -1 부터 1까지의 사이로 올 것이다. 

여기에 * 100정도의 범위로 움직이게 할 것이다. 

그러면 -100~100이된다.

 

 

그럼 이렇게 왔다리 갔다리 하는 걸 볼 수 있다. 

 

이렇게 반복적으로 어떤 그래프를 이용해서 하는걸 통칭해서

Easing이라고 부른다. 

 

sin값때문에 빠르게 갔다가 끝으로 가면 느려지고 다시 빨라졌다가 느려지고


 

풀이문제: 

 

총 30개 정도 되는 값을 이용해서 

클래스 하나 만들고

Math 클래스 처럼 Static으로 만들고

Easing 클래스 만들고 

 

(실제 게임 구현 할때 많이 쓰인다 느려졌다 빨라졌다가 , 라이트 같은 몹 같은거) 

 

내부에 들어가면 함수가 다 나와있다. 그걸 보고 구현하자.

왜이렇게 움직이는 지를 생각하며 만들자. 

 

이미지 캐릭터 파일을 30개를 깔고 각 함수의 글자를 띄어서 마리오가 어떻게 움직이는 방식인지 띄워라 

 

 

Easing Functions Cheat Sheet

Easing functions specify the speed of animation to make the movement more natural. Real objects don’t just move at a constant speed, and do not start and stop in an instant. This page helps you choose the right easing function.

easings.net

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

참고할 만한 링크) 

 

Delta timing - Wikipedia

Concept in game programming Delta time or delta timing is a concept used amongst programmers in relation to hardware and network responsiveness.[1] In graphics programming, the term is usually used for variably updating scenery based on the elapsed time si

en.wikipedia.org

 

 

다음시간) 

 

[C++]DriectX Inheritance_상속 그 안의 속성(커플링)

ImGui 활용한 DirectX 11 3D를 이용한 2D를 만드는 내용입니다. 본 내용은 똑같이 사용할 수 없음을 알립니다. (참고 및 공부자료로 만들어진 내용임을 밝힙니다.) 전 과정에 대해 이해를 해야 다음 이

ppatabox.tistory.com

 

 

 

 

 

 

 

 

 

 

 

 

 

 


각주)

  1. [본문으로]
  2. Image의 외곽선 정리? [본문으로]
  3.   게임이 시작되서 현재까지의 시간  [본문으로]
  4.   전 프레임을 완료하는데 걸린 시간 [본문으로]
  5.   프레임 간 경과 시간 [본문으로]
  6. int 64비트 정수형 x2 int형  [본문으로]
  7. 게임 서버의 형태, 전담 서버를 의미 대규모 온라인 게임용 서버는 지속적으로 동작하며 하나의 서버에서 많은 게임 플레이와 처리를 수행하는 반면, 데디케이드 서버는 하나의 서버가 게임 한판 만을 전담하므로 게임의 시작과 함께 서버를 시작하여 해당 게임의 끝나게 되면, 서버도 종료된다. 그래서 장 단점이 있다 [본문으로]
  8. 1초동안 CPU가 1초에 진동할 수 [본문으로]
728x90
728x90
LIST
profile

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

@공부하는 PPATABOX

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