給田/背泳 2024/02/10 15:02

【進捗】魚肚白[2024.02] + Ren'Py Tips(?)

 4か月分の更新をすっ飛ばし、年も明けての2月です。大変遅ればせながら、今年もどうぞよろしくお願いします。

 今週始めは住んでいる地域で雪も降り、比較的寒い日がまだ続いていますが、来週は20℃行くかもしれないとかいう予報に、春だ~~~~~~!!!とテンションが上がっています。やっぱり寒い時期は得意になれない。空気が澄んでいて空がきれいだったり、良いところもあるんですけどね。

2024年の目標、なんかないのか

 過ぎし2023年は「魚肚白の体験版リリース」と「人生初の薄い本(二次創作)作り」という目標を掲げ、結果だけ見ると片手落ちということになりました。最近、後者の薄い本の進捗を呟いたりしていませんでしたが、結局、昨年夏頃にペン入れは全ページ終わったものの、トーンに入った段階で「ペン入れやり直してえ……」「本当にこのクオリティで発行するんか……」の気持ちになってしまい、それ以上手が動かなくなっていたという経緯です😇 ちょっと本当に今年こそはなんとかしたい。ペン入れやり直してもいいから……そもそも同人誌なんて自己満足なのだから……。

 昨年の目標達成状況の振り返りをしたところで、今年の目標は「魚肚白のRen'Py移植」と「魚肚白のヂェンルートシナリオの完成」、「人生初の薄い本作り(昨年から継続)」としたいと思います。できるんか本当に?!? Ren'Py移植はなんなら上手くいけば今月中にでも終えられそうなためシナリオ完成も入れましたが、自身の遅筆っぷりを疑ったことのない身としては不安しかない。多分、「うみをはむ」の16:9対応とかRen'Py移植とかに逃げそう。

「魚肚白」のRen'py移植状況

 年明けてからはほぼRen'Py移植に集中していました。今のところ、下記で言う「バックログのキャラ紹介・用語画面整備」のところまで進んでいます。これが終わって、細々追加のやりたいことを実装できたらリリースなので、前述のとおり実際作業ペース的にこのまま今月もしくは来月にはリリースできそうという順調さ。
https://twitter.com/svqg84/status/1751558578450911724

Ren'PyのTips的なこと

 そういうわけで今回は進捗がスクリプト作業に偏っているので、Ren'Pyを採用&作品移植をしてきてここまでで、自分が躓いた点・調べてみてこういうことだったのかと解決した方法等々、少しまとめてみます。今後、Ren'Pyに挑戦される方の一助となれば幸い。

 Tipsなどと偉そうに銘打っていますが、前提として下記の点は予めご了承ください。

  • 以下、Ren'Py側の記載を[R]、python側の記載を[P]としています。
  • コピペできるような具体的なコード類はあまり記載していないです。Ren'Py公式ドキュメントを軸として、基本的なことは自分で調べて理解できる人(プログラミング苦手じゃないけど得意とか専門職とかではない私と同じレベルの人)が理解に至るまでのショートカットになるように、のレベルで書いてます。(※とはいえ、具体的にここどう書いてる?と聞いていただければお答えするのでお気軽にお声がけください)
  • NScripter出身者なので、それ以外のツールor最近のプログラミングでは当たり前とされていること・概念も大げさに取り上げてたりします。許してね。

