노트 11 부 드 러 운 애니메이션:떨 리 지 않 는 작은 눈송이

이 시 리 즈 는 71 안개 중앙 에서 작 성 했 으 니 전재 하 겠 습 니 다.출처 를 밝 혀 주 십시오.
 http://blog.csdn.net/u011371356/article/details/9430645
저자:칠십 일 안개 중앙 시 나 웨 이 보:http://weibo.com/1689160943/profile?rightmod=1&wvr=5&mod=personinfo
      지난 절 에 안개 중앙 에서 평면 적 인 장애물 판정 을 설명 했다.원래 경사 의 장애물 판정 을 설명 하려 고 했 지만 어떤 친구 가 글 을 추천 했다.장애물 판정 에 대해 잘 설명 했다.안개 중앙 은 주 소 를 직접 붙 이 고 중복 되 지 않 았 다.
                 2D 게임 에서 의 장애 판정
      이 글 은 2D 게임 의 많은 것 을 설명 하고 있 습 니 다.잘 보 세 요.안개 속 에서 도 게임 개발 을 연구 하 는 친구 들 이 좋 은 글 을 추천 하고 함께 발전 하 기 를 바 랍 니 다.감사합니다.
      또한 이 노트 부터 안개 중앙 은 시리즈 이름 을'C++프로 그래 밍'으로 바 꾸 기로 했 습 니 다.구체 적 인 원인 은 이동 해서 필기 하 세 요.
     
      그 전에 안개 가 배경 스크롤 을 설 명 했 는데 여러분 이 발 견 했 는 지 모 르 겠 습 니 다.인물 이 이동 할 때 화면 이 한 번 씩 끊 기 는 이 유 는 여러분 이 방향 키 를 누 르 고 이동 한 후에 인물 이 갑자기 거 리 를 이동 하기 때 문 입 니 다.그리고 배경 도 한 번 거 리 를 이동 하면 서 갑자기 변화 하 는 화면 이 여러분 에 게 카드 의 느낌 을 주기 때 문 입 니 다.이후 입자 시스템 에서 떨 리 는 작은 눈송이 도 마찬가지 라 고 언급 했다.그 릴 때마다 눈송이 가 확실한 위 치 를 늘 렸 지만 컴퓨터 상태 가 계속 변화 하기 때문에 두 프레임 사이 의 시간 차이 가 다 르 기 때문에 눈송이 의 이동 도 불규칙 하 다.떨 리 는 느낌 이 든다.
      위의 토론 을 통 해 알 수 있 듯 이 게임 에서 정확 한 위 치 를 늘 려 특정한 사물 의 위 치 를 바 꾸 는 것 은 정확 하지 않 고 화면 이 원활 하지 않 을 수도 있다.그러나 이런 떨 림 이 발생 하 는 원인 을 생각하면 우 리 는 많은 깨 우 침 을 받 을 수 있다.우 리 는 매번 이동 하 는 거 리 를 줄 이 고 이동 하 는 빈 도 를 늘 려 같은 위치 에 도달 할 수 있 지 않 을 까?이렇게 하면 화면의 위 화 감 을 크게 낮 출 수 있 고 가장 높 은 빈 도 는 바로 화면 이 그 리 는 빈도 와 일치 하기 때문에 우 리 는 화면 을 그 릴 때마다 작은 폭 으로 업 데 이 트 를 할 수 있다.그러나 두 번 그 리 는 사이 의 시간 차 의 변동 에서 벗 어 나 기 위해 우 리 는 시간 차 를 계산 하고 업데이트 폭 과 시간 차 를 연결 해 야 한다.
     
      가장 직접적인 실현 방식 은 당연히 시간 과 속 도 를 통 해 상술 한 효 과 를 얻 는 것 이다.
      예 를 들 어 인물 에 대해 우 리 는 그 에 게 x 와 y 방향의 속 도 를 주 고 시간 곱 하기 속 도 를 통 해 그의 위 치 를 업데이트 한다.유저 의 조작 은 캐릭터 의 방향 과 속 도 를 바 꿀 수 있 습 니 다.입자 계통 도 마찬가지다.
 
      모두 가 원 리 를 알 게 된 후에 실현 하기 전에 우 리 는 먼저 몇 가지 문 제 를 해결 해 야 한다.
      우선 두 프레임 사이 의 시간 차 를 얻 는 것 이다.이것 은 우리 가 마지막 으로 그린 시간 을 기록 하고 그 릴 때마다 현재 시간 을 가 져 오 라 고 요구 합 니 다.둘 사이 의 차 이 는 바로 원 하 는 것 입 니 다.마지막 으로 그 려 진 시간 을 전역 변 수 를 사용 하여 기록 할 수 있 습 니 다.여기 서 안개 낀 곳 은 정적 변 수 를 사용 합 니 다.
 
