HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2009
0816
centerスクリプト化して効率的にノベル的な物を作成したい5解決


center

リンク

2009/8/16(Sun) 02:15:41|NO.27098

・・・タイトルではあまり分かりづらかったでしょうか?
えっと、、今ノベル的な物を作ってるのですが、
スクリプト(HSPの)内にメッセージやらコマンドを入れてるのですが、
流石に非効率なので、外部にスクリプトファイル的な物を作成し、
その中にコマンドやらメッセージやらを格納して実行したいんです。

で、そのコマンドとかについてどうやったら効率的にできるか、
また、そのコマンドなどをプログラム内で処理する仕方など教えて下さい。

・・・って分かりにくいですよね。。
まず最初にコマンド自体を作らないといけないのですが、
どうやったら効率的に出来るかわからないんですよね。。

私が考えたのは、HTMLみたいに”<”や”>”で記述する方法で、
例えばメッセージを表示する場合は、

<1 mode="mes" name="キャラ名"> メッセージ </1>
って感じなんですけども、どうも非効率な感じなんですよね。。
まず1って言うのはセーブなどの関係でロード時に開始する場所を区別するための番号(?)です。
”mode”は何を処理するかを記述する項目です。ここではmes(メッセージ表示)としてます。
”name”はメッセージに表示するキャラクター名を記述する項目です。

で、またこれをプログラム内でどういう風に処理すれば良いのかもイマイチ分からないんですよね。
私はひとつひとつ検索していく方法しか思いつかないのですが(汗)
もっと効率的に出来る方法は無いんでしょうか?

色々質問しちゃってますが、よろしくおねがいします。
結構分かりにくいところがあると思うんで、あったら教えてください。
すみません。



この記事に返信する


shinkun

リンク

2009/8/16(Sun) 10:18:50|NO.27101

ノベルゲームで HTML 風の書式は確かに非効率ですね。
スクリプトを記述する側からにしても、スクリプトを解析する側からにしても。


1.効率的なスクリプトの書式

ノベルゲームでは、スクリプトの記述量が多いので簡潔に記述出来る書式を最優先します。これを意識しつつ、解析も簡単に出来る書式を考えると、HSP が採用している命令の書式が最も適していると思います。

mes "脇役A", "おらー、テレビ欲しいちゃけんどん。良い電気屋知らんかー?" mes "脇役B", "そんなら、吉村生協プロパンがいいっちゃが。"
ただし、":" 区切りで 1 行に数命令書けるようにはしないようにしましょう。解析が面倒になります。
これなら一行一命令で、命令名が先頭に来るので必要な引数の数も分かり、解析が簡単になります。

この書式では、center さんが考えていらっしゃるセーブ番号が明記されていませんが、一行毎に命令が書かれている関係上、行番号をセーブ番号にすることが可能です。もちろん、center さんの HTML 風の書式でも同様の事は可能です。
書かなくて済む物は書かないようにする。そうすると記述する側も解析する側も幸せになれます。


2.解析&実行

上記の書式のスクリプトを解析&実行する場合、まず始めに用意しなければならないのは、現在どの行を実行しているのかを表す変数です。プログラムカウンタ pc と呼ぶ事にしましょう。実行時には pc が指す行のコードを拾ってきて、これを解析し、その結果に沿って処理を行います。

sdim script, 10240 notesel script noteload "script.txt" pc = 0 ; 0 行目から開始 *main noteget code, pc ; 命令を読み込む gosub *analyze_and_run ; 解析&実行 pc++ ; 一命令が済んだら次の行へ... gosub *wait_for_click ; クリックがあるまで待機 goto *main
*analyze_and_run の中では、code を先頭から調べていって命令名を取得し、命令名に応じて引数を取得、それらの引数を利用して適切な処理を行うようにします。


以上の事は、要点のほんの一部です。しかし、最も大事な部分です。実際に実用出来る代物にするには、様々な機能拡張が必要になりますし、上記のコードも大改造を要します。
例えば、条件判断と(HSP でいう)ラベルへのジャンプ機能は、フラグの状態に応じて処理を分けたり、選択肢を実装するのに必要になります。
フラグを設定するだけの命令など、命令によっては、ユーザーがクリックするまで待機して欲しくない場合があるので、コードの構造を変更する必要も出て来ます。

道のりは長いですが、頑張って下さい!!



Ve

リンク

2009/8/16(Sun) 10:42:33|NO.27104

@会話,キャラのID
表示するメッセージ
@終了

自分は上記のような記述をスクリプトの仕様としました。

まずスクリプトをテキストか何かで書く。
ファイルを読み込みメモリに格納。
1行ずつ読み出す。
getstrで , の区切りを検索。
スクリプトの命令と一致すればそのスクリプトをプログラム上で実行。


