MAGI JAVA -Make a game in Java-
JAVA Game作成講座 014回
会話 分岐イベント作成


kouza014 jarファイル


[今回追加したもの]
・会話イベントのアレンジ版、分岐イベントを作成

簡単にできると思ったら滅茶苦茶エラーに悩まされた。
所々変数をいじっている。

[EventExecutionクラス、eventblockのデータ入力から] if (evnum==1) {

datablock[0][0]=1;
datablock[0][1]=someData[0]; //オブジェから会話データを取り出す。
datablock[1][0]=999;


}
if (evnum==2) {

datablock[0][0]=2;
datablock[0][1]=someData[0];
datablock[0][2]=someData[1];
datablock[1][0]=3;
datablock[1][1]=3;
datablock[1][2]=5;
datablock[2][0]=1;
datablock[2][1]=2;
datablock[3][0]=999;
datablock[4][0]=1;
datablock[4][1]=3;
datablock[5][0]=999;


}

evnum==1のものは通常の会話イベント。
今回作ったのはevnum==2の分岐会話イベント。
どう違って、どう処理を変化させたのかをざっと説明する。
自作ツールの解説ばかりだが、
どこをどういじるとその処理ができるか、という勉強になる…と思う。

datablock[0][0]=2;
今回の新処理。
分岐つきの会話モードに入る。
会話ウィンドウを二つ表示し、うち一個の枠内でカーソルを表示。
上下で選択肢を選び、スペースで決定。
この時のカーソル位置を変数に記憶し、
それを元に次のイベントでphaseの流れを分岐する。


datablock[1][0]=3;
というのが、会話表示後に実行する分岐判定。
先ほどの処理で保存した変数=「決定したカーソル位置」を元に、
加算するphase値を変動させる。
一個目の選択肢は自動的にphase+1させる。
いわゆる通常の流れに入るパターン。

2個目の選択肢を選んだ場合は、
datablock[1][1]=3;
このデータを使用する。phaseを3プラスするわけだ。
1+3でphase4までスキップする。

datablock[4][0]=1;
datablock[4][1]=3;
phase4はおなじみの会話イベントを立ち上げる。
会話の中身は3番。
次に999イベントを実行してループを抜ける。
スキップ先にも終了イベントを配置しておくのがポイント。

3個目の選択肢を選んだらphase+5だが、今回は2択なので無視していい。
最大4択まで作れるようにしてある。
ドラクエ式のYES/NOイベントをこれである程度再現できるだろう。

一度作れば使いまわせるので便利だが、phaseの加算値はイベントごとに異なる為、
長く複雑なイベントを仕込んでいた場合は、適切な位置にスキップさせないとバグる。
文字にすると簡単そうだが、実際にコードを書いてみると意外にめんどくさい。

では、実際のコードをかいつまんで説明する。

public void eventSet() {

//今のフェーズのデータを切り出す。
int[] data=datablock[phase];
//一度だけ通る初期設定
switch (data[0]) {
case 1: //(001)会話イベント
talkEventSet(data[1],0);
break;
case 2: //(002)会話 分岐イベント
//dt1,bunkiKazu
talkBunkiEventSet(data[1],data[2]);
break;
case 3: //選択結果を元に処理をワープさせる。
bunkiResult(data);
break;
case 999:
eventEnd();
break;
default:
phasePlus++;
break;
}
count++;


}
public void eventStart() {

time++;
//実行する
if (eventMode==1) talkEventStart();
if (eventMode==2) talkBunkiEventStart();
if (phasePlus>=1) {
phase+=phasePlus;
phasePlus=0;
count=0;
eventMode=0; //モードはフェーズ切り替え時に一度リセットされる。
time=0;
}
if (time>=200) {
time=0;
}


}

eventSetの時点でeventModeを切り替え、
そのモードしか回さないように切り替えているのがポイント。
talkEventStart とは別の talkBunkiEventStart ループに流れを変えているのだ。
paint処理も同様にeventModeに合わせて切り替えている。

public void paint(Graphics gr) {

//gData=gdt;
g=gr; //eveExt内のGraphicsにARPanelのgをパスする
if (eventMode==1) talkEventPaint();
if (eventMode==2) talkBunkiEventPaint();


}

イベント処理ごとにモードが増えていくので、
100個イベントを作ったら100個モードが増えるかも…。
あまりいいやり方ではないかもしれないが、
イベントごとに処理を独立させているので、モードの把握さえできていれば
考える単位を最小限にできる利点がある。
あっちこっちいじくり回してどれがエラーの元か迷わなくても済む。

あまりにイベントが増えてスパゲッティプログラムになるようなら、
さらにクラスを分割することも考えられる。
真っ先に分けるのはdatablockの入力だけど…。

最後に分岐メッセージの関数のソースコードを書いておく。


