'API/이론'에 해당되는 글 24건

  1. 2016.05.02 캐릭터 이동제한, y축 점프이동거리 감소, 홀드
  2. 2016.05.01 캐릭터 점프
  3. 2016.04.30 메모리 생성을 각 클래스 안으로 넣기.
  4. 2016.04.30 싱글턴을 이용한 메인함수의 메모리 버퍼 정리
  5. 2016.04.30 싱글턴 패턴
  6. 2016.04.29 이미지 깜박거림 없앰.
  7. 2016.04.29 캐릭터 뒷배경 검정색 없애기.
  8. 2016.04.29 시간 경과에 따른 애니메이션
  9. 2016.04.28 캐릭터 출력하기.
  10. 2016.04.27 배경을 클래스화 해서 출력하기.

캐릭터 이동제한, y축 점프이동거리 감소, 홀드

|

우선 캐릭터 이동거리 제한을 합시다.



빨간색 칸 안에서만 이동할 수 있도록 합시다.

첫 번째로 할 일은 캐릭터의 시작 지점을 바꿔주는 일입니다.


캐릭터의 시작 지점을 정해 주는 변수는 m_Position인데 Object클래스에서 상속받아서 사용하고 있습니다.

그렇기 때문에 Object클래스에 있는 변수의 값을 바꿔주도록 하겠습니다.


1
2
3
4
5
void Object::Init( HBITMAP _m_hResource )
{
    m_hResource   = _m_hResource;
    m_Position    = MakePoint(100,500);
}
cs


그러면 위 이미지와 같이 캐릭터가 저만한 위치에 서게 됩니다.


그리고 이동제한을 걸도록 하죠

1
2
if(pos.x > 0 && pos.x < 1080 && pos.y > 340 && pos.y < 570 )
    this->SetPos(pos.x, pos.y);
cs


저 if범위가 저 빨간색 칸의 범위 입니다.

캐릭터가 저 범위의 안에 있을때만 좌표를 Set하게 해서 범위 밖을 벗어나면 Set을 안하게 됨으로

캐릭터가 밖으로 나가지 못하게 됩니다.


1
2
3
void Hero::Action( float _dt )
{
}
cs

액션 함수 안에 넣어주시면 되겠습니다.


두 번째로 점프시 y축 이동 감소를 하도록 하겠습니다.

간단합니다

1
2
3
4
5
6
7
8
9
10
if(GetAsyncKeyState(VK_UP))
{
    if( m_iState != JUMP && m_iState != DROP ){ m_iState = WALK; pos.y -= m_MoveSpeed; }
    else pos.y -= m_MoveSpeed / 3;
}
if(GetAsyncKeyState(VK_DOWN))
{
    if( m_iState != JUMP && m_iState != DROP ){ m_iState = WALK; pos.y += m_MoveSpeed; }
    else pos.y += m_MoveSpeed / 3;
}
cs

점프중이 아니고 떨어지는 중이 아니면 일반적인 속도를

점프 중일때는 m_MoveSpeed / 3 스피드를 3/1로 감소 시킵니다.


마지막으로 홀드를 적용 시킵시다.

홀드는 점프를 시작할 때 움직일수 없게 하고

착지 할때 움직일 수 없게 하기 위한 것입니다.


클래스 맴버변수로

1
bool m_hold;
cs

를 추가 시킵시다.

초기화는

1
m_hold            =    FALSE;
cs

FALSE로 주시고


1
2
3
4
5
6
7
8
9
10
if(GetAsyncKeyState(VK_RIGHT))
{
    if(m_hold == FALSE ){ pos.x += m_MoveSpeed; m_iDirection = RIGHT; }
    if( m_iState != JUMP && m_iState != DROP ) m_iState = WALK;
}
if(GetAsyncKeyState(VK_LEFT))
{
    if(m_hold == FALSE ){ pos.x -= m_MoveSpeed; m_iDirection = LEFT; }
    if( m_iState != JUMP && m_iState != DROP ) m_iState = WALK;
}
cs

액션 함수에서의 키 값은