sdim buf ;スクリプトファイル読込 buf(0)="@会話,0" buf(1)="表示するメッセージ1" buf(2)="@終了" buf(3)="@会話,1" buf(4)="表示するメッセージ2" buf(5)="表示するメッセージ3" buf(6)="@終了" buf(7)="@会話,2" buf(8)="表示するメッセージ4" buf(9)="@終了" buf(10)="@会話,1" buf(11)="表示するメッセージ5" buf(12)="@終了" ;読み出す行数の初期化 l=0 *メイン ;行数より多かったらSTOP if l>=length(buf) : stop ;スクリプト読み出し goto *スクリプト読込 wait 1 goto *メイン *会話 c=0 getstr s,buf(l),0,',' : c+=strsize ;実行停止 if s="@終了"{ l++ goto *メイン } ;キャラクター0(キャラクターなし) if chara_ID=0 { mes s } ;キャラクター1 if chara_ID=1 { mes "○<"+s } ;キャラクター2 if chara_ID=2 { mes "■<"+s } ;キー入力待ち repeat stick key if key!=0 : break wait 1 loop ;行を進める l++ goto *会話 *スクリプト読込 ;1行の中から命令を見つける c=0 getstr s,buf(l),0,',' : c+=strsize ;会話,キャラID(顔なんかの表示) if s="@会話"{ getstr s,buf(l),c,',' ;キャラID chara_ID=int(s) logmes ""+chara_ID ;行を進める l++ ;会話処理へ goto *会話 } goto *メイン

ノベルであれば、ラベルなどの飛び先を用意したり色々あるでしょうな。



ANTARES

リンク

2009/8/16(Sun) 15:07:51|NO.27117

 ノベル開発ツールを作ろうとでもいうのでない限り、スクリプトにするのは
効率も悪いし、開発もたいへんですし、何よりスクリプトの入力が面倒です。

>まず1って言うのはセーブなどの関係でロード時に開始する場所を区別するための番号(?)です。
 これは不要です。
 シーン番号を宣言するコマンド(mode)を設けましょう。

>”mode”は何を処理するかを記述する項目です。ここではmes(メッセージ表示)としてます。
 コード化しましょう。

>”name”はメッセージに表示するキャラクター名を記述する項目です。
 これもコード化しましょう。

 問題はメッセージですが、究極的にはこれもコード化した方がいいです。
これですべてをコード化できたので、さらにバイナリ化すれば
読み込みは配列にbloadするだけで終わりです。

 ファイルの作成は、専用のスクリプトを作り、
script(0,0)=5,2,3,4
script(0,1)=6,2,2,1



bsave file,script

 これではあまりにもわかりにくいので、入力ツールを作るのが理想ですが、
時間の余裕がなければCSVファイル(カンマ区切りのテキストファイル)を
読んでbsaveするスクリプトを書くといいでしょう。
でも、CSVファイルにするなら、結局、メッセージ以外はコード化することに
なると思います。
入力が面倒なので。

 メッセージ以外のコード表はスクリプト内に持てばいいでしょうが、
メッセージのコード表は、改行区切りのファイルとしてnoteloadで読み込むのが
最初に思いつくことです(メッセージ内の改行は「@@」とか「||」とかにして
notegetの後で置換する)しかし、……

 問題はメッセージの持ち方ですが、配列にすると、1要素の長さを
最大のものに合わせなければならないので、究極的にはすべての
メッセージを1つの巨大文字変数に入れるのが最も効率的です。
オフセット(開始位置)をメッセージコードとします。
この場合はメッセージ内の改行は改行コードがそのまま使えます。
メッセージ間の区切りはやはり「|」「@」「`」あるいはバイナリの1とかにします。
getstrで取り出すと、改行コードまでしか取り出してくれないので、
拙作anthspex.dllのdivide命令を使うといいかもしれません。
やはり、読み込みはbload一発で終わりです。
ファイルの作りやすさを考えると、空行を区切りとしてもいいでしょう。
この場合はinstrで"\n\n"を検索してstrmidで取り出します。

 すべてのメッセージを読み込むのが非現実的な場合は
bloadのオフセット機能を使い、bloadのオフセットをメッセージコードとします。
メッセージ単位で読むのが非効率だと思うなら、シーンごとにまとめて
読むことも考えられます。
シーン単位メッセージ群のオフセットと全体の長さを持つシーンテーブルで管理します。
これも配列にbloadするだけです。

 コマンド(mode)別の分岐はラベル配列を使えば「gosub label(script(0,iScript))」と
書けます。iScriptは現在何番目のスクリプトを実行中かを示す変数です
script(0,iScript)がコマンドコードですが、command(iScript)のように
分けることもできます。
例えばこれの値が1ならlabel(1)がコマンド1の分岐先ラベルです。



ANTARES

リンク

2009/8/16(Sun) 15:21:40|NO.27118

> 問題はメッセージの持ち方ですが、配列にすると、1要素の長さを
>最大のものに合わせなければならないので
 あれ? これはHSP3にはあてはまらないんでしたっけ?



ぴっくる

リンク

2009/8/17(Mon) 23:13:23|NO.27140

NScripter使うほうがいいかも



ONION software Copyright 1997-2023(c) All rights reserved.