Pyxel을 사용한 2D 게임 시작하기 (파트 7): 캐릭터 제어

발행: (2026년 1월 11일 오전 12:00 GMT+9)
9 min read
원문: Dev.to

Source: Dev.to

2D 게임 시작하기 with Pyxel – 파트 7: 캐릭터 제어

이번 파트에서는 플레이어가 직접 캐릭터를 움직일 수 있도록 입력 처리이동 로직을 구현합니다. 앞선 파트에서 만든 기본 화면에 키보드 입력을 연결하고, 캐릭터가 화면 안에서 부드럽게 움직이도록 만들겠습니다.


1. 키 입력 받기

Pyxel은 pyxel.btn()pyxel.btnp() 함수를 제공하여 현재 키가 눌러져 있는지, 혹은 방금 눌렸는지를 확인할 수 있습니다.

함수설명
pyxel.btn(key)지정한 키가 지속적으로 눌러져 있는지 반환
pyxel.btnp(key, hold=0, period=0)지정한 키가 새로 눌렸는지(한 번만) 반환. holdperiod 옵션으로 반복 입력을 제어

키 코드는 pyxel.KEY_LEFT, pyxel.KEY_RIGHT, pyxel.KEY_UP, pyxel.KEY_DOWN 등으로 접근합니다.

if pyxel.btn(pyxel.KEY_LEFT):
    self.x -= self.speed
if pyxel.btn(pyxel.KEY_RIGHT):
    self.x += self.speed
if pyxel.btn(pyxel.KEY_UP):
    self.y -= self.speed
if pyxel.btn(pyxel.KEY_DOWN):
    self.y += self.speed

2. 캐릭터 위치 업데이트

캐릭터의 좌표(x, y)와 이동 속도(speed)를 클래스 변수로 선언하고, update() 메서드 안에서 위의 입력 로직을 실행합니다. 화면 밖으로 나가지 않게 제한을 두는 것이 일반적입니다.

def update(self):
    # 입력 처리
    if pyxel.btn(pyxel.KEY_LEFT):
        self.x = max(0, self.x - self.speed)
    if pyxel.btn(pyxel.KEY_RIGHT):
        self.x = min(pyxel.width - self.w, self.x + self.speed)
    if pyxel.btn(pyxel.KEY_UP):
        self.y = max(0, self.y - self.speed)
    if pyxel.btn(pyxel.KEY_DOWN):
        self.y = min(pyxel.height - self.h, self.y + self.speed)
  • max()min()을 사용해 화면 경계를 벗어나지 않도록 합니다.
  • self.w, self.h는 캐릭터 스프라이트의 가로·세로 크기입니다.

3. 애니메이션 추가 (선택 사항)

키 입력에 따라 스프라이트 인덱스를 바꾸면 간단한 걷는 애니메이션을 구현할 수 있습니다. 보통 self.frame 변수를 0~1 사이에서 토글하면서 두 개의 스프라이트를 교대로 그립니다.

self.frame = (self.frame + 1) % 2   # 0 ↔ 1 토글
pyxel.blt(self.x, self.y, 0, 0 + self.frame * 8, 0, 8, 8, colkey=0)

위 코드는 8×8 크기의 스프라이트 시트에서 첫 번째와 두 번째 프레임을 번갈아 그립니다.


4. 전체 예제

아래는 지금까지 설명한 내용을 모두 합친 최소 실행 가능한 예제입니다. 코드 블록 내부는 그대로 유지하고, 설명 부분만 한국어로 번역했습니다.

import pyxel

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.w = 8
        self.h = 8
        self.speed = 2
        self.frame = 0

    def update(self):
        if pyxel.btn(pyxel.KEY_LEFT):
            self.x = max(0, self.x - self.speed)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.x = min(pyxel.width - self.w, self.x + self.speed)
        if pyxel.btn(pyxel.KEY_UP):
            self.y = max(0, self.y - self.speed)
        if pyxel.btn(pyxel.KEY_DOWN):
            self.y = min(pyxel.height - self.h, self.y + self.speed)

        # 간단한 걷기 애니메이션
        self.frame = (self.frame + 1) % 2

    def draw(self):
        pyxel.blt(self.x, self.y, 0, self.frame * 8, 0, 8, 8, colkey=0)

class App:
    def __init__(self):
        pyxel.init(160, 120, caption="Pyxel Character Control")
        self.player = Player(80, 60)
        pyxel.load("assets.pyxres")   # 스프라이트 시트가 포함된 파일
        pyxel.run(self.update, self.draw)

    def update(self):
        self.player.update()

    def draw(self):
        pyxel.cls(0)
        self.player.draw()

App()

코드 설명

  • Player 클래스는 캐릭터의 위치, 속도, 프레임 정보를 관리합니다.
  • update() 메서드에서 키 입력을 감지하고 좌표를 업데이트합니다.
  • draw() 메서드에서는 현재 프레임에 맞는 스프라이트를 화면에 그립니다.
  • App 클래스는 Pyxel 초기화, 메인 루프 연결, 그리고 전체 화면을 담당합니다.

