Vertor 내적, 외적

백터의 내적

수학 이론으로 벡터의 내적은 v1 = (x, y, z), v2 = (a, b, c) 이라고 할 때,

||v1|| * ||v2|| * cosΘ 
= x*a + y*b + z*c

 와 같이 된다.

게임 프로그래밍에서 벡터의 내적은 두 물체 사이의 각도를 구하기 위하여 사용한다.
내적을 구할 때는 반드시 두 벡터를 Normalize를 시키고 해야 한다.

D3DXVECTOR3 vPos1(1.0f, 1.0f, 0.0f);
D3DXVECTOR3 vPos2(10.0f, 0.0f, 0.0f);

D3DXVec3Normalize(&vPos1, &vPos1);

D3DXVec3Normalize(&vPos2, &vPos2);

float iRadian = D3DXVec3Dot(&vPos1, &vPos2);

float iDegree = D3DXToDegree(acos(iRadian));

DX의 D3DXToDegree 함수는 라디안 값을 각도 값으로 변경하여 준다.

벡터의 외적

벡터의 외적은 두 벡터가 있다면, 두벡터와의 각이 90도인 벡터를 구하는 것이다.
시작 벡터에서 목표점 벡터 방향으로 왼손을 감싸주면 엄지가 가르키는 방향이 그 벡터의 외적이다.

게임 프로그램에서는 외적은 fps의 경우 케릭터가 보는 시점은 그대로 이고 케릭터가 이동을 할 경우에 외적을 이용한다.

DX에서는 다음과 같이 사용 된다. vPos1 과 Pos2의 외적을 구해서 vTemp에 넣어 주게 된다.

D3DXVECTOR3 vPos1(1.0f, 1.0f, 0.0f);

D3DXVECTOR3 vPos2(10.0f, 0.0f, 0.0f);

D3DXVECTOR3 vTemp;

D3DXVec3Cross(&vTemp,&vPos1,&vPos2);



by 유이 | 2012/01/26 20:46 | DirectX | 트랙백 | 덧글(0)

Vector

벡터란 위치 정보를 가지고 있지 않고, 방향과 크기(즉, 길이만)를 가지고 있는 선이다.
게임 프로그래밍에서 기본벡터를 방향을 가지고 있으므로 방향 벡터라고 칭하고, vLook 이런 식으로 이름을 지어 사용하게 된다.
또한, 실제로는 없지만 게임 프로그래밍의 편의를 위해서 위치를 나타내기 위한 위치 벡터를 만들어 vPos라는 식의 이름으로 만들어 사용한다. 위치 벡터도 벡터의 더하기, 빼기, 정규화(Normalize)이 문법적으로는 문제가 없다. 하지만 위치만을 나타내 주기 위해 만든 벡터이므로 위의 연산들은 하지 않도록 하자.

그리고 기본 개념으로 DX를 프로그래밍을 할때 좌표값은 플라밍고의 왼손 법칙의 손모양을 그대로 사용하고, 중지는 x의 +방향
검지는 z축의 +방향, 엄지는 y축의 +방향을 나타냄을 알고 있자. 사용하진 않지만 Opengl의 경우에는 오른손을 사용한다.