static float lastTime=timeGetTime();   
static float currentTime=timeGetTime();
currentTime=timeGetTime();
//    
lastTime=currentTime;

 
      그 후에 부 드 러 운 애니메이션 을 얻 을 수 있 습 니 다.안개 중앙 은 예전 의 입자 시스템 에서 눈 송 이 를 예 로 들 면 예전 의 방식 과 비교 하면 차 이 를 더욱 분명하게 볼 수 있 습 니 다.
      또한 이렇게 프레임 간 의 시간 차 를 얻 으 면 FPS 를 계산 할 수 있 습 니 다.프레임 수의 계산 은 매우 간단 합 니 다.바로 화면 그리 기 횟수 를 그 리 는 데 걸 리 는 시간 으로 나 누 면 됩 니 다.프레임 수가 계속 뛰 지 않도록 1 초 간격 으로 계산 할 수 있 습 니 다.
//    FPS
float CalculateFPS()
{
    static float  fps = 0;           //FPS    
    static int    frameCount = 0;    //     
    static float  currentTime =0.0f;   
    static float  lastTime = 0.0f;  
    //     ,   1
    frameCount++;           
    currentTime = timeGetTime()/1000.0f;
 
//                 , 1/    ,          ,
//          ,      ,          ,             
    if(currentTime - lastTime > 1.0f) //      1     
    {  
        fps = frameCount /(currentTime - lastTime);//   1   FPS    
        lastTime = currentTime; 
        frameCount    = 0;        
    }  
  
    return fps;  
}

      
      이전 노트 에서 애니메이션 과 관련 된 것 은 모두 타 이 머 를 사 용 했 습 니 다.안개 가 게임 을 처음 배 울 때 코드 에 타 이 머 를 많이 사 용 했 습 니 다.하하.하지만 이제 우 리 는 이렇게 많은 타 이 머 를 사용 하지 않 을 수 있 습 니 다.만약 에 여러분 이 WIN 32 를 직접 사용 하면 타 이 머 를 전혀 사용 하지 않 을 수 있 습 니 다.하지만 MFC 를 사용 하면 타 이 머 를 사용 하여 OnPaint 그림 을 그 려 야 합 니 다.나머지 애니메이션 은 시간 차 를 계산 하여 업데이트 할 수 있 습 니 다.
      예 를 들 어 100 밀리초 마다 한 프레임 의 애니메이션 을 업데이트 합 니 다.
if(currentTime-lastTime>100.0f)
          

      또한 주의해 야 할 것 은 스티커 를 붙 일 때 픽 셀 에 따라 위 치 를 정 하 는 것 입 니 다.즉,위 치 는 반드시 정형 의 수치 여야 합 니 다.그러나 시간*속도 로 위 치 를 계산 하기 때문에 매번 추가 하 는 부분 이 매우 작 기 때문에 xy 좌 표 는 부동 소수점 형 이지 만 그 릴 때 정 리 된 것 입 니 다. 
 
      지난번 에 말 한 입자 시스템 과 달리 이번 안 개 는 입자 류 를 봉 인 했 습 니 다.코드 는 예전 보다 훨씬 깨끗 해 보 였 습 니 다.또한 안 개 는 이번에 매크로 정 의 를 stdafx.h 에 넣 었 습 니 다.여러 파일 이 매크로 정의 에 사용 되 어야 하기 때 문 입 니 다.
 
      안개 중앙 은 먼저 입자 의 구조 체 를 정의 했다.
 