홀드가 FALSE일때만 움직일 수 있게 하면 됩니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
case JUMP:
    {
        m_srcPos        =    MakePoint(85,135);
        m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 610610);
        m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
        m_dFrameDelay += _dt;
        if(m_dFrameDelay < 0.1f)
        {
            m_JumpPower = JUMP_POWER;
            m_nFreame = 0;
            m_hold = TRUE;
            break;
        }
            
        m_fz += m_JumpPower * _dt;
        m_JumpPower -= GRAVITY * _dt;
 
        if(m_dFrameDelay > 0.1f){m_nFreame = 1; m_hold = FALSE;}
        if(m_dFrameDelay > 0.2f) m_nFreame = 2;
        if(m_dFrameDelay > 0.3f) m_dFrameDelay = 0.1f;
 
        if(m_JumpPower <= 0)
        {
            m_iState = DROP;
            m_JumpPower = 0;
            m_hold = FALSE;
        }
        break;
    }
cs


1
2
3
4
5
6
7
if(m_dFrameDelay < 0.1f)
{
    m_JumpPower = JUMP_POWER;
    m_nFreame = 0;
    m_hold = TRUE;
    break;
}
cs

점프 파워를 셋팅하는 부분에 홀드를 TRUE로 주겠습니다.

TRUE가 됬으니 움직이지 못할 겁니다.

하지만 게속 그 상태를 유지하면 안되므로


1
if(m_dFrameDelay > 0.1f){m_nFreame = 1; m_hold = FALSE;}
cs

시간 딜레이가 0.1보다 커지면 홀드를 FALSE로 바꿔주어 풀어 줍니다.


그리고 착지 할때도 움직이게 하면 안되므로

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    case DROP:
        {
            m_srcPos        =    MakePoint(85,135);
            m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 610610);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_fz -= m_JumpPower * _dt;
            m_JumpPower += GRAVITY * _dt;
            m_dFrameDelay += _dt;
 
            if(m_fz <= 0)
            {
                m_fz = 0;
                if(m_dFrameDelay > 0.2f) m_nFreame = 5;
                if(m_dFrameDelay > 0.3f) m_nFreame = 6;
                if(m_dFrameDelay > 0.4f){m_iState = IDLE; m_hold = TRUE; }
            }
            else
            {
                m_nFreame = 3;
                if(m_dFrameDelay > 0.1f) m_nFreame = 4;
            }
            break;
        }
cs


1
2
if(m_dFrameDelay > 0.4f){m_iState = IDLE; m_hold = TRUE; }
 
cs

딜레이 시간이 0.4보다 커질때 홀드를 TRUE시켜줍니다.

그럼 언제 홀드를 해제(FALSE)해 주느냐?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
case IDLE:
        {
            m_srcPos        =    MakePoint(54,144);
            m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 61010);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_dFrameDelay += _dt;
            if(m_dFrameDelay > 0.1f)
            {
                m_dFrameDelay = 0;
                m_nFreame++;
                m_hold = FALSE;
                if(m_nFreame >= 4) m_nFreame = 0;
            }
            break;
        }
    case WALK:
        {
            m_srcPos        =    MakePoint(75,143);
            m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 610310);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_dFrameDelay += _dt;
            if(m_dFrameDelay > 0.1f)
            {
                m_dFrameDelay = 0;
                m_nFreame++;
                m_hold = FALSE;
                if(m_nFreame >= 8) m_nFreame = 0;
            }
            break;
        }
 
cs

IDLE상태와  WALK상태 일때 하시면 됩니다.



결과




'API > 이론' 카테고리의 다른 글

캐릭터 점프  (0) 2016.05.01
메모리 생성을 각 클래스 안으로 넣기.  (0) 2016.04.30
싱글턴을 이용한 메인함수의 메모리 버퍼 정리  (0) 2016.04.30
싱글턴 패턴  (0) 2016.04.30
이미지 깜박거림 없앰.  (0) 2016.04.29
And

캐릭터 점프

|

현재 캐릭터의 좌표는 x,y로 관리하고 있다.

점프를 하기 위해서는 z축이 필요하다.

하지만 없으므로 가상 z축을 만들기로 하겠다.

물론 가상 z축은 실제로는 y축이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Hero : public Object{
private:
    HDC hDC;
    CGPoint m_srcPos;
    CGPoint m_srcSize;
    CGPoint m_offset;
    int m_iDirection;
    int m_iPrevState;
    int m_iState;
    int m_nFreame;
    float m_dFrameDelay;
    float m_MoveSpeed;
    float m_JumpPower;
    float m_fz;
public:
    virtual void Init( HBITMAP _m_hResource );
    virtual void Render();
    virtual void Update( float _dt );
 
    void Animation( float _dt );
    void Action( float _dt );
 
    static Hero *Create( HBITMAP _Hero );
};
cs

히어로 클래스의 맴버 변수를 2가지 추가 하도록 하겠다

하나는 가상z축과 또 하나는 점프하는 파워다.

