언어 기초

Ren'Py 언어를 설명하기 전에 먼저 스크립트의 구조를 살펴보겠습니다. 파일이 여러 줄로 이루어진 블록으로 나뉘는 방식과, 각 줄이 문을 구성하는 요소로 나뉘는 방식을 설명합니다.

파일

Ren'Py 게임의 스크립트는 game/ 디렉터리 아래에 있는 .rpy 확장자의 모든 파일로 구성됩니다. Ren'Py는 이 파일들을 모두 읽어 그 내용을 게임 스크립트로 사용합니다.

일반적으로 스크립트를 하나의 큰 파일에 쓰든 여러 파일로 나누어 쓰든 동작에는 차이가 없습니다. 다른 파일의 레이블로 점프하거나 그 레이블을 호출해 파일 간에도 실행 위치를 옮길 수 있습니다. 따라서 파일을 어떻게 나눌지는 제작자의 취향에 달려 있습니다. 이벤트나 날짜별로 작은 파일을 만드는 제작자도 있고, 하나의 큰 스크립트를 선호하는 제작자도 있습니다.

Ren'Py는 로딩 시간을 줄이기 위해 시작 시 .rpy 파일을 .rpyc 파일로 컴파일합니다. .rpy 파일을 수정하면 다음 실행 때 .rpyc 파일도 갱신됩니다. 다만 대응하는 .rpy 파일 없이 .rpyc 파일만 있으면 그 .rpyc 파일을 그대로 사용합니다. 따라서 .rpy 파일을 삭제하거나 이름을 바꾸거나 다른 위치로 옮길 때 .rpyc 파일을 함께 삭제하지 않으면 문제가 생길 수 있습니다. 이전 스크립트가 계속 실행되기 때문입니다.

파일 이름은 문자나 숫자로 시작해야 합니다. 다만 "00"으로 시작하는 이름은 Ren'Py가 내부 용도로 사용하므로 사용할 수 없습니다.

기본 디렉터리

기본 디렉터리는 게임과 함께 배포할 파일이 모두 들어 있는 디렉터리입니다. 단, 실제로 그 안의 파일을 전부 배포하는 것은 아닙니다. 배포 파일 만들기도 참고하세요. README 같은 파일은 기본 디렉터리에 넣습니다.

새 게임을 만들면 런처에서 설정한 프로젝트 디렉터리(Projects Directory) 안에 기본 디렉터리가 생성됩니다. 예를 들어 프로젝트 디렉터리가 renpygames이고 게임 이름이 "HelloWorld"라면 기본 디렉터리는 renpygames/HelloWorld입니다.

게임 디렉터리

게임 디렉터리는 기본 디렉터리 안의 "game" 폴더입니다. 기본 디렉터리가 renpygames/HelloWorld라면 게임 디렉터리는 renpygames/HelloWorld/game입니다.

게임 디렉터리에는 게임에서 사용하는 모든 파일이 들어갑니다. Ren'Py는 하위 디렉터리까지 포함해 .rpy 파일과 .rpyc 파일을 찾고, 그 내용을 합쳐 게임 스크립트를 구성합니다. .rpa 압축 파일도 찾아 자동으로 사용합니다. 또한 Ren'Py에 파일 경로를 지정할 때는 극히 일부 예외를 제외하고 게임 디렉터리를 기준으로 해석합니다. 다만 config.searchpath를 설정하면 이 동작을 바꿀 수 있습니다.

주석

Ren'Py 스크립트에는 주석을 작성할 수 있습니다. 주석은 해시 기호(#)로 시작해 해당 줄 끝까지 이어집니다. 다만 문자열 안의 해시 기호는 주석을 시작하지 않습니다.

# This is a comment.
show black # this is also a comment.

"# 문자열의 일부이므로 주석이 아닙니다."

Ren'Py는 주석을 무시하고, 주석이 없는 것처럼 스크립트를 처리합니다.

논리적 줄

스크립트 파일은 논리적 줄로 나뉩니다. 논리적 줄은 항상 파일의 어느 줄 맨 앞에서 시작하며, 보통 그 줄의 끝에서 끝납니다. 다만 다음 경우에는 다음 줄까지 이어집니다.

  • 줄의 마지막 문자가 역슬래시(\)인 경우.

  • 여는 괄호((, {, [)에 대응하는 닫는 괄호(각각 ), }, ])가 아직 나오지 않은 경우.

  • 문자열이 끝나기 전에 줄바꿈이 나오는 경우. Python과 달리 작은따옴표 문자열을 포함한 모든 문자열에 적용됩니다.