struct snow
{
	float x;
	float y;
	float speed; //  
	int number;  //      
};

다음은 입자 류.
 
class CParticle
{
private:
	int m_number; //  
	struct snow *m_pSnow;  //  
	CImage m_snowMap[7]; //      
public:
	CParticle(int number);
	~CParticle();

public:
	void Init();  //     
	void Draw(CDC &cDC);  //    
	void Update(float time);//    
};

입자 류 의 구체 적 실현
 
#include"stdafx.h"
#include"particle.h"

CParticle::CParticle(int number)
{
	m_number=number;
	m_pSnow=new struct snow[m_number];
}

void CParticle::Init()
{
	//      
	char buf[20];
	for(int i=0;i<7;i++)    //      
	{
		sprintf(buf,"Snow//%d.png",i);
		m_snowMap[i].Load(buf);
		TransparentPNG(&m_snowMap[i]);
	}
	//       
	for(int i=0;i<m_number;i++)
	{
		m_pSnow[i].x=rand()% WINDOW_WIDTH;   //              
		m_pSnow[i].y=rand()% WINDOW_HEIGHT; //           
		m_pSnow[i].number=rand()%7;         //        
		m_pSnow[i].speed=(rand()%5+1)/20.0;
	}
}

void CParticle::Draw(CDC &cDC)
{
	//      
	for(int i=0;i<m_number;i++)
		m_snowMap[m_pSnow[i].number].Draw(cDC,m_pSnow[i].x,m_pSnow[i].y,32,32);
}

void CParticle::Update(float time)
{
	for(int i=0;i<m_number;i++)
	{
		m_pSnow[i].y+=time*m_pSnow[i].speed;
		if(m_pSnow[i].y>WINDOW_HEIGHT)
			m_pSnow[i].y=-32;  
	}
}

CParticle::~CParticle()
{
	delete[] m_pSnow;
}

마지막 으로 CChildView 헤더 파일 입 니 다.
 
// ChildView.h : CChildView     
//

#pragma once
#include "particle.h"

// CChildView   

class CChildView : public CWnd
{
//   
public:
	CChildView();

//   
public:

	CRect m_client;    //       
	CImage m_bg;      //    

	CParticle *m_snow;
	CDC m_cacheDC;   //  DC
	CBitmap m_cacheCBitmap;//    
//   
public:

//   
	protected:
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

//   
public:
	virtual ~CChildView();

	//          
protected:
	afx_msg void OnPaint();
	DECLARE_MESSAGE_MAP()
public:
	
	afx_msg void OnTimer(UINT_PTR nIDEvent);
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
};

 CPP 파일
//-----------------------------------【    】----------------------------------------------
// 【MFC    】               
// VS2010  
//          CSDN   http://blog.csdn.net/u011371356/article/category/1497651
//        : @     
//------------------------------------------------------------------------------------------------


// ChildView.cpp : CChildView     
//

#include "stdafx.h"
#include "GameMFC.h"
#include "ChildView.h"

#include "mmsystem.h"
#pragma comment(lib,"winmm.lib")//        

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CChildView

CChildView::CChildView()
{
}

CChildView::~CChildView()
{
	mciSendString("stop bgMusic ",NULL,0,NULL);
	delete m_snow;
}


BEGIN_MESSAGE_MAP(CChildView, CWnd)
	ON_WM_PAINT()
	ON_WM_TIMER()
	ON_WM_CREATE()
END_MESSAGE_MAP()



// CChildView       

BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs) 
{
	if (!CWnd::PreCreateWindow(cs))
		return FALSE;

	cs.dwExStyle |= WS_EX_CLIENTEDGE;
	cs.style &= ~WS_BORDER;
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, 
		::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
	
	//-----------------------------------         -------------------------
	
	//    
	m_bg.Load("bg.png");

	//      
	mciSendString("open background.mp3 alias bgMusic ", NULL, 0, NULL);
	mciSendString("play bgMusic repeat", NULL, 0, NULL);

	m_snow=new CParticle(100);
	//   
	m_snow->Init();

	return TRUE;
}

void CChildView::OnPaint() 
{
	static float lastTime=timeGetTime();    
	static float currentTime=timeGetTime();
	//    DC  
	CDC *cDC=this->GetDC();
	//      
	GetClientRect(&m_client);
	//    DC
	m_cacheDC.CreateCompatibleDC(NULL);
	m_cacheCBitmap.CreateCompatibleBitmap(cDC,m_client.Width(),m_client.Height());
	m_cacheDC.SelectObject(&m_cacheCBitmap);
	//————————————————————    ——————————————————————
	//   ,          DC:m_cache  
	m_bg.Draw(m_cacheDC,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
	//   
	m_snow->Draw(m_cacheDC);
	//    
	currentTime=timeGetTime();
	m_snow->Update(currentTime-lastTime);
	lastTime=currentTime;
	//     DC       DC 
	cDC->BitBlt(0,0,m_client.Width(),m_client.Height(),&m_cacheDC,0,0,SRCCOPY);

	//————————————————————    —————————————————————
	
	//      ,      
	ValidateRect(&m_client);
	//    DC
	m_cacheDC.DeleteDC();
	//    
	m_cacheCBitmap.DeleteObject();
	//    DC
	ReleaseDC(cDC);
}


//       
void CChildView::OnTimer(UINT_PTR nIDEvent)
{
	
	OnPaint();
}


int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:              

	//    10            
	SetTimer(TIMER_PAINT,10,NULL);

	return 0;
}

몇 장의 운행 사진 을 보면 여러분 들 은 화면 에서 지난번 과 의 차 이 를 볼 수 없 을 것 입 니 다.그러나 실제로 운행 하면 여러분 들 은 지난번 보다 몇 백 배 나 강하 다 는 것 을 알 게 될 것 입 니 다.
  또한,이번 눈송이 의 속 도 는 안개 가 일정 범위 내 에서 무 작위 로 설정 되 어 더욱 감각 적 으로 보 였 다.
 구체 적 으로 는 데모 다운 받 으 시고 체험 해 보 세 요.
PS:배경 음악 은 야 니 의 나이팅게일 입 니 다.좋 은 곡 입 니 다.좋아해 주 셨 으 면 좋 겠 습 니 다.
          이 노트 원본 코드 는 여 기 를 클릭 하여 다운로드 하 십시오.
    《C++게임 개발 노트 11 은 여기까지 입 니 다.더 많은 하 이 라 이 트 는 다음 편 을 주목 하 세 요.만약 당신 이 글 이 당신 에 게 도움 이 된다 고 생각한다 면,당신 의 댓 글 을 남 겨 주 십시오.칭찬 을 눌 러 주 십시오.당신들 의 댓 글 을 볼 수 있 는 것 은 제 가 가장 기 쁜 일 입 니 다.왜냐하면 이것 은 제 가 저 처럼 망 설 였 던 소년 을 돕 고 있다 는 것 을 알 게 되 었 기 때 문 입 니 다.당신들 의 지 지 는 바로 제 가 계속 써 나 가 는 동력 입 니 다.우리 가 함께 공부 하고 함께 노력 하여 국산 게임 을 부흥 시 키 기 를 바 랍 니 다.
      문장의 누락 이나 잘못 에 대해 여러분 의 지적 을 환영 합 니 다.

좋은 웹페이지 즐겨찾기