변수명 

설명 

 m_JumpPower

점프 하는 힘. 

 m_fz

 가상 z축

그리고 헤더에 2가지를 정의하겠다.

1
2
#define JUMP_POWER    700
#define GRAVITY        1500
cs

점프하는 힘과 중력값이다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void Hero::Render()
{
    HDC m = ST::Call()->g_hMemDC;
    HDC b = ST::Call()->g_hBackBuffer;
 
    CGPoint pos = this->GetPos();
 
    pos.x -= m_offset.x + m_srcPos.x / 2;
    pos.y -= m_srcPos.y + m_fz;
 
    SelectObject(m, m_hResource);
 
    BitBlt(b, 
            pos.x, pos.y,
            m_srcPos.x, m_srcPos.y,
            m,
            m_srcSize.x + m_srcPos.x * m_nFreame, m_srcSize.y + m_srcPos.y,
            SRCAND);
 
    BitBlt(b, 
            pos.x, pos.y,
            m_srcPos.x, m_srcPos.y,
            m,
            m_srcSize.x + m_srcPos.x * m_nFreame, m_srcSize.y,
            SRCPAINT);
}
cs

가상 z축이지만 실제로는 y축을 이용해야 하기 때문에

점프 키를 누르면 y값이 +됐다가 다시 -되야 한다.

그렇기 때문에 pos.y에 m_fz을 + 해준다. (pos.y -= m_srcPos.y + m_fz;)

 

 

이제 상태에 따른 애니메이션을 주도록 하겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
void Hero::Animation( float _dt )
{
    if(m_iPrevState != m_iState)
    {
        m_iPrevState  = m_iState;
        m_dFrameDelay = 0;
        m_nFreame     = 0;
    }
 
    switch(m_iState)
    {
    case IDLE:
        {
            m_srcPos        =    MakePoint(54,144);
            m_srcSize        =    MakePoint(m_iDirection == RIGHT ? 0 : 61010);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_dFrameDelay += _dt;
            if(m_dFrameDelay > 0.1f)
            {
                m_dFrameDelay = 0;
                m_nFreame++;
                if(m_nFreame >= 4) m_nFreame = 0;
            }
            break;
        }
    case WALK:
        {
            m_srcPos        =    MakePoint(75,143);
            m_srcSize        =    MakePoint(m_iDirection == RIGHT ? 0 : 610310);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_dFrameDelay += _dt;
            if(m_dFrameDelay > 0.1f)
            {
                m_dFrameDelay = 0;
                m_nFreame++;
                if(m_nFreame >= 8) m_nFreame = 0;
            }
            break;
        }
    case JUMP:
        {
            m_srcPos        =    MakePoint(85,135);
            m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 610610);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_dFrameDelay += _dt;
            if(m_dFrameDelay < 0.1f)
            {
                m_JumpPower = JUMP_POWER;
                m_nFreame = 0;
                break;
            }
            
            m_fz += m_JumpPower * _dt;
            m_JumpPower -= GRAVITY * _dt;
 
            if(m_dFrameDelay > 0.1f) m_nFreame = 1;
            if(m_dFrameDelay > 0.2f) m_nFreame = 2;
            if(m_dFrameDelay > 0.3f) m_dFrameDelay = 0.1f;
 
            if(m_JumpPower <= 0)
            {
                m_iState = DROP;
                m_JumpPower = 0;
            }
            break;
        }
    case DROP:
        {
            m_srcPos        =    MakePoint(85,135);
            m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 610610);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            
            m_fz -= m_JumpPower * _dt;
            m_JumpPower += GRAVITY * _dt;
            m_dFrameDelay += _dt;
 
            if(m_fz <= 0)
            {
                m_fz = 0;
                if(m_dFrameDelay > 0.2f) m_nFreame = 5;
                if(m_dFrameDelay > 0.3f) m_nFreame = 6;
                if(m_dFrameDelay > 0.4f) m_iState = IDLE;
            }
            else
            {
                m_nFreame = 3;
                if(m_dFrameDelay > 0.1f) m_nFreame = 4;
            }
            break;
        }
    }
}
cs

 

점프 상태로 들어왔을 때

1
2
3
4
5
6
7
m_dFrameDelay += _dt;
if(m_dFrameDelay < 0.1f)
{
    m_JumpPower = JUMP_POWER;
    m_nFreame = 0;
    break;
}
cs

딜레이 시간이 0.1보다 작으면

점프 파워를 700으로 대입해주고 프레임을 0으로 대입시켜준다.