실제로 DX에서는 다음과 같이 벡터를 만든다.
D3DXVECTOR3 vPos(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 vLook(10.0f, 0.0f, 0.0f);


벡터의 합

벡터의 합은 위치 벡터에 플레이어가 위치 하고 있다면, 그 플레이어를 방향벡터로 이동 시키기 위하여 사용한다.
수학적 이론에서 사용되는 벡터의 합은 다음과 같다.(2차원)
벡터 u = (x,y)
벡터 v = (a,b)
 u + v = (x+a, x+b)



수학적 이론으로는 위와 같고 DX에서는 연산자 오버로딩을 사용하여 벡터의 합을 구하게 된다.
vPos += vLook;
보통 위가 같은식으로 사용한다.


벡터의 차

기준 벡터에서 다른 벡터를 빼게 되면 나오는 벡터는 기준 벡터에서 다른 벡터를 가르키는 벡터가 만들어진다. 그러므로 벡터의 차는 게임에서 두객체 즉, 플레이어와 몬스터가 있다면 한 쪽에서 다른쪽으로 이동하기 위해서 사용한다.

수학적 이론에서 사용되는 벡터의 차는 다음과 같다.(2차원)
벡터 u = (x,y)
벡터 v = (a,b)
 u + v = (x-a, x-b)



벡터의 길이

u = (1, 2, 3) 이라고 할 경우 벡터의 길이는 다음과 같다.

실제 코드에서는 다음과 같이 사용한다.
float fDist = D3DXVec3Length(&vLook);


단위 벡터

단위 백터는 벡터의 길이를 1로 만든것이다.
실제 코드에서는 다음과 같이 사용한다.
D3DXVec3Normalize(&vTemp, &vLook);
vLook를 정규화 하여 vTemp에 저장하고, D3DXVECTOR3로 리턴값을 보낸다.

by 유이 | 2012/01/26 17:35 | DirectX | 트랙백 | 덧글(0)

DirectX를 위한 기본 작업

우선 DirectX SDK란 것을 설치 해야 한다. 설치시에 만약에 Runtime Install Type를 선택 하라고 나온다면 Debug Mode로 설치 해야한다.
DirectX SDK를 설치 한 후에 Visiual Studio에 include와 Library 폴더를  아래 경로(디폴트로 설치할 시)추가해준다.

C:\Program Files\Microsoft DirectX SDK (June 2010)\Include
C:\Program Files\Microsoft DirectX SDK (June 2010)\Lib

그리고 stdafx.h에 다음과 같이 include파일과 Library파일을 추가해준다.

#include <d3dx9.h>
#include <d3d9.h>

#pragma comment (lib, "d3dx9.lib")
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "dxguid.lib")

위의 함수들은 추가해 줘야 DX에서 모든 기능을 사용할 수 있다고 생각해두자.
dxguid.lib 없으면 벡터도 쓰지 못한다고 한다.

by 유이 | 2012/01/26 16:41 | DirectX | 트랙백 | 덧글(0)

lhs, rhs에 관하여

사용자 정의 유형의 "Time"에 추가 허용하는 연산자 오버로딩의 예시 (C++에서):

Time operator+(const Time& lhs, const Time& rhs) 
{
Time temp = lhs;
    temp.seconds += rhs.seconds;
    if (temp.seconds >= 60)
    {
        temp.seconds -= 60;
temp.minutes++;
}
temp.minutes += rhs.minutes;
    if (temp.minutes >= 60)
    {
        temp.minutes -= 60;
temp.hours++;
}
    temp.hours += rhs.hours;
return temp;
}

덧셈은 왼쪽과 오른쪽 피연산자를 의미하는 이항 연산이다. C++에서, 전달되는 인자는 피연산자이며, 임시 개체가 반환 값이다. 연산자는 또한 클래스 메서드를 정의할 수 있으며, 숨겨진 this 인수로 lhs를 대체한다. 그러나 이것은 왼쪽 피연산자 타입 Time의 효과와 this는 수정 가능하게 될 수 있는 lvalue(왼쪽 값)을 추정한다.

 Time Time::operator+(const Time& rhs) const {
Time temp = *this; /- 'this' 값 복사, 이것은 수정되지 않는다. *-
temp.seconds += rhs.seconds;
if (temp.seconds >= 60)
    
{
temp.seconds -= 60;
temp.minutes++;
}
temp.minutes += rhs.minutes;
if (temp.minutes >= 60)
     {
temp.minutes -= 60;
temp.hours++;
}
temp.hours += rhs.hours;
return temp
;
}

this에서 작동되는 클래스 메서드로 정의된 단항 연산자는 명백한 인수를 받을 일은 없을 거라고 한다:

bool Time::operator!() const {
return ((hours == 0) && (minutes == 0) && (seconds == 0));
}

by 유이 | 2011/12/29 21:26 | C & C++ | 트랙백 | 덧글(0)

삼각함수를 이용한 객체간의 거리 및 각도 구하기

(m_fX, m_fY)에서 부터 m_fAngle 각도로 100 길이만큼 이동한 (m_fX2, m_fY2) 구하기


m_fX2 = cos(m_fAngle * PI / 180) * 100 + m_fX;
m_fY2 = -sin(m_fAngle * PI / 180) * 100 + m_fY;

컴퓨터는 각도를 표현 하지 못하고 라디안으로 표시 하는데 1도를 라디안으로 변환 하면
대충 PI = 3.141592라고 가정하고 변환 하면  1도 = PI /180 이다.