Ren'Pyの変数について

 基礎的なところはみやこ出版さん(種々参考にさせていただいています!)でも解説されていますが、自分が躓いたところをまとめるとこう。

  • define[R]とdefault[R]とpython内での変数の定義・代入の違い【Ren'Py公式
    ぶっちゃけ変数管理ができていて、都度適切に初期化等出来る人であればあんま意識する必要ないと思います(非プログラマー思考)が、念のため。
    とはいえ、これはRen'Py公式読んでね以上に言えることがない。これ以上うまく説明できる自信がない。
  • 変数におけるstoreという概念 【Ren'Py公式
    「define x = ...[R]」「x = ...[P]」で定義した変数は自動的に "store" という名前の store に保存される。同じ "store" という名前のstoreからの参照は、そのまま「x」という変数を呼び出すだけなので、あまり凝ったことをする必要がないゲームでは意識する必要ないけれど、効率化等のためにpython使って関数を定義するときにここを把握していないと「そんな変数、どこにもない(未定義)けど?」と言われて戸惑ったりする。pythonのクラスとかを使っていると、そこは "store" とは別のstoreになるので、例えばRen'Py側で「define x = ...[R]」で定義した変数を「x」ではなく「store.x」と記述して呼び出さなければいけなくなる。
    公式文書でも書いてあるとおり、storeは「python in 名前」で「ここのpythonのstore名は『名前』だよ」と宣言して任意に変更することもできる。
    (※余談 これに気付くまで自分はpythonのglobal宣言をわざわざして"store"以外のstoreから"store"内の変数を呼び出していました……。実際これでも動いたけれど、かなり対処療法的で普通に考えて邪道な気がする)
  • 永続データ 【Ren'Py公式
    これが「このエンドをみたかどうか」等のフラグを格納する変数。ゲーム画面を一度落としても保存されているので、次にゲームを起動したときも変わっていない変数。persistent.~の形になる。
    いわゆるNScripterでいうところの「グローバル変数」、ティラノスクリプトでいうところの「システム変数」。(設計思想が異なるゲームエンジン間での例えは厳密には不正確だと思いますが、ゲーム制作者ならこっちのほうが通じやすい気がするので書いてます)

Ren'Pyの旨味:スクリーン

 Ren'Pyの個人的に大好きな機能です。この機能を理解したとき、NScripterはじめとする古のゲームエンジン使用経験がある人間的には、頭を殴られたぐらいの衝撃を受けました。べ、便利……圧倒的便利ッ!!!! ゲーム本編が動的に動いていくのに対して、タイトル画面・セーブロード画面・選択画面・確認画面など、「画面」とつく比較的静的な機能をゲームでは実装する必要があるわけですが、それを簡単に作れる機能です。きまったハコだけ作って関数的に構成・呼び出ししたりもできる。要素の横並び(Hbox)・縦並び(Vbox)からはじまって、一部をスクロールボックス化する(Viewport)なんてこともめちゃくちゃ簡単にできる。特にImagemapの便利さは後述します。魚肚白のシーン選択画面、秒でつくれたぞ……。

 スクリーンも基本的なところ+αはみやこ出版さんをご覧ください(デジタルお絵かきする人間的には「スクリーン=レイヤー的なもの」というのも理解の導入になって良い!)。勿論、Ren'Py公式もね。

デフォルトでRen'Pyに存在するスクリーンの名称

Ren'Pyは開発元の言語圏が英語のため、(日本語用のテンプレ使っていても)英語圏での独特の名称が出てきて初心者だと「何を指してる語???」となります。ここわりとよく言われていてほかの方もまとめていると思うけれど改めて拙作での例とともに書いておきます。

以下、[R]=Ren'Pyでの名称:[日]日本語圏での名称(独断と偏見)

  • [R]メインメニュー・main menu : [日]スタート画面・タイトル画面

  • [R]ゲームメニュー・game menu : [日]セーブ画面・コンフィグ画面等の大元の箱の画面(Ren'Pyはデフォルトだとgame menuというscreenを土台にしてセーブ・コンフィグ等各種画面を作成しています。勿論、それぞれ完全なる別物として作り上げることも可能)

  • [R]Sayスクリーン: [日]テキストウィンドウ

  • [R]クイックメニュー・quick menu : [日]常駐メニュー

  • [R]CTCスクリーン:[日]クリック待ち・改ページアイコン(後述注)

その他はhistory(履歴)とか、英単語の意味が分かれば意味しているところは分かるかと思います。デフォルトで用意されているスクリーンはRen'Pyの「screen.rpy」にほぼ全て記載があるので、基本はそこをいじり倒す形。

後述注:CTCスクリーン【Ren'Py公式, 】は「screen.rpy」に記載がありません。個別に設定するか、していなくてもCharacterオブジェクト内の記載(Ren'Py公式)で指定を渡していれば表示してくれます。ここはまだそこまでいじり倒してないのであまり語れることがない。続報をお待ちください。


では以下からスクリーンの便利なところとか躓いたところとか。スクリーン周りはいろいろあるのでまずは上記のゲームとして基本的な画面にまつわること。