딜레이 시간때문에 이 if문은 다음부터는 실행되지 않게 된다.

 

1
2
m_fz += m_JumpPower * _dt;
m_JumpPower -= GRAVITY * _dt;
cs

z값이 = 점프파워(700) * 시간(0.1)

점프파워 = 중력(1500) * 시간(0.1)

시간이 지남에 따라 점프파워는 점점 감소하게 된다.

 

1
2
3
if(m_dFrameDelay > 0.1f) m_nFreame = 1;
if(m_dFrameDelay > 0.2f) m_nFreame = 2;
if(m_dFrameDelay > 0.3f) m_dFrameDelay = 0.1f;
cs

처음 점프를 뛰었을때에 프레임이라 생각하면 된다.

 

1
2
3
4
5
if(m_JumpPower <= 0)
{
    m_iState = DROP;
    m_JumpPower = 0;
}
cs

점프 파워가 점점 감소하므로 결국 0보다 작아진다.

0보다 작아지면 점프의 상태를 DROP로 바꿔주어 떨어주는 모션을 준다.

DROP같은 경우는 점프와 비슷하므로 자세한 설명은 생략하겠다.

 

 

키를 눌렀을때 점프를 해야되는데 그 키 값을 정해주도록 하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void Hero::Action( float _dt )
{
    CGPoint pos = GetPos();
    m_MoveSpeed = 300.0f * _dt;
 
    if( m_iState != JUMP && m_iState != DROP )
        m_iState = IDLE;
 
    if(GetAsyncKeyState(VK_RIGHT))
    {
        pos.x += m_MoveSpeed;
        m_iDirection = RIGHT;
        if( m_iState != JUMP && m_iState != DROP ) m_iState = WALK;
    }
    if(GetAsyncKeyState(VK_LEFT))
    {
        pos.x -= m_MoveSpeed;
        m_iDirection = LEFT;
        if( m_iState != JUMP && m_iState != DROP ) m_iState = WALK;
    }
    if(GetAsyncKeyState(VK_UP))
    {
        pos.y -= m_MoveSpeed;
        if( m_iState != JUMP && m_iState != DROP ) m_iState = WALK;
    }
    if(GetAsyncKeyState(VK_DOWN))
    {
        pos.y += m_MoveSpeed;
        if( m_iState != JUMP && m_iState != DROP ) m_iState = WALK;
    }
    if(GetAsyncKeyState('C'))
    {
        if(m_iState != DROP) m_iState = JUMP;
    }
    this->SetPos(pos.x, pos.y);
}
cs

 

 

1
if( m_iState != JUMP && m_iState != DROP )
cs

모든 키값에 if문 추가.

이 if문을 추가 시켜주면 점프중이나 드롭중일때 상태가 변하지 않으므로

2단 이상의 점프가 불가능 해진다.

 

1
2
3
4
if(GetAsyncKeyState('C'))
{
    if(m_iState != DROP) m_iState = JUMP;
}
cs

점프 키는 C가 되시겠다.

 

결과

 

 

 

And

메모리 생성을 각 클래스 안으로 넣기.

|

WM_CREATE에서 메모리 생성을 했던 것도

각 클래스로 집어넣어 봅시다.


우선 배경클래스로 가서

1
2
3
4
5
6
class BackGround : public Object {
public:
    virtual void Render();
    virtual void Update( float _dt ){}
    static BackGround *Create( HBITMAP BG );
};
cs


static BackGround *Create( HBITMAP BG );

를 만듭시다.


cpp에 함수를 구현 해 주시고요.

메모리를 반환해 줍시다.

1
2
3
4
5
6
ObjectBackGround *ObjectBackGround::Create( HBITMAP _BG )
{
    ObjectBackGround *g_CBackground = new ObjectBackGround;
    g_CBackground->Init( _BG );
    return g_CBackground;
}
cs


그 다음 똑같이 히어로 클래스로 가서

함수를 만들고 마찬가지로 함수를 구현해 줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Hero : public Object{
private:
    HDC hDC;
    CGPoint m_srcPos;
    CGPoint m_srcSize;
    CGPoint m_offset;
    int m_iDirection;
    int m_iPrevState;
    int m_iState;
    int m_nFreame;
    float m_dFrameDelay;
    float m_MoveSpeed;
public:
    virtual void Init( HBITMAP _m_hResource );
    virtual void Render();
    virtual void Update( float _dt );
 
    void Animation( float _dt );
    void Action( float _dt );
 
    static Hero *Create( HBITMAP _Hero );
};
cs