논리적 줄이 끝나면 다음 물리적 줄의 맨 앞에서 새로운 논리적 줄이 시작됩니다.

Ren'Py 언어의 문은 대부분 하나의 논리적 줄로 이루어집니다.

"이것은 하나의 논리적 줄입니다"

"이 줄에는 문자열이 있으므로 줄이 끝나도
 계속 이어집니다."

$ a = [ "괄호가 있으므로 이 줄도",
        "여러 줄에 걸쳐 이어집니다." ]

빈 줄은 무시되며 논리적 줄로 세지 않습니다.

들여쓰기와 블록

들여쓰기는 각 논리적 줄의 앞에 공백을 넣어 Ren'Py 문의 시작 위치를 맞추는 것을 뜻합니다. Ren'Py에서는 들여쓰기에 공백만 사용할 수 있습니다.

들여쓰기는 여러 문을 블록으로 묶는 데 사용합니다. 블록은 여러 줄, 대개는 여러 문으로 이루어진 묶음입니다. 파일을 블록으로 나누는 규칙은 다음과 같습니다.

  • 파일이 시작되는 지점에서 블록 하나가 시작됩니다.

  • 어떤 논리적 줄을 앞선 논리적 줄보다 더 깊게 들여쓰면 새 블록이 시작됩니다.

  • 한 블록 안의 모든 논리적 줄은 들여쓰기 깊이가 같아야 합니다.

  • 비어 있지 않은 논리적 줄의 들여쓰기가 현재 블록보다 얕아지면 그 블록이 끝납니다.

Python과 마찬가지로 Ren'Py에서도 들여쓰기는 매우 중요합니다. 잘못 들여쓰면 구문 오류나 논리 오류가 생길 수 있습니다. 한편 별도의 구분자로 블록을 표시하는 다른 언어에 비해 들여쓰기만으로 구조를 드러내는 방식은 훨씬 간단합니다.

"이 문과 뒤에 오는 if 문은 같은 블록에 속합니다."

if True:

    "하지만 이 문은 새 블록에 속합니다."

    "이 문도 그 새 블록에 속합니다."

"이 문은 다시 첫 번째 블록에 속합니다."

문의 구성 요소

Ren'Py 문은 몇 가지 기본 요소로 구성됩니다.

키워드

키워드는 게임 스크립트에 정해진 철자 그대로 써야 하는 단어입니다. 주로 문이나 속성의 시작을 표시합니다.

이름

이름은 문자나 밑줄로 시작하며, 뒤에 문자·숫자·밑줄을 이어 쓸 수 있습니다. 여기서는 U+00a0부터 U+fffd까지의 유니코드 문자를 문자로 간주합니다.

경고

밑줄 하나(_)로 시작하는 이름은 별도로 명시된 경우를 제외하고 Ren'Py 내부 용도로 예약되어 있습니다.

밑줄 두 개(__)로 시작하지만 밑줄 두 개로 끝나지는 않는 이름은 해당 파일에 고유한 이름으로 변환됩니다.

이미지 이름

이미지 이름은 공백으로 구분된 하나 이상의 구성 요소로 이루어집니다. 첫 구성 요소는 이미지 태그이고, 두 번째 이후의 구성 요소는 이미지 속성입니다. 각 구성 요소에는 문자, 숫자, 밑줄을 사용할 수 있습니다.

예를 들어 이미지 이름이 mary beach night happy라면 이미지 태그는 mary이고 이미지 속성은 beach, night, happy입니다.

at, as, behind, onlayer, with, zorder는 이미지 이름의 구성 요소로 사용할 수 없습니다.

문자열