//---------------------------------------------------------------------------
//(002) 分岐メッセージ。
//---------------------------------------------------------------------------
public void talkBunkiEventSet(int dt1,int bunkikazu) { //dt1,int dt2,int bunkiKazu) {

nowline=0;
eventMode=2;
talkText=tkData.talkGet(dt1);
nowline=0;
timeEnd=20;

endline=talkText.length;
cursorInit();
cursor[1]=0;
if (bunkikazu>=2) cursor[1]=bunkikazu-1; //[0]で現在のカーソル位置、[1]でカーソルの最大値を管理する。
waitTime=10; //キーの暴発を防ぐため、実行を少し遅らせる。
System.out.println("talkbunkieventset1");


}

大体の処理は会話イベントを流用している。
コメントにある通り、cursor[0]が現在のカーソル位置、cursor[1]がマックス値。
上下でカーソル値(cursor[0])が変化する。

public void talkBunkiEventStart() {

//PlayerPlatform pPlatform=gData.pPlatform;
int cursorPlus=0;
if (gData.pPlatform.keyPush[4]) {
gData.pPlatform.keyPush[4]=false;
selectKekka=cursor[0];
phasePlus++;
}
if (gData.pPlatform.keyPush[0]) {
gData.pPlatform.keyPush[0]=false;
cursorPlus=-1;
}
if (gData.pPlatform.keyPush[1]) {
gData.pPlatform.keyPush[1]=false;
cursorPlus=1;
}
if (cursorPlus!=0) {
cursor[0]+=cursorPlus;
if (cursor[0]<0) cursor[0]=cursor[1];
if (cursor[0]>cursor[1]) cursor[0]=0;
}


}

keyPushを取得することに代わっている以外は、マップ移動のキー取得と同じ。
pPlatform内ではキーを打つたびにwaitをかけている。
それがないと異様に早くカーソルが動き、
選択肢を決定後、描画する前に次のメッセージも終了してしまう。
waitの量はお好みで調整可能なので、実行しながら設定してほしい。

sursor[0]が下限か上限に達したらループするようにしてある。


public void talkBunkiEventPaint() {

//ここでは、分岐の選択肢だけ描画する。
//1ページ目にメッセージ、2ページ目が選択の種類最大4個を記憶してある。
int sx=64;
int sy=300;
gData.rectSet(g,sx,sy,672,130,1,200,1);
gData.wordDisp(g,talkText,0,8,sx,sy);

gData.rectSet(g,sx,sy+140,672,130,0,200,1);
gData.wordDisp(g,talkText,4,8,sx+24,sy+150);

gData.wordDisp_short(g,"→",sx+10,sy+174+cursor[0]*24);


}

描画処理。rectsetして、その上にwordDispするのは同じだが、
"メッセージ表示用"と"選択肢表示用"の2つぶんウィンドウを作っている。
そのため、メッセージを少し上にスライドし、元あった部分に選択肢のウィンドウを描画。
そして、カーソルとなる"→"を選択しの左側に表示している。
カーソルは現在のカーソル位置でy座標の表示位置が変わる。

この流れはもう少し後に作る予定のステータス画面でも流用する。
カーソルの移動や文字、ウィンドウの出し方はほぼ同じ。
違いはそこに出るメッセージが大半固定というくらい。

//---------------------------------------------------------------------------
// (003) 選択結果により処理を分岐させる。処理のスキップですね。
//---------------------------------------------------------------------------
public void bunkiResult(int[] dt) {

//dt[1]-[2]に、スキップするフェーズ数を入力していること。
phasePlus=1;//選択が1の場合はそのまま進ませる。
if (selectKekka>=1) {
phasePlus=dt[selectKekka];
}


}

"selectKekka"はtalkBunkiEventStart関数でキープした変数。

だんだん説明が端折られていくが、あとで気がついたら追加する。

次は何から手を付けようか…。
RPGとして成立させるには足りないものがある。
・ステータス
・ステータス表示、装備などのモード
・セーブとロードもステータス画面に含める
・アイテム購入する店
・イベントでアイテム取得
・戦闘イベント

という感じだろうか。
この中で真っ先に必要なのは、ステータスだ。
ステータスが無いと戦闘も買い物も何もできない。
装備もできない。ステータスにはお金も含まれる。

というわけで、次はプレイヤーユニットにステータスをつける。
LV,経験値,HP,攻撃力,というやつだ。
それと並行して、ステータスの表示も手を付ける。
セットしたデータが本当に入っているかどうかを見るためだ。
装備、アイテム使用などは後で付ければいい。

まとめると、 ・ステータスをざっと決める。
・ステータスウィンドウを開いてステータスを見れるようにする。
この二つを作る予定。

・トップページへ戻る
inserted by FC2 system