그 이유는 라디안이라는 것은 원의 호의 길이 인데 원의 둘레는 2πr(r은 반지름이고, 반지름을 1이라 가정)이고 원의 각도는 360도
결국 360도 = 2π이므로 1도 = π /180 이게 된다.

그리고 직각 삼각형의 길이를 모두 알고 각도Θ를 구할려면

float fAngle = acos(cosΘ) * 180 / PI;
여기서 * 180 / PI는 라디안을 각도로 변경 하기 위한것이다.

직각 삼각형이 있다고 가정하면,
cosΘ = 빗변 / 밑변
이다.

by 유이 | 2011/12/29 13:11 | C & C++ | 트랙백 | 덧글(0)

SingleTon 패턴

프로그램에서 유일 하게 한개만 존재.
아래의 소스는 API에서 2개의 객체의 거리와 각도를 구해서 반환 해주는 싱글톤 클래스이다.

기본 싱글톤 구조 (헤더 파일)
#pragma once

 
class CCheckCollision
{
private:
 static CCheckCollision* m_pInst;

public:
 static inline CCheckCollision* GetInst(void)
 {
  if(!m_pInst)
   m_pInst = new CCheckCollision;
  return m_pInst;
 }

public:
 static inline void DestroyInst(void)
 {
      if(m_pInst)
      {
          delete m_pInst;
          m_pInst = NULL;
      }
 }

private:
 CCheckCollision(void);
 ~CCheckCollision(void);
};



기본 싱글톤 구조 (cpp 파일)

#include "StdAfx.h"
#include "CheckCollision.h"

CCheckCollision* CCheckCollision::m_pInst = NULL;

CCheckCollision::CCheckCollision(void)
{
}

CCheckCollision::~CCheckCollision(void)
{
}



실제 적용 예제.

//        CheckValue.h                //


#pragma once                                                                // 헤더 중복 방지

#include "Defines.h"                                                        // 헤더 파일을 모아놓은 헤더파일
#include "Value.h"                                                          // typedef로 형식 변환 및 자주 쓰는 변수등을 모아놓은 헤더파일

class CCheckValue
{
private:
   static CCheckValue* m_pInst;                                    

public:
   static inline CCheckValue* GetInst(void)
   {
        if(!m_pInst)
            m_pInst = new CCheckValue;
        return m_pInst;
   }

public:
inline void DestroyInst(void)
{
   if(m_pInst)
   {
       delete m_pInst;
       m_pInst = NULL;                                                       // 동적 할당한 것을 해제 후엔 NULL값을 채워주는게 좋다.
    }
}

public:
 _PFLOAT GetValue(CObj* pDest, CObj* pSour);                   //_PFLOAT 는 float * 을 typedef로 형식 변환 해놓은것.
private:
    CCheckValue(void);
    ~CCheckValue(void);
};





//        CheckValue.cpp                //
#include "StdAfx.h"
#include "Value.h"
#include "CheckValue.h"

CCheckValue* CCheckValue::m_pInst = NULL;

CCheckValue::CCheckValue(void)
{
}

CCheckValue::~CCheckValue(void)
{
}

_PFLOAT CCheckValue::GetValue(CObj* pDest, CObj* pSour)
{
    _FLOAT fWidth;
    _FLOAT fHeight;
    static _FLOAT fValue[2];                                     // 0은 거리, 1은 각도를 저장

    fWidth = _FLOAT(pDest->GetPos().left - pSour->GetPos().left);
    fHeight = _FLOAT(pDest->GetPos().top - pSour->GetPos().top);

    fValue[0] = sqrt(pow(fWidth,2) + pow(fHeight,2));
    fValue[1] = acos(fValue[0] / fWidth) * 180 / PI;

    if(pDest->GetPos().top / 2 > pSour->GetPos().top / 2)
   {
        fValue[1] = 360.0f - fValue[1];
    }

     return fValue;
}



m_fAngle = *(CCheckValue::GetInst()->GetValue(m_pPlayer, this) + 1);
이런식으로 사용한다.

by 유이 | 2011/12/29 12:49 | C & C++ | 트랙백 | 덧글(0)

template 활용

CObj 클래스를 이용하여 다형성을 이용하여 즉, Cobj를 상속받아 플레이어나 몬스터, 총알클래스 등을 만들어준다.
여기서 몬스터나 총알의 경우는 플레이어처럼 한개만 생성해주는게 아니라 여러개 생성 해줘야 하므로 리스트를 이용한다.
몬스터나 총알등의 생성을 자주 해줘야 하게 되는데, 템플릿을 활용하여 이런 객체 생성을 관리 하여 줄 수 있다.