5. 마무리

  • 입력 처리경계 체크를 통해 기본적인 캐릭터 이동을 구현했습니다.
  • 필요에 따라 점프, 공격, 다중 키 입력 등 복합적인 동작을 추가할 수 있습니다.
  • 다음 파트에서는 맵 로딩충돌 처리를 다루어 보다 완성도 높은 2D 게임을 만들 예정입니다.

Tip: pyxel.btnp() 를 사용하면 키를 한 번만 인식하도록 할 수 있어, 점프와 같은 동작에 유용합니다.

이제 캐릭터를 자유롭게 움직일 수 있으니, 여러분만의 게임 로직을 추가해 보세요! 🚀

캐릭터 제어

이 장에서는 Space 키가 눌렸을 때를 감지하고 플레이어의 이동 방향을 좌 ↔ 우로 전환합니다. 이를 통해 보다 강한 직접 제어 감각을 제공합니다.

초기 이동 방향 설정

Game 생성자에서 함선의 초기 방향을 무작위로 선택합니다 (오른쪽 = 0° 또는 왼쪽 = 180°) 그리고 속도를 설정합니다.

# main.py – inside Game.__init__()
import random

# Randomly choose left or right
deg = 0 if random.random() < 0.5 else 180
self.ship.move(SHIP_SPD, deg)

Flip X 메서드

BaseSprite에 x‑축 속도를 반전시키는 flip_x() 메서드를 추가합니다.

# sprite.py – added to BaseSprite class
def flip_x(self):
    """Flip movement in the x direction"""
    self.vx *= -1

flip_x()를 호출하면 방향이 바뀝니다:

  • 오른쪽 → 왼쪽
  • 왼쪽 → 오른쪽

키보드 입력 처리

Game 클래스에 control_ship() 메서드를 만듭니다. 이 메서드는 pyxel.btnp()를 사용해 Space 키가 정확히 눌린 순간을 감지하고 함선의 방향을 전환합니다.

# main.py – added to Game class
def control_ship(self):
    """Handle input"""
    if pyxel.btnp(pyxel.KEY_SPACE):
        self.ship.flip_x()  # Reverse movement

Space 키를 누를 때마다 함선의 수평 이동이 토글됩니다.

화면 경계 래핑 로직

함선이 화면을 벗어나면 반대쪽으로 이동시킵니다. 재사용 가능한 overlap_spr() 메서드는 모든 스프라이트(예: 향후 추가될 소행성)에도 사용할 수 있습니다.

# main.py – added to Game class
def overlap_spr(self, spr):
    """Wrap sprite around screen edges"""
    if spr.x < -spr.w:
        spr.x = W
        return
    if W < spr.x:
        spr.x = -spr.w
        return
    if spr.y < -spr.h:
        spr.y = H
        return
    if H < spr.y:
        spr.y = -spr.h
        return

전체 코드

아래는 위에서 설명한 기능들의 전체 구현입니다.

# sprite.py
import pyxel
import math
import random

class BaseSprite:
    def __init__(self, x, y, w=8, h=8):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.vx = 0
        self.vy = 0

    def update(self):
        self.x += self.vx
        self.y += self.vy

    def draw(self):
        pass  # Implemented in subclasses

    def move(self, spd, deg):
        rad = deg * math.pi / 180
        self.vx = spd * math.cos(rad)
        self.vy = spd * math.sin(rad)

    def flip_x(self):
        """Flip movement in the x direction"""
        self.vx *= -1

class ShipSprite(BaseSprite):
    def __init__(self, x, y):
        super().__init__(x, y)

    def draw(self):
        pyxel.blt(self.x, self.y, 0, 0, 0, self.w, self.h, 0)
# main.py
import pyxel
import random
import sprite

W, H = 160, 120
SHIP_SPD = 1.4  # Player speed

class Game:
    def __init__(self):
        self.score = 0
        self.ship = sprite.ShipSprite(W / 2, H - 40)

        # Random initial direction
        deg = 0 if random.random() < 0.5 else 180
        self.ship.move(SHIP_SPD, deg)

        pyxel.init(W, H, title="Hello, Pyxel!!")
        pyxel.load("shooter.pyxres")
        pyxel.run(self.update, self.draw)

    def update(self):
        self.ship.update()
        self.control_ship()
        self.overlap_spr(self.ship)

    def draw(self):
        pyxel.cls(0)
        pyxel.text(10, 10, f"SCORE:{self.score:04}", 12)
        self.ship.draw()

    def control_ship(self):
        if pyxel.btnp(pyxel.KEY_SPACE):
            self.ship.flip_x()  # Reverse movement

    def overlap_spr(self, spr):
        if spr.x < -spr.w:
            spr.x = W
            return
        if W < spr.x:
            spr.x = -spr.w
            return
        if spr.y < -spr.h:
            spr.y = H
            return
        if H < spr.y:
            spr.y = -spr.h
            return

def main():
    Game()

if __name__ == "__main__":
    main()

게임을 실행하면 함선이 수평으로 이동하는 것을 볼 수 있습니다; Space 키를 누르면 방향이 바뀌고, 화면 가장자리를 넘어가면 반대쪽으로 이동합니다.

*In the ne

다음 장에서는 “Let’s Spawn Asteroids.”*

Back to Blog

관련 글

더 보기 »