1
2
3
4
5
6
Hero *Hero::Create( HBITMAP _Hero )
{
    Hero *hHero = new Hero;
    hHero->Init( _Hero );
    return hHero;
}
cs


구현이 다 끝났으면 메인cpp에서 불러와야 겠죠

자, 더 줄여줍시다.



And

싱글턴을 이용한 메인함수의 메모리 버퍼 정리

|

싱클턴 클래스를 하나 만들어서

메모리 버퍼를 가져와 관리 하도록 하겠다.

ST.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
#include "header.h"
 
class ST{
private:
    ST(){}
public:
    static *ST instance;
    static *ST Call()
    {
        if( instance != NULL ) instance = new ST;
        return instance;
    }
 
    void CreateBuffer( HWND hWnd );
    HBITMAP CreateBitmap( int Index );
    void DeleteMemory();
};
cs

헤더 파일을 새로 하나 만들어준다.

함수 이름 

설명 

 void CreateBuffer( HWND hWnd );

 메모리 버퍼들을 만들어주는 함수.

 HBITMAP CreateBitmap( int Index );

 비트맵을 불러오는 함수.

 void DeleteMemory();

 생성된 메모리를 지워주는 함수.

 

초기화

 

 

메인cpp에 WM_CREATE에 있는 메모리 생성 부분을 ST클래스의 CreateBuffer함수로 가져온다.

 

DoubleBuffer.cpp

 

ST.h

버퍼들을 ST클래스의 CreateBuffer로 옮겨 줍시다.

 

DoubleBuffer.cpp

 

 ST.h

 

          불러온 비트맵을 반환 해줍니다.

 

LoadBitmap의 첫 번째 인자로 윈도우 핸들이 필요하므로 멤버 변수로 m_hInstance를 만들어 줍니다.

 

       m_hInstance의 초기화는 CreateBuffer 그러니까, 메모리가 만들어 질때 해주면 됩니다.

만들어진 핸들은 로드 비트맵 함수의 첫 번째 인자에 넣어 주도록 합시다.

 

메인 함수로 돌아와

필요 없어진 LoadBitmap을 지워주도록 합시다.

 

ST에 있는 버퍼 만드는 함수를 불러와 주시고

마찬가지로 비트맵을 불러오는 함수를 불러줍시다.

그리고 이제 g_hBackBuffer와 g_hMemDC는 필요 없으므로

Init에서 지워줍시다.

Object,

Object_BackGround,

Object_Hero

에 함수의 매개변수로 있는 g_hBackBuffer와 g_hMemDC를 다 지워주도록 합시다.

Object에는 g_hBackBuffer와 g_hMemDC의 맴버 변수도 필요 없어졌으므로 지워줍시다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
case WM_CREATE:
    {
        ST::Call()->CreateBuffer(hWnd);
        g_hBGA = ST::Call()->CreateBitmap(IDB_BITMAP1);
        g_hHero = ST::Call()->CreateBitmap(IDB_BITMAP2);
 
        g_CBGA = new BackGround;
        g_CBGA->Init( g_hBGA );
 
        g_CHero = new Hero;
        g_CHero->Init( g_hHero );
        break;
    }
cs


아직도 길기 때문에 조금더 줄여 주도록 하겠습니다.



 

 

이젠 만들어진 메모리를 삭제 합시다.

1
2
3
4
5
6
void ST::DeleteMemory()
{
    DeleteObject(g_hBackBitmap);
    DeleteDC(g_hMemDC);
    DeleteDC(g_hBackBuffer);
}
cs

 

1
2
3
4
5
6
 case WM_DESTROY :
{
    ST::Call()->DeleteMemory();
    PostQuitMessage(0);    
    break;
}
cs

 

 메모리를 저렇게 따로 지우는 이유는 WM_DESTROY()가 호출된다고 해서

프로그램이 바로 종료 되는것이 아니고

while루프를 몇번 더 돌기 때문에 메모리에 쓰레기값이 생깁니다 그렇기 때문에

while이 종료된 후에 지워주는 것이 더 확실하게 지워주는 것임돠

 

결과

 



잘 되네영


'API > 이론' 카테고리의 다른 글

캐릭터 점프  (0) 2016.05.01
메모리 생성을 각 클래스 안으로 넣기.  (0) 2016.04.30
싱글턴 패턴  (0) 2016.04.30
이미지 깜박거림 없앰.  (0) 2016.04.29
캐릭터 뒷배경 검정색 없애기.  (0) 2016.04.29
And

싱글턴 패턴