#pragma once

//클래스의 프로토타입.
class CObj;

template <class T> class CObjFactory                              // <class T>가 C++식 표현, <typename T> C식 표현.
{
public:
 //abstract factorial
 static inline CObj* CreateObj(void)                                   // 어디서든 사용하기 위해 static으로 선언
 {
  CObj* pObj = NULL;
  
  pObj = new T;  

  pObj->Init();

  return pObj;  
 }

private:
 CObjFactory(void) {}
 ~CObjFactory(void) {}
};


위 템플릿에 의해 객체 생성은 다음과 같은 식으로 해주게 된다.

CObj*    m_pPlayer = CObjFactory<CPlayer>::CreateObj();

// 몬스터 3마리 생성
for(_INT i = 0; i < 3; ++i)
 {
  m_MonsterList.push_back(CObjFactory<CMonster>::CreateObj());
  iter = m_MonsterList.end();
  --iter;
  ((CMonster*)*iter)->SetPos(600, i * 100 + 100);            //몬스터 생성후 생성한 몬스터 위치를 다르게 잡아준다.
  ((CMonster*)*iter)->SetBulletList(&m_BulletList[BI_MONSTER]);    // 총알리스트의 포인터를 몬스터 클래스에 넘겨준다.
  ((CMonster*)*iter)->SetPlayer(m_pPlayer);                                  // 총알을 플레이어에게 쏘거나 총알 충돌처리를
                                                                                                 // 위해 플레이어 클래스의 포인터를 넘겨준다.
                                                                                                 // 다형성을 이용하므로 형변환을 통해 몬스터 클래스에서
                                                                                                 // 생성한 함수를 이용한다. (CMonster*) 가 형변환임
                                                                                                 // CObj를 상속받아 클래스가 형성되기 때문.
                                                                                                 // 3개의 함수는 몬스터 클래스에 구현되어 있다.
 }

by 유이 | 2011/12/29 12:28 | C & C++ | 트랙백 | 덧글(0)

API 구조 2

API 구조에서 메시지 처리부분 Peekmessage 부분에서
if문으로 MainGame의 Init 함수를 불러 MainGame 클래스를 초기화 해주고,
Progress 함수에서 처리를 하고, Progress 함수 끝에서 Render 함수를 호출하여, 화면에 뿌려준다.
게임의 기본 구조는 Init로 초기화 해주고, Progress로 처리하고, Render로 Progress로 처리한걸 그려주는 방식으로 하는게
구조적으로 좋다.
MainGame 클래스 예제

//------------------------------------ MainGame.h ------------------------------------ //

#pragma once                     // 중복 include를 제거 하기 위해 쓴다.

#include "Defines.h"             // include 파일들을 모아 놓은 헤더 파일
                                         // 헤더 파일의 순서로 인한 헤더 참조가 꼬일 수 있으니 주의!!!!
#include "Value.h"               // typedef한 변수 타입이나 enum문등 여러 클래스에서 같이 쓰이는것을 모아 놓은 헤더파일

class CMainGame
{
private:
 HDC   m_hdc;                   // 윈도우 화면 안에 쓰이는 선이나 도형 색상등의 정보가 들어 있는 것이다.
 CObj*  m_pPlayer;            // Obj란 부모 클래스에서 다형성을 이용하여 자식 클래스에게 상속을 내려줘서 하기 위해 
                                        // 이와 같이 객체를 선언.
 list<CObj*> m_MonsterList;                  // Obj 클래스에는 기본 Init, Progress, Render 함수를 가상함수화 해서 자식에서 사용
 list<CObj*> m_BulletList[BI_END];        // 다시 사용하게 해주고, 자식들은 Obj 클래스에서 상속을 받으므로 상속을 받은

                                                          // 클래스 등은 서로 충돌 체크 및 서로의 거리 등의 체크가 쉽게 할 수 있다.

                                                         // BulletList는 몬스터 총알과 플레이어 총알을 구분해서 체크 하기 위해 enum을 
                                                        // 이용하여 리스트를 생성 하였다.
// enum문은 value.h 파일에 다음과 같이 선언 되어 있다.
// enum BULLETID {BI_PLAYER, BI_MONSTER, BI_END};
// 플레이어 ID와 몬스터 ID, 그리고 총알의 끝을 알려 주는 BI_END를 만들어서 리스트에서 push_back 할 때,
// iter로 for문을 돌려서 생성 할 때, 총알 리스트 갯수를 BI_END로 갯수 처리도 가능하다.
                        
public:
 bool Init(void);
 void Progress(void);
 void Render(void);


public:
 CMainGame(void);
 ~CMainGame(void);
};

