개발/Graphics

SDL Sprite Animation

huiyu 2018. 8. 19. 12:51

스프라이트 애니메이션 :
게임 개체의 동작을 표현할 때 사용하는 방법, 애니메이션과 마찬가지로 움직이는 그림을 순서대로 빠른 시간 안에 이어주면 눈의 착시로 연속된 동작으로 보이게 된다. 때문에 필요한 동작 대로 그 움직이는 각 단위의 그림이 모두 필요하다. 이그림을 모두 그려준 다음, 그림의 바탕색만 빼주면 캐릭터가 배경 위에 올라온 것처럼 보이게 된다.

보통 아래 그림과 같이 연속된 동작이 일정한 크기로 구성되어져 있다.
각 동작별로 연속으로 그려주게 되면 애니메이션이 된다!


여기서는 SDL로 스프라이트 애니메이션을 그리는 법을 구현해본다.
우선 SDL을 통해 비트맵파일을 로드한다.

1
2
3
4
5
6
7
8
9
10
typedef struct AppData {
  SDL_Window* window;
  SDL_Surface* window_surface;
  SDL_Surface* player_surface;
} AppData;
 
 
AppData ad;
ad.player_surface = SDL_LoadBMP("./test.bmp");
SDL_SetColorKey(ad.player_surface, SDL_TRUE, SDL_MapRGB(ad.player_surface->format, 2550255));
cs

SDL_LoadBMP()는 SDL에서 비트맵을 로드하는 API로 이미지를 불러온 뒤 SDL_Surface형태로 반환한다.

기본적으로 비트맵은 투명 배경을 지원하지 않아,
위 이미지에서 보는 배경과 같이 보라색이나 특정한 색으로 설정하는 경우가 많다.

이럴 경우엔 직접 코드상으로 처리가 필요하다.
SDL_SetColorKey(ad.player_surface, 1, SDL_MapRGB(ad.player_surface->format, 255, 0, 255));

SDL에선 SDL_SetColorKey() API를 통해 비트맵 이미지 배경을 투명으로 처리할 수 있다.

1
2
3
int SDL_SetColorKey(SDL_Surface* surface,
                    int          flag,
                    Uint32       key)
cs

설정을 원하는 surface를 자신이 설정한 key의 색을 투명으로 설정한다. 위 예제에서는 배경색(255,0,255)를 투명으로 설정한다.

  

이상태로 이미지를 그려보면 보라색 배경이 투명으로 사라진 걸 볼 수 있다.

캐릭터 애니메이션을 그리기 위해선 위와같이 불러온 서피스 이미지를 프레임마다 한동작씩 잘라서 그려주면 된다.
전체의 이미지에서 특정 크기의 이미지 부분만 화면에 그리기 위해선 SDL_BlitSurface() API를 활용한다.

'Blit'이란 그래픽스에서 한 이미지에서 다른 이미지로 복사하는 것을 뜻한다. 공식적인 정의는 데이터 배열을 목적지 배열에 복사하는 것을 의미한다.
로드한 비트맵 서피스를 윈도우 서피스로 'blit'해주면 화면에 출력되는 윈도우에 그려지는데, 이 때 특정 사이즈만 blit을 하면 잘라진 이미지가 그려지게 된다.

SDL_BlitSurface()는 단순하다. src(surface)->dst(surface)로 복사를 하는데,
srcrect크기만큼 dstRect위치에 그려준다.
1
2
3
4
int SDL_BlitSurface(SDL_Surface*    src,
                    const SDL_Rect* srcrect,
                    SDL_Surface*    dst,
                    SDL_Rect*       dstrect)
cs


우선 아래와 같이 rcRect를 전체 이미지 사이즈로 해서 전체 이미지를 올려본다.(위 이미지와 같이)
srcrect를 NULL로 하면 전체 사이즈를, dstrect를 NULL로 하면 0,0에 위치하게 된다.

1
2
3
4
ad.window_surface = SDL_GetWindowSurface(ad.window);
 