|

싱글턴이란?

 

클래스의 객체를 단 하나만 만들게 해놓은 패턴.

싱글턴 패턴을 사용하면 어디서든지 전역변수 사용하는 것처럼 같은 객체를 여러 곳에서 사용할 수 있다.

전역변수나 전역객체는 생성해놓고 쓰지 않으면 메모리가 낭비된다는 단점이 있으나,

싱글턴의 경우는 한번이라도 호출하지 않으면 생성 자체가 안되기 때문에 전역변수와 같은 단점이 없다.


1
2
3
4
5
6
7
8
9
10
11
12
class ST{
private:
    ST(){}
public:
    ~ST(){ delete instance; }
    static ST* instance;
    static ST* Call()
    {
        if( instance == NULL ) instance = new ST;
        return instance;
    }
};
cs

생성자를 private에 선언하면 클래스 내부에서만 객체선언이 가능해 진다.

And

이미지 깜박거림 없앰.

|

Object_Hero.cpp

애니메이션 함수 제일 위에 밑의 소스를 추가.

1
2
3
4
5
6
if(m_iPrevState != m_iState)
{
    m_iPrevState  = m_iState;
    m_dFrameDelay = 0;
    m_nFreame     = 0;
}
cs

 

전 상태가 지금 상태와 같지 않을경우.

전 상태를 지금 상태로 바꿔주고

시간 딜레이와

프레임을 모두 0으로 대입시켜준다.

 

 

결과

 

 

'API > 이론' 카테고리의 다른 글

싱글턴을 이용한 메인함수의 메모리 버퍼 정리  (0) 2016.04.30
싱글턴 패턴  (0) 2016.04.30
캐릭터 뒷배경 검정색 없애기.  (0) 2016.04.29
시간 경과에 따른 애니메이션  (0) 2016.04.29
캐릭터 출력하기.  (0) 2016.04.28
And

캐릭터 뒷배경 검정색 없애기.

|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Hero::Render()
{
    CGPoint pos = this->GetPos();
 
    pos.x -= m_offset.x + m_srcPos.x / 2;
    pos.y -= m_srcPos.y;
 
    SelectObject(m_hMemDC, m_hResource);
 
    BitBlt(m_hBackBuffer, 
            pos.x, pos.y,
            m_srcPos.x, m_srcPos.y,
            m_hMemDC,
            m_srcSize.x + m_srcPos.x * m_nFreame, m_srcSize.y + m_srcPos.y,
            SRCAND);
 
    BitBlt(m_hBackBuffer, 
            pos.x, pos.y,
            m_srcPos.x, m_srcPos.y,
            m_hMemDC,
            m_srcSize.x + m_srcPos.x * m_nFreame, m_srcSize.y,
            SRCPAINT);
}
cs



결과



'API > 이론' 카테고리의 다른 글

싱글턴 패턴  (0) 2016.04.30
이미지 깜박거림 없앰.  (0) 2016.04.29
시간 경과에 따른 애니메이션  (0) 2016.04.29
캐릭터 출력하기.  (0) 2016.04.28
배경을 클래스화 해서 출력하기.  (0) 2016.04.27
And

시간 경과에 따른 애니메이션

|

이번에는 시간 경과에 따른 애니메이션을 구현해 보도록 하겠다.

우선, 시간관련 함수를 사용하기 위해서는 #pragma comment(lib, "winmm.lib")을 포함 시켜야 한다.

헤더에 포함 시켜주도록 하자.




timeGetTime() 

 컴퓨터가 부팅된 시간으로부터 현재의 시간을 구한다.


위의 코드들을 간단히 설명하자면. '한번 싸이클을 도는 시간을 측정한다.'


예를들어서

deltaTime = timeGetTime();

PrevTime = timeGetTime();

이 두 변수에는 같은 시간이 들어가 있다.

들어가 있는 시간이 예를들어 5라고 해보자.


deltaTime  = timeGetTime() - PrevTime; // 5  = 5 - 5;

PrevTime = timeGetTime(); // 5


deltaTime에는 0이 들어가고

PrevTime에는 5가 들어가게 된다.


while에서 timeGetTime()으로 새롭게 시간을 가져왔지만,

 아직 싸이클을 다 돌지 않았기 때문에 위에 선언한 변수의 시간과 같은 시간이 들어온다.

한 번의 싸이클이 끝나고 다음 싸이클이 돌게되면

deltaTime  = timeGetTime() - PrevTime; // 0  = 6 - 5;

PrevTime = timeGetTime(); // 6