//------------------------------------MainGame.cpp------------------------------------//


#include "StdAfx.h"
#include "MainGame.h"

CMainGame::CMainGame(void)
: m_pPlayer(NULL)                                     // Obj 클래스의 주소로 선언한 m_pPlayer 포인터 변수를 NULL로 초기화
                                                                //  헤더 파일 참조.
{
 
}

CMainGame::~CMainGame(void)
{
 list<CObj*>::iterator iter;

 ReleaseDC(g_hWnd, m_hdc);            // API 메인 함수에서 전역으로 선언했던 g_hWnd핸들 값의 HDC 값을 리턴하는 함수

 delete m_pPlayer;

 for(iter = m_MonsterList.begin(); iter != m_MonsterList.end(); ++iter)
 {
  delete *iter;                  // 몬스터 객체의 포인터로 객체 삭제
  *iter = NULL;                // 포인터 주소값을 NULL로 대입 . 이렇게 해야 객체가 재 참조 될 때 쓰레기 값이
   }                                 // 않 들어가므로 체크가 가능 해진다.

 m_MonsterList.clear();         // 리스트에 저장되어 있는 객체의 주소의 이름 삭제


}

bool CMainGame::Init(void)
{
 list<CObj*>::iterator iter;               // 몬스터 객체의 주소값을 가지고 있는 리스트를 만들기 위해서 리스트의 주소값인
                                                  // iter 선언

 m_hdc = GetDC(g_hWnd);            // API 메인 함수에서 전역으로 선언했던 g_hWnd핸들 값의 HDC 값을 받아오는 함수
                                                  // GetDC 함수를 사용하면 객체 소멸시 반드시 ReleaseDC 함수로 HDC값을 반환해야함.

 m_pPlayer = CObjFactory<CPlayer>::CreateObj();

 //플레이어한테 총알 정보와 몬스터 정보를 보냄(Set함수들은 Cplayer클래스에 있음.)
 ((CPlayer*)m_pPlayer)->SetBulletList(&m_BulletList[BI_PLAYER]);
 ((CPlayer*)m_pPlayer)->SetMonsterList(&m_MonsterList);


 for(_INT i = 0; i < 3; ++i)
 {
  m_MonsterList.push_back(CObjFactory<CMonster>::CreateObj());
  iter = m_MonsterList.end();
  --iter;                                                                   // iter의 끝을 잡아주고 감소 연산자를 사용하여 방금 생성한 
                                                                             //  객체의 주소값으로 함수들이 접근이 가능해진다.
  ((CMonster*)*iter)->SetPos(600, i * 100 + 100);        // SetPos 함수는 몬스터 클래스에서 몬스터의 중심점 x,y좌표를 
                                                                            // 대입해주는 녀석이다.
  ((CMonster*)*iter)->SetBulletList(&m_BulletList[BI_MONSTER]);
 }
 return true;
}