문자열은 따옴표 문자(", ', ` 중 하나)로 시작하고, 텍스트를 넣은 뒤 같은 따옴표 문자로 끝냅니다.

역슬래시(\)는 따옴표나 특수 문자를 이스케이프하는 데 사용합니다. 예를 들어 %는 \%, [는 \[, {는 \{로 씁니다. \n을 쓰면 줄바꿈도 넣을 수 있습니다.

Ren'Py 문자열 안에서 연속된 공백과 줄바꿈은 공백 하나로 합쳐집니다. 다만 공백 앞에 역슬래시를 붙이면 그 공백은 유지됩니다.

'문자열에는 구분자를 넣을 수 없습니다. 단, \'처럼 이스케이프 처리하면 가능합니다.'

"다음 두
 단어 사이에는 공백이 들어갑니다."

"이 두 부분 사이에는\n줄바꿈이 들어갑니다."

"그리고 이 두 부분 사이에는\ \ \ 공백이 세 칸 들어갑니다."

r 접두사는 지원하며 Python과 대체로 같은 규칙을 따릅니다. u, b, f 같은 다른 접두사는 지원하지 않습니다. 일반 문자열이 필요한 곳에서는 대체로 삼중 따옴표 문자열을 사용할 수 없습니다. 사용할 수 있는 경우에도 보통 결과가 달라집니다. 예시는 독백 모드를 참고하세요.

참고

이 규칙은 say 문이나 게임 내 선택지 메뉴처럼 Ren'Py 스크립트에 직접 작성하는 문자열에 적용됩니다. Python 문이나 아래에서 설명하는 표현식 안의 문자열은 일반적인 Python 규칙을 따릅니다.

단순 표현식

단순 표현식은 Ren'Py 스크립트의 일부 위치에 Python 코드를 넣을 때 사용하는 Python 표현식입니다. 단순 표현식은 다음 중 하나로 시작합니다.

  • 이름.

  • 문자열.

  • 숫자.

  • 괄호로 감싼 임의의 Python 표현식.

그 뒤에는 다음 요소를 원하는 만큼 이어 붙일 수 있습니다.

  • 점(.)과 그 뒤의 이름.

  • 괄호로 감싼 Python 표현식.

예를 들어 3, (3 + 4), foo.bar, foo(42)는 모두 단순 표현식입니다. 반면 3 + 4는 하나의 단순 표현식으로 처리되지 않습니다. 앞의 요소에서 단순 표현식이 끝나기 때문입니다.

Python 표현식

Python 표현식에는 임의의 Python 표현식을 쓸 수 있지만 콜론은 포함할 수 없습니다. if 문이나 while 문의 조건 등에 사용합니다.

문의 공통 문법

대부분의 Ren'Py 문은 공통 문법을 따릅니다. say 문을 제외하면 모두 해당 문을 나타내는 키워드로 시작합니다. 매개변수를 받는 문이라면 키워드 뒤에 매개변수를 씁니다.

매개변수 뒤에는 하나 이상의 속성이 올 수 있습니다. 각 속성을 한 번만 지정한다면 순서는 자유롭습니다. 속성은 키워드로 시작하며, 대부분의 속성은 이름 뒤에 앞서 설명한 구문 요소 중 하나를 받습니다.

블록을 받는 문은 줄 끝에 콜론(:)을 붙입니다. 블록을 받지 않으면 그대로 줄을 끝냅니다.

Python 표현식 문법

참고

지금 이 절을 자세히 읽을 필요는 없습니다. 먼저 다음 내용으로 넘어간 뒤 예제를 이해하기 어렵거나 실제 동작 방식을 알고 싶을 때 돌아와 읽어도 됩니다.

Ren'Py의 여러 기능은 Python 표현식을 받습니다. 예를 들어 새 캐릭터를 정의할 때는 Character() 함수를 호출합니다. Python 표현식은 매우 강력하지만 기본적인 Ren'Py 게임을 만드는 데는 그중 일부만 알면 됩니다.

Python 표현식의 주요 요소를 간단히 소개합니다.

정수

정수는 소수점이 없는 수입니다. 3과 42가 정수입니다.

실수

float는 부동소수점 수를 뜻하며, 소수점이 있는 수입니다. .5, 7., 9.0이 모두 float입니다.

문자열

Python 문자열은 "나 '로 시작하고 같은 문자로 끝납니다. \는 닫는 따옴표를 이스케이프하거나 줄바꿈(\n) 같은 특수 문자를 넣는 데 사용합니다. Ren'Py 문자열과 달리 이 형태의 Python 문자열은 여러 줄에 걸쳐 쓸 수 없고, `로 감쌀 수도 없습니다.

True, False, None

세 가지 특별한 값이 있습니다. True는 참, False는 거짓입니다. None은 값이 없음을 나타냅니다.

튜플

튜플은 항목의 개수가 중요한 데이터 묶음을 나타낼 때 사용합니다. 예를 들어 항목 두 개짜리 튜플, 즉 쌍으로 너비와 높이를 표현하거나, 항목 네 개짜리 튜플 (x, y, width, height)로 사각형을 표현할 수 있습니다.

튜플은 여는 괄호 (로 시작하고, 쉼표로 구분한 Python 표현식을 0개 이상 넣은 뒤 닫는 괄호 )로 끝냅니다. 특별히 항목이 하나뿐인 튜플은 그 항목 뒤에 쉼표를 반드시 붙여야 합니다. 예를 들면 다음과 같습니다.

()
(1,)
(1, "#555")
(32, 24, 200, 100)
리스트

리스트는 항목의 개수가 달라질 수 있는 데이터 묶음을 나타낼 때 사용합니다. [로 시작하고, 쉼표로 구분한 표현식을 넣은 뒤 ]로 끝냅니다. 예를 들면 다음과 같습니다.

[]
[1]
[1, 2]
[1, 2, 3]
변수

Python 표현식에서는 define 문이나 default 문으로 정의한 값을 담는 변수를 사용할 수 있습니다. 변수 이름은 문의 구성 요소에서 설명한 이름의 규칙을 따릅니다. 예를 들면 다음과 같습니다.

playername
love_love_points
trebuchet2_range
필드 접근

Python의 모듈과 객체에는 필드가 있습니다. 표현식, 보통은 변수 뒤에 점과 필드 이름을 붙여 접근합니다. 예를 들면 다음과 같습니다.

config.screen_width

위 표현식은 변수 config와 그 필드 screen_width에 대한 접근으로 구성됩니다.

호출

Python 표현식에서는 값을 반환하는 함수를 호출할 수 있습니다. 표현식, 보통은 변수 뒤에 여는 괄호를 붙이고, 쉼표로 구분한 인수 목록과 닫는 괄호를 씁니다. 인수 목록에는 먼저 Python 표현식으로 된 위치 인수를 쓰고, 그 뒤에 인수 이름·등호·표현식으로 이루어진 키워드 인수를 씁니다. 다음 예제에서는:

Character("에일린", type=adv, color="#0f0")

Character() 함수를 호출합니다. 위치 인수는 문자열 "Eileen" 하나입니다. 키워드 인수는 두 개로, type에는 adv 변수의 값을, color에는 문자열 "#0f0"를 전달합니다.

함수 이외에도 호출할 수 있는 객체가 있으며, 이런 객체를 통틀어 호출 가능 객체(callable)라고 합니다.

이 문서에서는 다음과 같은 함수 서명을 볼 수 있습니다.

Sample(name, delay, position=(0, 0), **properties)

Ren'Py에 실제로 존재하는 함수가 아니라, 문서 설명을 위한 예시 함수입니다.

이 함수의 서명은 다음을 의미합니다.

  • 이름은 "Sample"입니다.

  • 위치 매개변수는 name과 delay 두 개입니다. 실제 함수라면 각 매개변수의 자료형을 문서에서 설명합니다.

  • 키워드 인수는 position 하나이며, 기본값은 (0, 0)입니다.

끝의 **properties는 추가 키워드 인수로 스타일 속성을 받을 수 있다는 뜻입니다. 이 밖에 *args는 개수가 정해지지 않은 위치 매개변수를 받는다는 뜻이고, **kwargs는 보통 해당 함수 문서에서 설명하는 여러 키워드 매개변수를 받는다는 뜻입니다.

함수 서명에 단독으로 쓰인 /가 있으면 그 앞의 매개변수는 위치 전용이므로 키워드로 전달하면 안 됩니다. 반대로 단독으로 쓰인 *가 있으면 그 뒤의 매개변수는 키워드 전용이므로 반드시 name=value 형태로 전달해야 합니다.

Python은 이 안내서에서 다룰 수 있는 범위보다 훨씬 많은 기능을 제공합니다. 더 자세히 배우려면 python.org의 Python 튜토리얼부터 시작하는 것을 권장합니다. Ren'Py를 사용하기 위해 Python을 깊이 알아야 하는 것은 아니지만, Python 문과 표현식의 기초를 알면 도움이 되는 경우가 많습니다.