レイヤー画像 link
スプライトの組み合わせがある程度複雑になると、すべての可能な組み合わせの定義は難しくなります。例えば4つの服装と4つの髪型、6つの表情のキャラクターの組み合わせはすでに 96 組あります。すべての可能な組み合わせの静止画像作成は多くのディスクスペースとプログラマーの時間を消費します。
このような状況に対処するため、Ren'Py にはレイヤーに分けられた複数のスプライトで構成される画像を定義する方法があります(ここで言うレイヤーは Photoshop やGIMP のようなペイントソフトでのレイヤーであり、Ren'Py の他の場所で語られているようなレイヤーではありません)。これらのレイヤーの要素はその画像に指定された 属性 や実行時に評価された条件によって選択されます。
これらの画像は特別な言語により layerdimage
ステートメントを使用して宣言できます。レイヤー画像の定義をより簡単に定義するため、 Ren'Py には layerdimage
ステートメントがあります。 LayerdImage()
オブジェクトはその python に相当するものであり、 displayable ではありませんが、 image ステートメントに代入して画像のように使用出来ます。
このページの末尾には使用に対するアドバイスと例があります。
レイヤー画像の定義 link
レイヤー画像を定義するのに使用される言語はレイヤーを導入する僅かなステートメントで構成されます。こちらは実用的な意味はあまりありませんが、技術的には正しく、レイヤー画像の構文概要を示す例です。
layeredimage augustina:
zoom 1.4
at recolor_transform
always:
"augustina_base"
attribute base2 default
group outfit:
attribute dress default:
"augustina_dress"
attribute uniform
group face auto:
pos (100, 100)
attribute neutral default
label start:
show augustina # displaying dress and neutral
aug "I like this dress."
show augustina happy # auto-defined in the auto group
aug "But what I like even more..."
show augustina uniform -happy # uniform replaces dress, neutral replaces happy
aug "Is this uniform !"
Layeredimage link
まず、 layeredimage
ステートメントを紹介します。このステートメントは Ren'Py スクリプト言語の一部であり、 初期化時 に実行されます。 image ステートメントの ATL ブロック と同様に、画像名を受け取ってブロックを開きますが、ブロックの中身は大きく異なっています。画像名には、 Ren'Py の他の画像名と同じように、スペースを含めるられます。
ブロックの中には後述するステートメントと次の任意のプロパティーが収まります。
- image_format
文字列で画像が与えられており、かつこのプロパティーが与えられていると、image_format にその画像名が補完され、画像ファイルになります。例えば、 "sprites/eileen/{image}.png" ならsptritesのサブディレクトリーからその画像を探します ( 自動グループは画像ファイルではなく定義された画像を探すためこれは自動グループでは使用されません)。
- format_function
layeredimage.format_function()
の代わりに初期化時の画像定義中に使用して画像の情報を displayable 形式にする関数です。- attribute_function
表示される属性を調整する関数やコールバックです。画像に渡される属性の set で呼び出され、レイヤーの選択に使用される属性の set を返します。属性間の複雑な依存関係を表現したり、属性をランダムに選択するのに使用出来ます。いつどのように呼び出されるかは 表示する属性の選択 を参照してください。
- at
レイヤー画像へ適用される transform または transform のリストです。
- transform プロパティー
与えられれば、 Displayable に適用される transform を構築するのに使用されます。
- offer_screen
これが True ならゲームの画面全体と同じ領域が与えられたかのようにレイヤー画像はその子を配置し、可変サイズの子のサイズを合わせます。 False なら、利用可能な領域を考慮しながらこれらの動作が行われ、例えば他の要素を含む hbox では小さくなり、レイヤー画像の表示は表示されるたびに一貫しなくなります。
None の場合、デフォルトの
config.layeredimage_offer_screen
に戻ります。これはデフォルトでは True です。
Always link
always
ステートメントは常にレイヤー画像に表示され、属性には所属しない画像を宣言します。 displayable が与えられなければならず、プロパティーも受け取れます。両方を同じ行にもブロック内にも配置できます。
always
ステートメントは次のプロパティーを受け取ります。 :
- if_all
属性の名前の文字列または文字列リストです。これがあれば、このレイヤーはそのすべての属性名が与えられなければ表示されません。
- if_any
属性の名前の文字列または文字列リストです。これがあれば、このレイヤーはその属性名のどれかが与えられなければ表示されません。
- if_not
属性の名の文字列または文字列リストです。これがあれば、このレイヤーはその属性名がすべて与えられなければ表示されます。
- transform プロパティー
与えられれば、 Displayable に適用される transform を構築するのに使用されます。
- at
displayable に適用される transform または transform のリストです。
If link
if
ステートメント (または if-elif-else ステートメント) には実行時に評価される 1 つ以上の条件を渡せられます。各条件は Displayable に関連付けられ、最初に True となる条件のものが表示されます。 True となる条件がなく、 else
レイヤーがあれば、それが表示されます。
if
ステートメントのより完全な例は次のようになります。
if glasses == "evil":
"augustina_glasses_evil"
elif glasses == "normal":
"augustina_glasses"
elif glasses == "funky":
"augustina_glasses_clown"
else:
"augustina_nose_mark"
各節には displayable が与えられなければならず、次のプロパティーも与えられます。 :
- if_all
属性名の文字列または文字列のリストです。これがあれば、この条件はそのすべての属性名が与えられなければ考慮されません。
- if_any
属性名の文字列または文字列のリストです。これがあれば、この条件はその属性名のどれかが与えられなければ考慮されません。
- if_not
属性名の文字列または文字列のリストです。これがあれば、この条件はその属性名がすべて与えられなければ考慮されます。
- transform プロパティー
与えられれば、 Displayable に適用される transform を構築するのに使用されます。
- at
Displayable に適用される transform または transform のリストです。
if
ステートメントは layerdimage
ステートメント実行時に ConditionSwitch()
に変換されます。
- layeredimage.predict_all = None link
predict_all の値をレイヤー画像の
if
ステートメントで生成された ConditionSwitch に対して設定します。
predict_all
が True でなければ、レイヤー画像が表示されている、またはまさに表示されるときは if
ステートメントの条件の変更は避け、予測不能な画像の読み込みを避けるべきです。これはめったに変更されない character のカスタマイズオプションでの使用を意図しています。
Attribute link
attribute
ステートメントは、指定の属性が使用されたときに表示にされる最終的な画像の一部となる Displayable を追加します。例えば前述の例では、 show augustina dress
を呼び出すと、 "augustina_dress" が "augustina" 画像の一部として表示されます。
attribute
節は属性名を受け取り、それは1つの単語です。さらに 2 つのキーワードも受け取れます。 default
キーワードは同じグループの属性が呼ばれていなければデフォルトで与えられる属性であることを示します。 null
キーワードは Ren'Py が自動的にこの属性に対応する displayable を検索しないようにするので、 if_all や if_any, if_not, attribute_function, config.adjust_attributes
, config.default_attributes
を使用して表示条件を構築するのに便利です。
同じ属性名を複数の attribute
節 ( および auto
グループの一部として自動定義の属性 ) で使用して、対応するすべての Dsiplayable を同時に表示できます ( if_all, if_any, if_not プロパティーでこれを変更出来ます)。
Displayable が明示的に指定されなければ、レイヤー画像名と(あれば)グループ、(あれば)グループの variant, 属性の組み合わせから算出されます。詳細は pattern を参照ください。
attribute ステートメントは次のプロパティーを受け取ります :
- if_all
属性名の文字列または文字列リストです。これがあれば、このレイヤーはそのすべての属性名が与えられなければ表示されません。
- if_any
属性名の文字列または文字列リストです。これがあれば、このレイヤーはその属性名のどれかが与えられなければ表示されません。
- if_not
属性名の文字列または文字列リストです。これがあれば、このレイヤーはその属性名がすべて与えられなければ表示されます。
- transform プロパティー
与えられれば、レイヤーに適用される transform を構築するのに使用されます。
- at
レイヤーに適用される transform または transform のリストです。
if_* 節の評価は こちら で説明されたように、最終的な画像の属性リストに基づきますが、そのリストは 変更しません
layeredimage eileen:
attribute a
attribute b default if_not "a"
attribute c default if_not "b"
この例では b
と c
属性が ( それらの default
節のために ) 常に 属性リストにあります。 show eileen a
を呼び出すと、 a
属性が要求どおり表示され、 b
属性はその if_not
プロパティーにより表示されまん。しかし、表示されなくとも b
属性は属性リストにはまだ残っています。つまり c
属性は表示されません。
Group link
group
ステートメントは属性をグループ化し、相互に排他的にします。グループが multiple
でない限り、属性 a と b が同じグループであるときに show eileen a b
のように同時に両方の属性を含めるとエラーになります。同様に、属性 a を呼び出すと属性 b が非表示になり逆もしかりです。ただし、 同じグループ内であっても 複数の attribute
節に同じ名前が渡されてもよいので注意してください。その場合、それらは複数のスプライトを含む1つの属性として扱われます - 詳しくはこの章の最後で説明します。
group
ステートメントは名前を受け取ります。その名前はあまり使用されず、グループ内の属性のデフォルト名を生成するのに使われるのみです。しかし、 multiple
group では名前はまったく使用されず影響もありません。
名前の後に auto
キーワードを続けられます。これがあるとそのグループのすべての属性が宣言された後、 Ren'Py は画像のリストをスキャンしてグループパターン( 下記 参照)にマッチするものを探しますが、このとき layerdimage に渡された format_function
は無視され、 multiple キーワードを指定されたグループ名も通常のグループ名のようにパターンに含まれます。見つかった画像は明示的に宣言された属性に対応する物を除いて、すべての画像がそのグループのブロック内で attribute
ステートメントで宣言されたかのようにグループに追加されます。実践的なデモとして 例 を参照してください。
multiple
キーワードも続けられます。与えられれば、ブロック内で宣言された属性に非排他性が適用されます。これは排他的ではない複数の属性を自動定義するグループや同じプロパティーを一度に属性のセットに適用するのに便利です。これは属性の1つに default
キーワードが与えられていると衝突します。 multiple
group は他とかなり異なることに注意してください。通常のグループに当てはまることはほとんど当てはまりません。
これらの任意のキーワードに続いて、プロパティーはグループの最初の行で宣言できます。グループはプロパティーや属性を含むブロックも持てます。
group ステートメントは if_any
や at
などのように、 attribute
プロパティーを受け取ります。グループに提供されたプロパティーは、属性自身の同じプロパティーに上書きされない限りそのグループ内の属性に渡されます。加えてグループに限定の 2 つのプロパティーがあります。
- variant
指定されるならこれは文字列であり、自動生成の画像名の一部と
auto
グループで属性を自動定義するときの画像の検索パターンの一部になります。- prefix
指定されるなら、手動または自動で定義された属性名とアンダースコアで連結される接頭辞です。つまり prefix が "leftarm" で、属性名が "hip" なら、 "show eileen leftarm_hip" でそれが表示されます。
ある属性が複数のグループに属すこともでき、その場合、その属性は属するグループ内の他のすべての属性と排他的です。これは、例えば dress 属性の場合、表示されたときにトップとパンツの両方を非表示するのに便利です
layeredimage eileen:
attribute base default
group bottom:
attribute jeans default
attribute dress null
group top:
attribute shirt default
attribute dress
同じレイヤー画像で同じ名前の group
ブロックが定義されると、1つのグループの異なるパーツとして考慮されます。例
layeredimage eileen sitting:
attribute base default
group arms variant "behind":
attribute on_hips
attribute on_knees
attribute mixed
attribute table default
group arms variant "infront":
attribute on_table default
attribute holding_margarita
attribute mixed
この例では、 eileen_sitting_arms_behind_mixed.png
にはテーブルの後ろの左手があり、 eileen_sitting_arms_infront_mixed.png
にはテーブルの上の右手があります。 show eileen sitting mixed
を呼び出すと、その二つの画像がそれぞれテーブルの後ろと前に同時に表示されます。同じブロックで宣言されていなくても、両方が同じグループなのでこの例では、 on_hips 属性は on_table 属性に対して排他的です。
パターンとフォーマット関数 link
属性に明示的に画像が与えられていないときに属性に対する画像を探すのに使用されるパターンです。次で構成されます。 :
スペースがアンダースコアで置換されたレイヤー画像名
グループがありかつ
multiple
でなければグループ名あれば variant の名前
属性の名前
すべてはアンダースコアで結合されます。例えば、レイヤー画像 "augustina work" とグループ "eyes" があれば、これはパターン augustina_work_eyes_attribute にマッチする画像にマッチします。 variant が bule なら、パターン augustina_work_eyes_blue_attribute にマッチします。
layeredimage augustina work:
group eyes variant "blue":
attribute closed
この例では、属性は画像 "augustina_work_eyes_blue_closed"
にリンクされます。それにより augustina_work_eyes_blue_closed.png
の名前を持つ画像ファイルに名前解決されますが、例えば image ステートメント を使用して明示的にも定義できます。
multiple
グループの名前をパターンに含めたければ、次の構文が使えます。
group addons multiple variant "addons"
フォーマット関数を使用してパターンの動作を変更できます。 layeredimage.format_function()
上述の動作を実装するために内部で使用されている関数です。自身のフォーマット関数で置き換えたいなら、これが何の引数をとるかを参照しましょう。
- layeredimage.format_function(what, name, group, variant, attribute, image, image_format, **kwargs) link
これを呼び出して属性や条件を displayable の情報にフォーマットします。制作者によって置き換えられますが、新しい関数は未知のキーワード引数を無視するべきです。
- what
フォーマットされるものを記述する文字列で、よりよいエラーメッセージを作成するために使用されます。
- name
レイヤー画像の文字列です。
- group
属性のグループで、 提供されないか条件内での使用なら None になります。
- variant
グループへの variant 引数で、提供されなければ None です。
- attribute
属性です。
- image
displayable または文字列です。
- image_format
LayerdImage の image_format 引数です。
image が None なら、 name と (あれば) group,(あれば) variant, attribute がアンダースコアで結合され、 image の文字列になります。
images が文字列で image_format が None でなければ、 image は最終的な displayable を所得する文字列にフォーマットされます。
つまり name が "eileen", group が "expression", attribute が "happy" なら、 image は "eileen_expression_happy" に設定されます。 image_format が "images/{image}.png" なら、Ren'Py が見つける最終的な画像は "images/eileen_expression_happy.png" です。ただしフォーマット引数なしでも同じ画像を見るので注意してください。
Proxying Layered Images link
レイヤー画像を使い回して同じレイヤー画像を複数の場所で使用しなければならないときがあります。これは例えば、特定のレイヤー画像の transform を適用したバージョンを作成して、サイドイメージとして使用するためです。
LayeredImageProxy()
オブジェクトでこれを行います。レイヤー画像を1つ受け取ってどこかに複製します。例
image dupe = LayeredImageProxy("augustina")
独立して表示出来る画像の複製を作成します。これはこのように transform を引数に受け取るのでサイドイメージを配置するのに便利です。
image side augustina = LayeredImageProxy("augustina", Transform(crop=(0, 0, 362, 362), xoffset=-80))
次の例の違いに注目してください。
image sepia_augustina_one = Transform("augustina", matrixcolor=SepiaMatrix())
image sepia_augustina_two = LayeredImageProxy("augustina", Transform(matrixcolor=SepiaMatrix()))
sepia_augustina_one
はレイヤー画像 "augustina" の デフォルトバージョン のセピアバージョンであり、言い換えると表示されるものは属性を何も与えないときのものです。対照的に、 sepia_augustina_two
は "augustina" が受け取るどの属性も受け取られ、それらにセピア調のエフェクトを適用します。元々次ができるとすると、
show augustina happy eyes_blue dress
このようになります。
show sepia_augustina_one happy eyes_blue dress
# won't work, because Transform doesn't take attributes
show sepia_augustina_two happy eyes_blue dress
# will work, and show "augustina happy eyes_blue dress" in sepia effect
- class LayeredImageProxy(name, transform=None) link
これは画像のようなオブジェクトです。渡される属性を他のレイヤー画像に中継します。
- name
中継するレイヤー画像の名前の文字列です。
- transform
与えるなら、中継先の画像に適用される transform または transform のリストです。
表示する属性の選択 link
指定された show ステートメント に続いて何が表示されるかにはいくつかの要素が影響します。どのような順番で何が起こるかをより明確にするために、このセクションでは show ステートメントから画面上の表示まで、一連の属性の一生を紹介します。
show
ステートメントは画像タグに続いて最初の属性のセットを提供します。config.adjust_attributes
関数があり、その画像タグに一致すれば呼び出されて変更された可能性のある属性のセットを返します。そうであれば以前のセットは置き換えられ、忘れられます。config.default_attribute_callbacks
関数があって、その実行条件が満たされていれば、呼び出されてそのセットに属性が追加される可能性があります。
前述の段階はレイヤー画像に限定されません。この後の段階で Ren'Py はどの画像またはレイヤー画像が呼び出されて表示するか決定します。そのために、与えられた属性のセットは、 show statement section で説明されている動作で、1つの、そして唯一の定義された画像 ( または layeredimage, Live2D...) につながる必要があります。
次に、提供された属性はレイヤー画像に定義された属性と結合され、先に表示されていた属性のいくつかは破棄され、他の属性は保存されます。認識されない属性はここで検出され、エラーが発生します。そのようなエラーが発生しなければ、新しい属性と捨てられなかった属性が renpyによってその画像タグに関連する属性のセットとして認識されます。この計算では排他性の制約の一部を考慮に入れていますが、すべてではありません。例えば、属性が同じ非 multiple グループにあることによる排他性はこの時点で発生しますが、if_any/if_all/if_not 節ではエラーは発生しません。そのため、このような節で否定された属性も renpy ではアクティブとみなされ、例えば、 if_x 節の条件が満たされなくなった時点で再度呼び出されなくとも表示されるようになるのです。
attribute_function
がレイヤー画像に提供されている場合、残りの属性のセットで呼び出されます。これは潜在的に異なる可能性のある属性のセットを返します。このセットは、もう一度レイヤー画像の非排他性の制約に直面します。これが最終段階であり、残っている属性が表示されます。
アドバイス link
画像ファイル名ではアンダースコアを使用してください
デフォルトでは、 Ren'Py のレイヤー画像はアンダースコアで画像名をパーツに分割します。パーツ間にスペースがある画像の使用は魅力的かもしれませんが、後述の問題に発展しかねません。
Ren'Py には既に表示されているものと正確に同じ名前の画像を表示するときは置き換えて表示するルールがあります。これにより定義したレイヤー画像ではなく、直接スプライトを表示する可能性があり、これはなにもない空間に目が浮かぶような妙な問題に繋がる可能性があります。
各レイヤーがメインの画像と異なるタグを持てばこれは問題ではなくなります。
レイヤーの切り取りは不要です
Ren'Py は画像を RAM に読み込む前に、不透明なピクセルの矩形領域に切り取って画像を最適化します。つまり画像が適切に予測されれば、自分で画像を切り取ってもパフォーマンスや画像サイズは一般的にあまり改善しません。
レイヤー画像には実行時に変化するデータを使用するべきではありません
if
ステートメントの条件を除いて、 layeredimage
に記述されたすべての式はそのレイヤー画像が最初に定義される初期化時に評価されることに注意してください。これは例えば ATL transform や config.adjust_attributes
, config.default_attributes
, attribute_function
の場合はその限りではなく、レイヤー画像定義時にのみ呼び出される format_function
には当てはまります。
使用する構文を選んでください
あるスプライトが常に見えるようにしたければ always
節や attribute x default
構文を使用してください。 always
は明示的な Displayable の提供を要求します( pattern を使用した自動的な属性は利用不能です)。一方 attribute
は "x" を属性名としてそのレイヤー画像で常にアクティブにします。
show
ステートメントを使用してレイヤー画像に渡された属性にもとづいて表示したいなら、例えば show eileen jeans
の代わりに show eileen happy
など、 attribute
ステートメントを group
ブロックの内と外で (もしくは明示的に auto
グループで定義して) 使用してください。
python 変数や条件にもとづいて表示したいなら、 if
ステートメントを使用してください。
両方に基づかせたい ( 例えば show eileen ribbon
が青と赤どちらのリボンを表示するかを変数に基づき、 ribbon
属性でリボンを表示するかを決めたい場合)は、すべてのバージョンを属性として定義し、 config.adjust_attributes
関数を使用して調整してください。
例 link
パターンと自動グループ
images/ ディレクトリ ( またはそのサブディレクトリの1つ)に次のファイルがあり、次のコードを記述します :
francis_base.png
francis_face_neutral.png
francis_face_angry.png
francis_face_happy.png
francis_face_very_happy.png
francis_face annoyed.png
francis_supersad.png
layeredimage francis:
attribute base default
group face auto
attribute neutral default
attribute supersad:
Solid("#00c3", xysize=(100, 100))
francis
レイヤー画像は base
属性をデフォルトとして宣言し、 パターン を使用して(自動定義により)それを "francis_base" 画像に紐付けます。: レイヤー画像名("francis")、グループ名(ここではなし)、 variant 名(ここではなし)、属性名 ("base") がアンダースコアで分割されます。
次に face
グループで明示的な neutral
属性が "francis_face_neutral" 画像に紐付けられます。上記と同じパターンですが、ここではグループ名として "face" を属性名として "neutral" を使用します。
すべての明示的な属性が画像を受け取ると、 face
は auto
であるので、既存の画像(自動定義されているかどうかは別として)がパターンにマッチするかどうかスキャンされます。ここでは、"francis_face_angry", "francis_face_happy", "francis_face_very_happy" の3つが検出されました。これらはそれぞれ、先ほどと同じパターンを使用して angry
, happy
, very_happy
属性と関連付けられます。しかし、"francis_face annoyed" 画像にはアンダースコアが必要なところにスペースが含まれているため、annoyed
属性は定義されません。
最後に、 supersad
属性が宣言されますが、 displayable が明示的に指定されているため、パターンではマッチする画像を探しません。
"francis_supersad" と "francis_face annoyed" 画像は Ren'Py の通常の プロトコル の一環として、ファイル名から自動定義されますが、これらのスプライトはどのような属性やグループにもマッチされないため francis
レイヤー画像には結局使用されません。
見ての通り、パターンの使用により画像を属性に対応させ、自動グループによりコードを有意に省略できます。同じレイヤー画像をすべて明示的に宣言しようとすると、13 行必要になり、この構文により、スプライトの組み合わせの幾何学的な増加が可能になります(新しい顔をいくつか追加しても、コードを変更する必要がなくなります)。
動的な属性
こちらは(本章で述べたように)変数にもとづく属性を定義する例です。
layeredimage eileen:
attribute base default
group outfit auto
group ribbon prefix "ribbon":
attribute red
attribute blue
default eileen_ribbon_color = "red"
init python:
def eileen_adjuster(names):
atts = set(names[1:])
if "ribbon" in atts:
atts.remove("ribbon")
atts.add("ribbon_" + eileen_ribbon_color)
return names[0], *atts
define config.adjust_attributes["eileen"] = eileen_adjuster