SDL_BlitSurface(ad.player_surface, NULL, ad.window_surface, NULL);
 
cs

이제 srcrect값을 캐릭터 하나의 크기(50x50)에 맞춰서 설정을 해서 인자값을 넘겨주자.

1
2
SDL_Rect rcSprite = {005050};
SDL_BlitSurface(ad.player_surface, &rcSprite, ad.window_surface, NULL);
cs


잘라진 이미지가 올라간 것을 확인할 수 있다.
예제에서 rcSprite(SDL_Rect)의 x,y,w,h의 값을 각각 0,0,50,50으로 설정했는데
w,h는 올릴 이미지의 사이즈가 되고, x,y는 내가 올릴 이미지의 좌표라고 할 수 있다.

즉, 애니메이션을 설정하기 위해선 매 프레임마다 이 x좌표값을 변경해주면 된다.

매프레임 그릴때 x좌표를 변경해주기 위한 코드를 넣어보자.

우선 캐릭터의 매프레임마다 그릴 이미지를 선택하기 위한 player_idx를 선언한다.
이 값을 통해 이미지의 x좌표를 계산할 것이다.

1
int player_idx = 0;
cs

다음으로 매프레임 그리는 곳에 애니메이션을 위한 x값을 계산해준다.
idx값은 캐릭터 애니메이션의 갯수인 5까지 반복하며, 5가 되면 0으로 다시 처음으로 돌아간다.
그리고 이 idx값을 캐릭터의 크기인 50만큼 곱해주기만 x좌표가 구해진다(0->50->100->150->200)

1
2
3
4
player_idx ++;
if(player_idx  >= 5)
    player_idx  = 0;
rcSprite.x = 50 * player_idx;
cs

SDL_BlitSurface()에 계산한 rcSprite값을 넘겨주면 애니메이션을 하게 된다.


준비한 비트맵의 경우 한방향으로만 달리고 있는게 아닌 상/하/좌/우 모두 움직이고 있다. 이에 맞게 방향키를 눌렀을 때 원하는 방향의 애니메이션을 설정해줘보자.

구현은 애니메이션을 그리는 방법과 같다. 각 방향키에 해당하는 입력이 왔을 때 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
25
26
27
28
29
30
31
32
33
34
int player_state = 0;//y값 변경을 위한 값 선언
 
 
////////////main loop///////////////////
SDL_Event event;
if(SDL_PollEvent(&event)) {
    switch(event.type)
    {
        case SDL_QUIT:
            isQuit = SDL_TRUE;
        break;
        case SDL_KEYUP:
             switch(event.key.keysym.scancode)
             {
                 case SDL_SCANCODE_LEFT:
                     player_state = 0;
                 break;
                 case SDL_SCANCODE_RIGHT:
                     player_state = 1;
                 break;
                 case SDL_SCANCODE_UP:
                     player_state = 2;
                 break;
                 case SDL_SCANCODE_DOWN:
                     player_state = 3;
                 break;
             }
        break;
        }
    }
}
 
rcSprite.y = 50 * player_state;
 
cs

SDL_PollEvent()를 통해 키보드 입력을 위한 이벤트를 받고 각 방향에 해당하는 이벤트가 입력으로 들어왔을 경우(SDL_SCANCODE_LEFT, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UP, SDL_SCANCODE_DOWN), y값 변경을 위한 'player_state'값을 변경해준다.


이후 키보드 입력을 통해 방향별로 애니메이션을 하는 것을 확인 할 수 있다.

전체 코드는 아래에서 확인할 수 있다.

https://github.com/huiyueun/GraphicsStudy/tree/master/sprite_sample


728x90
반응형

'개발 > Graphics' 카테고리의 다른 글

Premultiplied alpha  (0) 2018.10.30
텍스쳐 맵  (2) 2018.09.15
프레임 드롭현상과 대책  (3) 2018.08.18
프레임과 FPS  (0) 2018.08.04
OpenGL Texture 그리기  (0) 2018.08.04