스프라이트
고친 사람 github-actions[bot]
스프라이트는 게임 화면에 캐릭터나 총알 같은 물체 하나를 그려 넣는 평면 이미지입니다. 그릴 때마다 위치를 조금씩 옮기면 화면 위에서 물체가 움직입니다. 그림을 바꿔 끼우면 걷거나 뛰는 동작이 됩니다. 웹에서도 아이콘을 다룰 때 이 이름을 빌려 씁니다. 이 항목은 게임 쪽 뜻을 다룹니다.
쉽고 빠른 이해
스프라이트는 화면 위를 움직이는 그림 한 장입니다. 옆으로 달리는 게임에서 주인공 캐릭터, 날아가는 총알, 바닥에 떨어진 동전이 하나하나 스프라이트입니다.
이렇게 나눠 두면 화면을 물체 단위로 다룰 수 있습니다. 화면 전체를 한 장의 그림으로 다루면 캐릭터가 한 칸 움직일 때마다 그 그림을 고쳐 그려야 합니다. 물체마다 그림을 따로 두면 그 물체의 위치만 바꾸면 됩니다.
어떻게 도나:
- 배경을 먼저 그립니다
- 스프라이트마다 지금 위치에 그림을 올립니다. 뒤에 있을 것부터 그립니다
- 다음 화면에서는 위치나 그림을 바꿔 1번부터 다시 그립니다
대가도 있습니다. 그림이 평면이라 정해진 방향에서 본 모습만 보여 줄 수 있습니다. 동작마다 그림을 여러 장 그려 두어야 해서 그림 수가 빠르게 늘어납니다. 크게 키우면 그림이 흐려지거나 계단처럼 깨집니다.
상세
이 절은 스프라이트 한 장이 무엇을 들고 있는지에서 출발합니다. 그다음 투명한 바탕, 겹쳐 그리는 순서, 움직임과 애니메이션, 부딪힘 판정을 차례로 봅니다. 이 앞 절반에서는 주인공이 옆으로 달리며 동전을 줍는 게임 하나를 예로 씁니다.
뒤 절반은 그래픽 카드가 스프라이트를 그리는 방법, 3D 게임 속 스프라이트, 이름이 생긴 배경, 웹에서 같은 이름을 쓰는 기법을 봅니다. 끝으로 스프라이트가 맞는 경우와 맞지 않는 경우를 가릅니다.
종이 인형극을 떠올리면 됩니다. 무대 뒤에 배경 그림을 걸어 둡니다. 그 앞에 오려 낸 종이 인형을 세우고 손으로 옮깁니다. 표정을 바꾸고 싶으면 다른 표정의 인형으로 바꿔 끼웁니다. 스프라이트가 이 종이 인형입니다.
그림 한 장과 위치
화면은 아주 작은 점들이 바둑판처럼 늘어선 것입니다. 이 점 하나가 픽셀입니다. 스프라이트의 그림도 픽셀을 가로세로로 늘어놓은 작은 이미지입니다. 동전 그림이라면 가로 16픽셀, 세로 16픽셀짜리 이미지 한 장인 식입니다.
그림만으로는 화면 어디에 그릴지 모릅니다. 스프라이트는 그림과 함께 위치도 들고 있습니다. 위치는 화면 왼쪽 위 같은 기준점에서 가로로 몇 픽셀, 세로로 몇 픽셀 떨어졌는지로 적습니다. 이렇게 두 수로 위치를 적는 방법을 좌표라고 부릅니다.
스프라이트 하나가 들고 있는 값은 대개 아래와 같습니다.
| 값 | 무엇을 정하나 |
|---|---|
| 그림 | 어떤 이미지를 보여 줄지 |
| 위치 | 화면 어디에 그릴지 |
| 크기와 회전 | 그림을 얼마나 키우고 얼마나 돌릴지 |
| 그리는 순서 | 다른 스프라이트보다 앞에 보일지 뒤에 보일지 |
| 뒤집기 | 좌우를 바꿔 반대쪽을 보게 할지 |
뒤집기가 있으면 오른쪽을 보는 그림 한 장으로 왼쪽을 보는 모습까지 냅니다. 그림 수를 절반으로 줄이는 흔한 방법입니다.
투명한 바탕
이미지는 언제나 네모입니다. 그런데 동전은 동그랗고 캐릭터는 사람 모양입니다. 네모를 그대로 그리면 캐릭터 둘레에 배경을 가리는 사각형이 보입니다.
그래서 스프라이트 그림의 픽셀은 색과 함께 투명한 정도를 갖습니다. 이 투명도 값을 알파라고 부릅니다. 캐릭터 바깥의 픽셀은 알파를 0으로 두어 아예 안 보이게 합니다. 그러면 네모 이미지에서 캐릭터 모양만 화면에 남습니다.
알파는 흔히 0에서 255까지의 값입니다(0에서 1 사이 소수로 적기도 합니다). 가장 큰 값인 255로 두면 뒤를 다 가립니다. 그 사이 값이면 반쯤 비쳐 보입니다. 그림자나 유리, 연기처럼 뒤가 비치는 물체를 이렇게 그립니다.
반쯤 비치는 픽셀은 그릴 색과 이미 화면에 있던 색을 알파만큼 섞어 칠합니다. 이 섞기를 알파 블렌딩이라 합니다. 알파가 128이면 두 색이 거의 반반 섞입니다.
겹쳐 그리는 순서
화면에는 스프라이트가 여러 장 겹쳐 있습니다. 나중에 그린 것이 먼저 그린 것을 덮습니다. 그래서 그리는 순서가 곧 앞뒤 관계가 됩니다.
뒤에 있을 것부터 그리고 앞에 있을 것을 나중에 그립니다. 먼 산 그림, 가까운 나무, 캐릭터 순으로 그리면 캐릭터가 나무 앞에 섭니다. 화가가 먼 배경부터 칠하고 가까운 것을 위에 덧칠하는 방식과 같아서 화가 알고리즘이라고 부릅니다.
순서를 스프라이트마다 하나하나 정하면 관리가 어렵습니다. 그래서 게임 엔진은 보통 레이어를 나눕니다. 게임 엔진은 그리기·입력·소리처럼 어느 게임에나 필요한 기능을 묶어 둔 기반 프로그램입니다.
배경 레이어, 물체 레이어, 캐릭터 레이어, 화면 위 글자 레이어를 둡니다. 앞뒤는 레이어 단위로 정합니다. 캐릭터 레이어에 놓인 것은 언제나 배경 레이어보다 앞에 보입니다. 이렇게 나눈 레이어를 정렬 레이어라고 부릅니다.
움직임과 애니메이션
게임은 화면 한 장을 그린 뒤 조금 바꿔 다시 그립니다. 이 일을 1초에 수십 번 되풀이합니다. 이렇게 그려 내는 화면 한 장을 프레임이라 합니다.
이 되풀이를 도는 반복문이 게임 루프입니다. 한 바퀴를 돌 때마다 프레임이 한 장 나옵니다. 아래 흐름도가 그 한 바퀴입니다.
flowchart TD
A["입력을 읽는다"] --> B["스프라이트 위치를 옮긴다"]
B --> C["다음 동작 그림으로 바꿔 끼운다"]
C --> D["배경을 그린다"]
D --> E["스프라이트를 뒤에서 앞 순서로 그린다"]
E --> F["완성된 화면을 보여 준다"]
F --> A
흐름도는 프레임 한 장을 만드는 순서입니다. 마지막 단계가 끝나면 다음 프레임을 위해 처음으로 돌아갑니다. 스프라이트가 움직이는 것도, 동작이 바뀌는 것도 이 고리 안에서 일어납니다. 둘은 아래에서 차례로 봅니다.
움직임은 위치를 바꿔서 냅니다. 프레임마다 캐릭터의 가로 좌표를 2픽셀씩 늘리면 캐릭터가 오른쪽으로 걸어가는 것처럼 보입니다.
물체마다 그림을 따로 두는 까닭이 이 대목에서 드러납니다. 화면 전체가 그림 한 장이라면 캐릭터가 2픽셀 움직일 때마다 그 큰 그림을 고쳐 그려야 합니다. 스프라이트로 나눠 두면 배경 그림은 손대지 않습니다. 바뀌는 것은 캐릭터 스프라이트의 위치 값 하나입니다.
동작은 그림을 바꿔서 냅니다. 다리를 앞으로 뻗은 그림, 모은 그림, 뒤로 뻗은 그림을 차례로 바꿔 보여 주면 걷는 모습이 됩니다. 이렇게 그림을 바꿔 끼워 동작을 만드는 일을 스프라이트 애니메이션이라고 부릅니다.
동작에 쓰는 그림 여러 장은 흔히 이미지 한 장에 모아 둡니다. 걷기 그림 세 장을 가로로 나란히 붙인 이미지 한 장인 식입니다. 그 묶음이 스프라이트 시트입니다. 게임은 시트에서 지금 보여 줄 칸만 골라 그립니다.
부딪힘 판정
캐릭터가 동전에 닿았는지는 게임이 직접 셈해야 합니다. 화면에 겹쳐 보인다고 게임이 저절로 알지는 못합니다.
가장 흔한 방법은 스프라이트마다 둘레를 감싸는 네모를 하나 두는 것입니다. 이 네모가 경계 상자입니다. 두 네모가 겹치면 닿은 것으로 칩니다. 돌리지 않은 네모끼리는 가로 범위와 세로 범위가 둘 다 겹치는지만 보면 됩니다.
아래 코드는 위치와 크기로 네모를 만들고 겹침을 봅니다. 주인공은 동전과 겹치고 벽과는 떨어져 있습니다.
from collections import namedtuple
Box = namedtuple("Box", "x y w h")
def hit(a, b):
return (a.x < b.x + b.w and b.x < a.x + a.w and
a.y < b.y + b.h and b.y < a.y + a.h)
player = Box(10, 10, 32, 32)
coin = Box(30, 20, 16, 16)
wall = Box(80, 10, 32, 32)
hit(player, coin) # True
hit(player, wall) # False
주인공의 가로 범위는 10에서 42입니다. 동전은 30에서 46이라 둘이 겹칩니다. 벽은 80에서 시작하므로 주인공과 가로 범위가 안 겹칩니다. 네모는 캐릭터 모양보다 크므로 투명한 귀퉁이끼리 닿아도 부딪힌 것으로 셉니다. 그래서 게임은 네모를 그림보다 조금 작게 잡곤 합니다.
그래픽 카드가 스프라이트를 그리는 방법
요즘 컴퓨터에서 화면을 그리는 일은 GPU(Graphics Processing Unit, 그래픽 처리 장치)가 맡습니다. GPU 는 같은 계산을 동시에 아주 많이 돌리는 칩입니다. 흔히 그래픽 카드라고 부르는 부품에 들어 있습니다.
GPU 는 기본으로 삼각형을 그립니다. 그래서 스프라이트 하나는 삼각형 두 개를 붙인 네모로 그려집니다. 이 네모를 쿼드라 합니다.
그 네모 위에 스프라이트 그림을 붙입니다. 그림은 먼저 GPU 가 바로 읽을 수 있는 메모리로 옮겨 둡니다. 이렇게 GPU 에 올려 둔 이미지를 텍스처라고 부릅니다.
네모의 네 귀퉁이마다 텍스처 위의 한 점을 짝지어 둡니다. 네모의 왼쪽 위 귀퉁이에는 그림의 왼쪽 위 귀퉁이를, 오른쪽 아래 귀퉁이에는 그림의 오른쪽 아래 귀퉁이를 짝짓는 식입니다. 이 짝을 적는 값을 텍스처 좌표라 합니다. GPU 는 네모를 칠할 때 안쪽 점마다 텍스처의 맞는 위치에서 색을 읽어 옵니다.
GPU 에 「이것을 그려라」 하고 내리는 명령 한 번이 드로 콜입니다. 드로 콜은 내기 전에 준비할 것이 많아 한 번마다 비용이 붙습니다. 스프라이트 수백 개를 하나씩 따로 그리면 드로 콜도 수백 번이 됩니다.
같은 텍스처를 쓰는 스프라이트들은 드로 콜 한 번에 묶어 그릴 수 있습니다. 이 묶어 그리기를 배칭이라고 부릅니다.
스프라이트 시트 한 장은 GPU 에 올라가면 텍스처 한 장이 됩니다. 스프라이트마다 텍스처 좌표로 시트 안의 다른 칸을 짚으면 그림은 달라도 텍스처는 하나입니다. 그래서 시트를 같이 쓰는 스프라이트들은 한 드로 콜로 묶입니다. 스프라이트 그림들을 시트 한 장에 모으는 까닭이 여기에 있습니다.
3D 게임 속 스프라이트
3D(3차원) 게임에도 스프라이트가 나옵니다. 3D 공간 안에 평면 그림 한 장을 세워 둡니다. 그리고 카메라가 어디로 돌든 그림이 늘 카메라 쪽을 보게 돌립니다. 이런 스프라이트를 빌보드라고 부릅니다.
빌보드는 연기, 불꽃, 먼 곳의 나무처럼 입체로 만들 만큼 중요하지 않은 것에 씁니다. 평면이라 그리는 비용이 적습니다. 대신 가까이서 돌아보면 평면이라는 것이 드러납니다.
빌보드를 가장 많이 쓰는 곳은 파티클 시스템입니다. 불꽃 하나를 작은 그림 수백 장으로 흩뿌려 그리는 방식입니다.
화면 위에 겹쳐 보이는 체력 막대나 버튼도 평면 그림입니다. 이런 화면 요소를 UI(User Interface, 사용자 인터페이스)라 합니다. 많은 게임 엔진이 UI 그림도 스프라이트로 다룹니다.
이름이 생긴 배경
스프라이트는 원래 옛 가정용 컴퓨터와 게임기에 있던 그래픽 칩 기능의 이름이었습니다. 그때는 메모리가 작고 처리 속도가 느렸습니다. 매 프레임 화면 전체를 다시 그리기가 버거웠습니다.
그래서 그래픽 칩이 배경 그림과 별개로 작은 그림 몇 장을 화면 위에 겹쳐 내보냈습니다. 배경은 손대지 않았습니다. 그 작은 그림의 위치만 바꾸면 물체가 움직였습니다. 배경 위를 떠다니는 모습에서 요정을 뜻하는 sprite 라는 이름이 붙었습니다. 지금은 그런 전용 회로 없이 GPU 가 다 그립니다. 그래도 이름은 남았습니다.
웹의 CSS 스프라이트
웹에도 이 이름을 쓰는 기법이 있습니다. 웹 페이지의 모양은 CSS(Cascading Style Sheets, 캐스케이딩 스타일 시트)라는 언어로 정합니다.
아이콘 여러 개를 이미지 파일 하나에 모아 둡니다. 그리고 CSS 로 그 파일의 한 부분만 잘라 보여 줍니다. 이 방법을 CSS 스프라이트라고 부릅니다.
이쪽은 화면 위를 움직이는 물체가 아니라 이미지를 모아 두는 방법을 가리킵니다. 게임의 스프라이트 시트와 같은 생각입니다. 아이콘마다 서버에 따로 요청하지 않으려고 씁니다.
쓸 때와 안 쓸 때
스프라이트는 2D(2차원) 게임의 기본 단위입니다. 횡스크롤 게임, 위에서 내려다보는 게임, 퍼즐 게임은 화면의 물체 대부분을 스프라이트로 그립니다. 점 하나하나를 손으로 찍어 그린 픽셀 아트 게임도 스프라이트로 만듭니다.
여러 방향에서 봐야 하는 물체에는 맞지 않습니다. 캐릭터가 360도로 도는 3D 게임에서 스프라이트를 쓰려면 방향마다 그림을 따로 그려야 합니다. 그럴 때는 점과 면으로 입체를 만든 메시를 씁니다.
크기를 자유롭게 바꿔야 하는 그림에도 불리합니다. 스프라이트 그림은 픽셀 수가 정해져 있습니다. 크게 키우면 흐려지거나 계단처럼 깨집니다. 여러 크기가 필요하면 크기별 그림을 따로 두거나, 선과 면을 수식으로 적는 벡터 그림을 씁니다.
동작이 많은 캐릭터도 짐이 됩니다. 걷기, 뛰기, 공격마다 그림 여러 장이 필요해 그림 수와 메모리가 빠르게 늘어납니다. 이럴 때는 그림을 부위별로 나눠 뼈대에 붙이고 뼈대를 움직이는 스켈레탈 애니메이션을 대신 쓰기도 합니다.
관련 항목
스프라이트가 쓰이는 그래픽스 분야
게임 개발 · 컴퓨터 그래픽스 · 2D 그래픽스 · 래스터 그래픽스 · 픽셀 아트 · 게임 엔진
스프라이트 그림을 이루는 구성 요소
픽셀 · 이미지 · 알파 채널 · 텍스처 · 텍셀 · 좌표 · 피벗
스프라이트 그림을 모아 두는 묶음
스프라이트 시트 · 스프라이트 아틀라스 · 텍스처 아틀라스 · CSS 스프라이트 · 타일맵
스프라이트를 겹쳐 그리는 처리 단계
게임 루프 · 프레임 · 화가 알고리즘 · 정렬 레이어 · 알파 블렌딩 · 프레임버퍼 · 더블 버퍼링
GPU 가 스프라이트를 그리는 데 쓰는 수단
GPU · 쿼드 · 텍스처 좌표 · 드로 콜 · 드로 콜 배칭 · 셰이더 · 텍스처 필터링
스프라이트를 움직이는 애니메이션 기법
스프라이트 애니메이션 · 프레임 애니메이션 · 스켈레탈 애니메이션 · 트윈 · 키프레임
스프라이트끼리 닿았는지 가리는 판정
충돌 판정 · 경계 상자 · AABB · 히트박스 · 물리 엔진
스프라이트를 3D 공간과 화면 위에 쓰는 기법
빌보드 · 파티클 시스템 · UI · HUD · 임포스터
스프라이트를 대신할 수 있는 다른 그림 수단
메시 · 벡터 그래픽스 · 3D 모델 · 복셀
다른 이름: sprite · 2D 스프라이트