基本的な画面(スクリーン)にまつわること

  • Say(テキストウィンドウ)改造 【Ren'Py公式
    地の文かセリフかでウィンドウの位置・形式を変えたい(拙作の魚肚白みたいなやつ)とか、発言者でセリフの色を変えたい、という場合はSayスクリーンを改造するのが一番早い。ゲーム本体で記述したセリフ=「what」、発話者=「who」という変数名で内容がわたってくるので、それをつかって条件分岐を設定する。
    :地の文にだけ適用したいスタイルや処理 …… if who is None: の下に続ける
    :括弧で始まるテキストに適用したいスタイスや処理(インデントとか) …… if what.startswith('「') or what.startswith('『') or what.startswith('('): の下に続ける

    条件分岐を作る際、pythonの処理を知っているととても便利。python自体のお勉強はいろんなところが紹介しているので割愛。基礎がわかったら、細かい処理とかはnkmkさんとかを眺めてみるのが個人的オススメです(ゲーム制作なら「文字列」の処理とかで十分)。こんな簡単な記述でこういう処理出来るんだ~! となると思います。
  • Say(テキストウィンドウ)非表示命令で一緒に消したいものがある場合 【Ren'Py公式
    「window hide[R]」とか「_window_hide[P]」でテキストウィンドウ+クイックメニューは消せるわけですが、そのとき一緒にこれも消したいんだが?! という画像やスクリーンとかがある場合、「hide_windows」という名前のラベルを作ってここにその画像やhide処理を書けばOK。これ、公式文書の検索機能でも出てこなくて見落とす(上記リンクのとおり書いてはいる。が、検索結果に出てこない)。ほんとこれ系は勘弁してくれ!(renpy\common\00keymap.rpyまで読みに行って知ったやつ)(というかこれ正確にはスクリーンの話じゃないんだけれど、多分Sayやクイックメニューに付随して湧き上がる疑問なのでここに)
  • ゲーム起動時にロゴ画面(メインメニュー表示の前に)【Ren'Py公式
    「ゲーム起動時に表示されるのがメインメニュー(スタート画面・タイトル画面)」なのだが、普通のゲームはメインメニューに入る前にロゴとかがだいたいある。あれはどうすればいいのか? メインメニューに入れ込むのか? そしたらメインメニューに戻るたびロゴ表示されて鬱陶しくない? 変数分岐してスキップするの?(それもできなくはない、多分)
    → 実はRen'Pyには既にそれを解決するデフォルトで用意されてるモノがある【Ren'Py公式】。「splashscreen」という名前のラベルを作ってここにロゴとかそのアニメーション入れておけばOK。先に言えよな、そういうの!(メインメニューに入れ込もうとしたやつ)(というかこれ正確にはスクリーンの話じゃないんだけれど以下略その②)
  • 各種スクリーンにまつわるトランジション(移行エフェクト)
    メニューを移行・表示するときに、パッパッと切り替えるより、ちょっとぼわ~っともやが広がるように移行・表示させたい、みたいな願望は誰しもあると思う。そういうときは「option.rpy」を「トランジション」で検索すれば設定できる箇所が見つかる。設定できるのは次のこと。
    ・ゲームメニューの開閉
    ・ゲームメニュー内の違うスクリーンへの移行
    ・ロード時の画面読込み
    ・Sayスクリーン:テキストウィンドウの表示・非表示
    上記以外のスクリーンは個別にShow(スクリーン名, transition)とかでやれるので基本、問題ないと思う。
    (※余談 個人的には「ImageDissolve【Ren'Py公式】」をつかってルール画像を使ったトランジョンを独自に定義するのが楽しかった。このときramplen=256(必ず2の整数乗の数にすること)とかにしてたと思う。ここをいじるだけでも印象がだいぶ違うのでいろいろ試してみるのオススメ)

独自の画面(スクリーン)を作るとき

こっちのほうがむしろスクリーンの「基礎」的なことなんですが、多分、だいたいのところをカスタマイズしなきゃ気がすまないゲ製作者より、公式が用意してくれている仕様・デザインに無理なく収まるように予め画像諸々を用意する人が多いと思うので、独自に画面を作っていく際のTipsは優先順位低いかなと思う。とはいえ自分は前者なので、その過程で知った・気づいたことを書いていきます。

  • modal設定【Ren'Py公式
    modal: モーダルっていうのはポップアップウィンドウが出てきた際、そのウィンドウより後ろ側にあるウィンドウ上のボタンは押せなくなる状態のこと。スクリーンを何重にも重ねて表示する場合(例:セーブ画面の上に、「セーブしますか?」の確認画面を出す)にこの設定をしておかないと、後ろ側の画面上のボタンも生きていて押せてしまい予期せぬこととなるので注意。
  • tag設定【Ren'Py公式
    「screen.rpy」のゲームメニュー類(game_menuそのものではなく、game_menuを使っているpreferencesとかhistoryとか)で「tag menu」というコードがある。これは「同じ『menu』というtagを持つスクリーン同士は排他的表示となる(1つが表示されていたら他は表示されない。他が表示されようとするとき、今まで表示されていたスクリーンは自動的に消える)」ようにするためのもの。逆に上記のmodal設定をして、2つのスクリーンを重ねて表示することにこそ意味がある場合、その2つのスクリーン同士が同じtag設定されていたら重ねて表示されない(同時に表示されることはないので片方が消える)ので注意。
    なお、Ren'Pyのデフォルトだとメインメニューとゲームメニューはどちらも「tag menu」を持っている。メインメニューの上にモーダル的にゲームメニューを表示させたい場合は、メインメニューの「tag menu」を消すこと。
  • Imagemap【Ren'Py公式
    「どこへ行く?」と表示され、地図画像がそのまま選択肢になっている(地図画像上のいたるところにボタンがある)、みたいなのを誰でも見たことがあると思うが、それを数枚の画像で完結させるのがこれ。超便利。
    普通、こうした画面は背景の地図画像、ボタンとして機能する個々の画像×n、そのホバー画像×nというそれなり~膨大な数の画像を用意しなきゃというのがこれまでだったと思うのだが(少なくともNScripterはそうでした)、Ren'Pyは「一番下の画像=ground」と「ボタンの統合画像」を用意すれば良いという簡単さ!!!
    恥を忍んで拙作「魚肚白」のシーン選択画面の例を晒すと画像のとおり。

    3枚の画像だけでこれが作れるわけです。hotspotに設定したところだけがボタン化され、ホバー時に変わるのもそこだけ。楽~~~~~~ッ!!! まあ相変わらず、hotspot=ボタン箇所のx,y座標はきちんと指定しなきゃなので、画像編集ソフトで確認しながら~ではあるけれど、個別画像保存の手間がないのは本当に楽。NScripterは更にセル化作業までありましたしね……
    追記2/11:Ren'Py標準機能でx,y座標+ボタンサイズを簡単に取得できるまふさんの知見! これで下記の余談はだいたい読み飛ばしOK!
    (※余談 完全にRen'Pyの話じゃないのですが、上記hotspot指定時のx,y座標の確認めんどくせえ! という方は最初からこうしたImagemap画面を作る際は、ClipStudioユーザーならグリッド表示を活用して5pxとか10px刻みのところにボタンを配置するようにするのもオススメ。x,y座標のキリが良くなるのでメモをミスして1pxズレた! とかがなくなります。場合によってはfor文で一括指定できるし。ちなみに私がUIを作る際はグリッド表示、グリッドにスナップ、長方形選択、選択範囲縮小・拡大、整列機能とかを使ってます)
    (※余談2 引き続きx,y座標指定の話をすると、あんまりボタンのx,y座標が等間隔じゃなくfor文での簡単な増減じゃ一括指定無理、という場合も、リストで比較的簡単に一括記述できます。リストで管理すれば後から変更しなきゃいけない場合も修正が簡単だしね。例えば上記の画像のシーンリストなら、私は各ボタンの情報のリスト(例:scenes.lists = [[シーンのラベル名, ボタンの大きさ, ボタンのx座標, ボタンのy座標, ]...等々])をつくって「for i, s in enumerate(scenes.lists)」)で勝手にhotspot化させる、という手法をとってます)

ここまで書いてめ~ちゃくちゃ息が上がってます(余談と言う名の無駄話に費やし過ぎているところも多分にある)。6時間ぐらい費やしてまだ半分イケたかイケてないかなのだが?! Ren'Pyの位置指定が意味わからんくて爆発した話とかアニメーションの話とかz-orderの話とかできていない……そのあたりこそ先にすべきでは?!
(気力が続けば)次回に続きます。生暖かい目で見守っていただけると嬉しいです。

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

記事のタグから探す

月別アーカイブ

限定特典から探す

記事を検索