//  Peekmessage에서 처리 해줄때, GetTickCount()로 시간값을 받아 줄때 +10을 해줘서 0.01초 마다 불러지는 함수다.)
void CMainGame::Progress(void)
{
 list<CObj*>::iterator iter; 

 m_pPlayer->Progress(); 

 for(iter = m_MonsterList.begin(); iter != m_MonsterList.end(); ++iter)
 { 
  (*iter)->Progress();
 }

 for(_INT i = 0; i < BI_END; ++i)         // enum 값으로 0이면 플레이어 1이면 몬스터 2면 총갯수를 사용해서 enum문의 2중 활용
 {
  for(iter = m_BulletList[i].begin(); iter != m_BulletList[i].end(); ++iter)
  {
   (*iter)->Progress();
  }
 }
 Render(); 
}
void CMainGame::Render(void)
{
 list<CObj*>::iterator iter;
 list<CObj*>::iterator iter1;

 TCHAR szBuf[128] = {0};        // 화면에 글씨 출력을 위한 char 변수 초기화.

// WINSIZEX, WINSIZEY는 상수로 윈도우 사이즈의 가로, 세로 값을 넣었다.
 Rectangle(m_hdc, 0, 0, WINSIZEX, WINSIZEY);            // fake로 화면에 사각형을 그려 다른 객체들의 잔상을 않보여준다.
                                                                               // 케릭터등이 움직 일때 기존것을 삭제 않해주고 계속 그려주므로
                                                                               // 이것을 선언하지  않으면, 플레이어등이 이동하면 플레이어등이
                                                                               // 주루룩 그려진다.

 m_pPlayer->Render(m_hdc);                                    // api에서 화면을 그릴 때 하는 HDC 값을 다른 클래스에 넘겨줘서
                                                                               // 다른 클래스에 객체등을 그리게 해준다.
                                                                               // HDC은 도형을 그릴때 테두리색이나 글자를 출력 할 때, 
                                                                               // 글자색등의 정보를 가지고 있다.

 for(iter = m_MonsterList.begin(); iter != m_MonsterList.end(); ++iter)
 {
  (*iter)->Render(m_hdc);  
 }

 for(_INT i = 0; i < BI_END; ++i)
 {
  for(iter = m_BulletList[i].begin(); iter != m_BulletList[i].end(); ++iter)
  {
   (*iter)->Render(m_hdc);
  }
 } 
}

by 유이 | 2011/12/27 21:20 | API | 트랙백 | 덧글(0)

API 구조


HINSTANCE hInst;
윈도우즈 프로그램은 멀디테스킹이 가능하므로 그 프로그램에 관리해주는 핸들값이 필요하다.
winapi의 경우 위의 값을 쓴다는 것만 알면된다. 직접 수정은 할 필요는 없으며 그냥 할당받아 쓰는 용도로 쓰면 된다.
HWND g_hWnd; 로 전역 변수에 선언을 하여 프로젝트 어디서든 사용 가능하게 하도록 하자.


cf) value.h 파일

#pragma once

#include "stdafx.h"

using namespace std;

typedef unsigned int _UINT;
typedef signed int _INT, *_PINT;
typedef float _FLOAT;


//━━━━━━━━상수 정의━━━━━━━━//
const DWORD DWFIRE = 0x0001;
const DWORD DWUNFIRE = 0x0002;


//━━━━━━━━상수 정의━━━━━━━━//
const _INT WINSIZEX = 800;
const _INT WINSIZEY = 600;

 

//━━━━━━━━열거형 정의━━━━━━━━//
enum BULLETID {BI_PLAYER, BI_MONSTER, BI_END};

 

 

//Value.h파일을 포함한 모든 클래스에서 g_hWnd를 사용할수 있게 하겠다.
//extern 현재 프로젝트 상에 위치한 모든 cpp파일을 검색해서.
//extern뒤에 있는 타입과 이름이 일치한 녀석을 찾고, 그 일치한녀석이 값이 정의되어있다면,
//그 값을 바로 사용하겠다.

extern HWND g_hWnd;                            // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)에 보면
                                                            // hWnd값을 전역으로 사용하기 위해서 g_hWnd에 대입 해주고 있다.



API의 기본 구조는 윈도우를 생성하고, 메시지를 받고, 그 메시지를 처리 하는 구조이다.
메시지는 WndProc 함수에서 만들어서 _tWinMain의 GetMessage에서 부분에서 처리 하는데 처리하는 방식이 느리므로
다음과 같이 변경해서 사용한다.

// DX에 가면 디바이스를 사용 할 때, 프로그래머가 디바이스를 초기화 해야 하므로 그 연습을 위해
// MainGame 클래스를 초기화 하면서 아래와 같이 체크 해준다.

if(!MainGame.Init())                     
 {
  MessageBox(g_hWnd, L"게임 초기화 실패", L"SYSTEM ERROR", MB_OK);
  return 0; 
 }


// 기본 메시지 루프입니다.
 while (GetMessage(&msg, NULL, 0, 0))
 {
  if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
  {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }
 }


이것을 다음과 같이 변경.