다음은


deltaTime  = timeGetTime() - PrevTime; // 1  = 7 - 6;

PrevTime = timeGetTime(); // 7

. . . . . .

이렇게 게속 돌게 되므로, 일정한 시간을 얻어올수 있게 된다.



Object_Hero.cpp

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

랜더

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Hero::Render()
{
    CGPoint pos = this->GetPos();
 
    pos.x -= m_offset.x + m_srcPos.x / 2;
    pos.y -= m_srcPos.y;
 
    SelectObject(m_hMemDC, m_hResource);
    BitBlt(m_hBackBuffer, 
            pos.x, pos.y,
            m_srcPos.x, m_srcPos.y,
            m_hMemDC,
            m_srcSize.x + m_srcPos.x * m_nFreame, m_srcSize.y,
            SRCCOPY);
}
cs

오프셀을 적용시켜준다.

※오프셀이란?





애니메이션

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void Hero::Animation( float _dt )
{
    switch(m_iState)
    {
    case IDLE:
        {
            m_srcPos        =    MakePoint(54,144);
            m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 61010);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_dFrameDelay += _dt;
            if(m_dFrameDelay > 0.1f)
            {
                m_dFrameDelay = 0;
                m_nFreame++;
                if(m_nFreame >= 4) m_nFreame = 0;
            }
            break;
        }
    case WALK:
        {
            m_srcPos        =    MakePoint(75,143);
            m_srcSize       =    MakePoint(m_iDirection == RIGHT ? 0 : 610310);
            m_offset        =    MakePoint(-m_srcPos.x / 2-m_srcPos.y);
 
            m_dFrameDelay += _dt;
            if(m_dFrameDelay > 0.1f)
            {
                m_dFrameDelay = 0;
                m_nFreame++;
                if(m_nFreame >= 8) m_nFreame = 0;
            }
            break;
        }
    }
}
cs


액션

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void Hero::Action( float _dt )
{
    CGPoint pos = GetPos();
    m_MoveSpeed = 300.0f * _dt;
 
    m_iState = IDLE;
    if(GetAsyncKeyState(VK_RIGHT))
    {
        pos.x += m_MoveSpeed;
        m_iDirection = RIGHT;
        m_iState = WALK;
    }
    if(GetAsyncKeyState(VK_LEFT))
    {
        pos.x -= m_MoveSpeed;
        m_iDirection = LEFT;
        m_iState = WALK;
    }
    if(GetAsyncKeyState(VK_UP))    pos.y -= m_MoveSpeed;
    if(GetAsyncKeyState(VK_DOWN))  pos.y += m_MoveSpeed;
 
    this->SetPos(pos.x, pos.y);
}
cs

함수들을 차례차례 수정한다.


결과




And

캐릭터 출력하기.

|

이번에는 캐릭터를 출력해 보도록 하자.


캐릭터 이동 정보를 담을 구조체 하나를 선언하자.

좌표는 당연히 x,y축이다.

그 밑에는 x,y를 편하게 사용하기 위해 정의한 함수다.

이 모든것을 header.h파일에 소스를 적어주면 된다.

그리고 저 사진에는 안나왔지만

전처리 헤더파일을 한 번만 참조해주기 위해서

맨 위에 #pragma once를 적어주도록 하자.



header.cpp파일에 함수를 정의해 놓은 것이다.



캐릭터에는 여러가지 상태가 있을것이다.

Direction

바라보는 방향

설명

RIGHT

캐릭터가 오른쪽을 바라본다

LEFT

캐릭터가 왼쪽을 바라본다.

 

State

캐릭터 상태 

설명 

 IDLE

 아무런 움직임이 없는 상태

 WALK

 오른쪽 혹은 왼쪽으로 걷는 상태

 JUMP

 점프를 뛴다.(상승한다.)

 DROP

 점프를 뛴다.(하강한다.)

 ATTACK

 공격모션

 HIT

 충돌




캐릭터의 좌표이동에 대한 정보를 셋팅하는 동시에 가져오기 위하여

멤버 변수로 변수를 하나 만들어주고

멤버 함수도 Set과 Get을 만들어 주었다.

Object에 만들어 곧바로 상속 받게 한다.


 

 

 변수명