while(true)
 {
  if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))            //기본 구조는 GetMessage와 같으나 PM_REMOVE 
  {                                                                                     // 메시지를 처리한후에 그 메시지를 삭제 하는 옵션이다.
      if(msg.message == WM_QUIT)                       //PeekMessage로 처리 할 경우 프로그램 종료를 위해 이어야함
      break;
   TranslateMessage(&msg);                            //메시지해석
   DispatchMessage(&msg);                            //메시지 처리부분으로 보냄
  }
  else
  {
// GetTickCount())  현재 시간을 초로 받아오는 함수(1초에 1000인데 정밀하지는 않다.) //
   if(dwTime + 10 < GetTickCount())                           
    {
    dwTime = GetTickCount();
    MainGame.Progress();                        //MainGame는 실제 게임의 메인 부분을 처리하는 클래스의 연산하는 
                                                             //부분의 함수 즉 CMainGame 클래스의 Progress 함수를 부르는 것이다.
   }   
  }
 }



ATOM    MyRegisterClass(HINSTANCE hInstance);  // 윈도우 창 정보 관련 윈도우 화면 크기등등.
BOOL    InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

MyRegisterClass의 wcex.lpszMenuName = NULL;
위와 같이 NULL값을 넣어 주면 윈도우 창의 파일,보기등의 메뉴 화면이 출력이 되지 않는다.

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, 800, 600, NULL, NULL, hInstance, NULL);

   g_hWnd = hWnd;                                            //윈도우 핸들을 프로젝트 전역에서 사용하기위해 g_hWnd라는

                                                                      //전역 변수를 만들어서 대입.
 if (!hWnd)     
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

by 유이 | 2011/12/21 20:37 | API | 트랙백 | 덧글(0)

STL 리스트

벡터와는 다르게 배열을 이용하지 않으며, 원소에 선행 원소의 포인터와 후행 원소의 포인터를 가지고 있다.
그에 따라 벡터처럼 랜덤 엑세스가 불가능 하다. 하지만 리스트는 벡터와는 다르게 삽입, 삭제때는 선행 원소와
후행 원소의 포인터값 즉, 위치값만 변경 해주면 되기 때문에 삽입, 삭제가 빠르다.
하지만 리스트는 특정 위치의 원소값에 접근 할때, 위치를 나타내 줄 것이 없기에
iterator라는 것을 사용한다. 벡터의 경우는 []등을 이용하여 특정 원소값에 쉽게 접근이 가능하다.
iterator는 begin()과 end()를 이용하여 시작 위치나 끝 위치를 정해서 증감연산자 (++ 혹은 --)을 이용하여 원소에 접근한다.
다른 것은 사용하면 않된다.

또한 iterator는 값을 삭제 한후에 후행 원소의 위치값을 리턴 하는데, 이것을 iterator에 대입 해주지 않는다면 error가 발생한다.
벡터는 다음과 같이 특정원소값에 접근하지만 리스트는 iterator를 이용하여 접근을 해야 한다.

벡터
vecItem[i]->m_iPrice

리스트
(*iter)->m_iPrice                //괄호의 위치가 중요하다. 연산자 우선 순위에 때문에


리스트를 사용하기 위해서는
#include<list>
#include<iostream>
using namespace std;
를 선언 해줘야 한다.

리스트의 선언
list<데이터 타입> 리스트의 이름;

iterator의 선언
list<데이터 타입>::iterator 이터레이터의 이름;
이터레이터는 헤더파일에 선언 하지 말고, 지역변수로 사용해야 한다.
헤더파일에 선언할 경우 에러를 유발 할 수 있다.


//Field클래스의 포인터를 원소값으로 받는 리스트 선언
list<CField*> m_FieldList;
// 리스트의 접근을 위한 iterator 선언
list<CField*>::iterator iter;

//m_FieldList에 저장된 Field 클래스의 GetName() 함수를 이용하여 Field 클래스에 저장된 특정한 문자열 값을 출력한다.
for(iter = m_FieldList.begin(), i = 0; iter != m_FieldList.end(); ++iter, ++i)
{
   cout << i + 1 << ". " << (*iter)->GetName() << endl;         // 연산자 우선순위에 의해서 괄호를 해주지 않으면 
}                                                                                    // *(iter->)가 먼저 호출 되어 error를 발생한다.


리스트에서 사용되는 함수들
vecItem.size()
vecItem.empty()
vecItem.swap(vecItem2)  vecItem과 vecItem2를 교체
vecItem.begin()
vecItem.end()
vecItem.insert()
vecItem.erase(위치)
vecItem.erase(시작점,끝점)
vecItem.clear()
vecItem.push_back()
vecItem.pop_back()

by 유이 | 2011/12/15 21:07 | C & C++ | 트랙백 | 덧글(0)

◀ 이전 페이지다음 페이지 ▶