설명 

 CGPoint m_srcPos;

 리소스에서의 x,y좌표

 CGPoint m_srcSize;

 리소스의 사이즈를 나타낸다.

 CGPoint m_offset;

 출력된 리소스의 출력위치 변환을 위한 변수

 int m_iDirection;

 캐릭터가 바라보는 방향

 int m_iPrevState;

 캐릭터의 전 상태

 int m_iState;

 현재 캐릭터의 상태

 int m_nFreame;

 리소스 프레임

 float m_dFrameDelay;

 다음 프레임 까지의 경과시간

 float m_MoveSpeed;

 움직이는 속도.

 

void Animation();

void Action();

이 두개의 멤버 함수는

각각 캐릭터의 상태 변화에 따른 애니메이션 적용과

사용자의 키보드의 키값에 따른 변화를 적용할 함수이다.

이것 다음 글에서 구현 하도록 하고 이번 글에서는 캐릭터를 출력만 하겠다.

 


 

선언한 변수들을 모조리 초기화 한다.

MakePoint는 헤더에서 구현한 구조체의 x,y값을 정의한 함수이다.


 

만들어진 리소스를 사용하기 위하여 Hero의 헤더를 포함 시킨다.

그리고 클래스 변수를 전역 변수로 선언한 뒤

비트맵DC 하나 전역변수로 선언해 캐릭터를 가져 올 수 있게 한다.


 

메세지 루프 구문에서는 캐릭터를 뿌려주는 랜더 함수를 불러오도록 한다.


 

 g_hHero에 LoadBitmap으로 비트맵을 불러온다.

동적 할당한 메모리에 초기화 함수를 불러와 메모리DC와 캐릭터 리소스를 셋팅 및 초기화 해준다.

 

이 과정이 완료되면 메모리 해제를 잊지 말도록 하자.


 

결과


And

배경을 클래스화 해서 출력하기.

|

배경 클래스 헤더 파일을 하나 만들어서 클래스를 하나 선언한다.

클래스의 이름은 BackGround이며 이 클래스는 Object클래스를 부모로 상속받는다.

부모클래스인 Object클래스에서

두 개의 순수 가상함수가 있는데,

Render와 Update다.

순수가상함수를 가볍게 설명 하자면 내용이 없다는 뜻에서 =0이 붙은 함수이다.

이 멤버함수가 포함된 클래스를 상속 받을 시에는 가상 멤버함수로 선언된 함수들을 반드시 재 정의 해줘야 한다.


보시다시피 Render와 Update의 2개의 멤버함수가 있지만 우리가 사용할 것은

Render멤버함수 뿐이다.

Update는 쓰지 않으므로 부모클래스에서 상속 받을 필요는 없지만,

부모 클래스가 다른 클래스도 상속 해 줄수 있으니 별 수 없이 받아오는 것이다.

그런데 별수 없이 받아온 함수가 순수 가상함수 이니 재 정의를 해줘야 하는데

그 방법은 어렵지 않다.

그냥 함수 앞에 블럭( { } )을 붙이고 내용을 채우지 않으면 된다.

Virtual void Update(){}


우리가 사용할 랜더 함수이다.

이 함수가 하는 일은 비트맵을 받아와서 화면에 뿌려주는 일을한다.

m_Resource로 비트맵을 받아와서 m_hMemDC에 뿌려주고, m_hBackBuffer에 복사해준다.

그리고 메인에 WM_PAINT에서 BitBlt을 다시 써서 화면으로 뿌려주면 완료된다.



클래스화된 배경을 사용하려면 메인 함수에 배경 헤더에대한 파일을 #include해주고 배경 클래스 변수를 전역변수로 하나 선언해 준다.




그리고 메세지 루프를 GetMessage에서 PeekMessage로 바꿔줘야 하는데,

깊게는 안들어가고 가볍게 말하자면

GetMessage는 문서용인 반면,

PeekMessage는 게임용이라고 생각하면 된다.




WM_CREATE에서 LoadBitmap으로 불러온 비트맵을

동적할당된 메모리에 Init의 인자로 넘겨준다.

이때 3개의 인자를 넘겨줘야 하는데, 그려질 도화지인 g_hBackBuffer와 그릴 일을 할 g_hMemDC와 그려질 리소스인 g_hBGA를를 넘겨준다. 





프로그램 종료시 사용했던 DC들과 동적 메모리를 해제해 준다.



결과



'API > 이론' 카테고리의 다른 글

시간 경과에 따른 애니메이션  (0) 2016.04.29
캐릭터 출력하기.  (0) 2016.04.28
여러 이미지 출력을 위한 소스정리 및 파일 나누기  (0) 2016.04.26
배경화면 출력하기.  (0) 2016.04.26
더블 버퍼링  (0) 2016.04.25
And
prev | 1 | 2 | 3 | next