上級編

上級編と銘打ったものの、実質は中級編までに説明出来なかった事の補足編とも言う



構造体の使い方

分かるまで大変だけど分かってしまえば便利な機能。色々応用が効くので説明していきます。
functionに無い単語を使いたい、あるいは普通では引き出せない情報を引き出したい、そんな時に構造体を使います。
例えば現在の自分のHPによって弾の性能を変化させたい、だけど自分のHPってどうやって参照すればいいの?という時。

C_GetCharacterFromObjNo(int obj_no)

スクリプトリファレンスにはこういうAPIが存在します。これは『キャラのオブジェクトナンバー』を入れると『そのキャラの構造体にアクセス出来る』というAPIです。
オブジェクトナンバーは中級編の最後で説明したchr_obj_noだったりblt_chr_noだったりするもので、構造体にはキャラのHPだったりEXPだったり色々な情報が詰まっています。

では試しにShotの中に前述のAPIを入れて、HPを参照してみます。

C_GetCharacterFromObjNo(int obj_no)

まず、キャラのオブジェクトナンバーを『int obj_no』のところに記入しなければいけないのですが、

Shot = function(self,chr_obj_no,chr_id,blt_type,px,py,vx,vy,vec_angle,power,frame)

Shotのfunctionの中には幸運にも『chr_obj_no』があります。これを記入すればあとはShotさんが勝手に自分のオブジェクトナンバーを入れてくれるので

C_GetCharacterFromObjNo(chr_obj_no)

これで準備はOKです。ではここからどうやって参照するかですが、まずはスクリプトリファレンスの『構造体』のところを見てみましょう

上の方にある type_session - キャラ情報構造体 ここから下にしばらくスクロールすると

short HP_c - 現在のHP

という文が見付かったかと思いますが、これがキーになります。
ちなみにshortやunsignedの部分はデータ型といってまあその辺りはググるかスルーかでOKです。使うのはリファレンスでいう青字の部分だけです(この場合はHP_c)。
C_GetCharacterFromObjNo(chr_obj_no)の後に.(ドット)を付けてさらにHP_cと続けて書くと、現在の自分のHPを参照出来ます。

C_GetCharacterFromObjNo(chr_obj_no).HP_c

こんな感じです。例えば自分の現在のHPが500なら上記の文も500をあらわし、HPが変わればそれに合わせて変わります。

if―endの使い方

これ絶対初級編でやっとくべきだったろ・・・と思いましたけど、まあ構造体の話出したのでちょうど良いからここに。

if ○○ == ×× then
	△△
end

if、endの基本形はこちらになります。これは『もし○○が××と同じなら、△△を実行』という感じの意味になっています。
例えば構造体の記述を持ち出してみましょう。

if C_GetCharacterFromObjNo(chr_obj_no).HP_c == C_GetCharacterFromObjNo(chr_obj_no).HP_m then
	△△
end

HP_mとは最大HPを参照する構造体です。この場合は『もし自分の現在のHPが自分の最大HPと同じなら、△△を実行』となります。
要するにHPがマックスの時だけ△△実行する、みたいな種類のものですね。
ちなみに何回もC_GetCharacterFromObjNoを書くのが面倒(というか何回も書くと見辛くなる)ならこんな感じの書き方も出来ます。

c = C_GetCharacterFromObjNo(chr_obj_no)
if c.HP_c == c.HP_m then
	△△
end

断然スッキリしましたね。これは『C_GetCharacterFromObjNo(chr_obj_no)をcと置く』といった感じで、何回も同じ記述をする時に短い単語に置き換えておくと便利です。
ここで注意したいのが、『置き換える時の=は1個、if文に使う==は2個』というところです。結構間違える事が多く、間違えたら当然エラーを吐くので気を付けましょう。

if文で==以外によく使うと思われる不等号

○○ >= ×× ○○が××以上
○○ <= ×× ○○が××以下
○○ ~= ×× ○○が××と同じでない(~は環境にもよりますが、シフトを押しながら^キーで出ます)
○○ > ×× ○○が××を越える
○○ < ×× ○○が××未満

if―elseの使い方、return falseについて

これも間違いなく上級編じゃないけど、まあifの話出したのでちょうど良いからここに。

if ○○ == ×× then
	△△
else
	▲▲
end

これは『もし○○が××と同じなら△△を実行するが、そうでないなら▲▲を実行する。』という意味です。
elseにはもう一つあり、

if ○○ == ×× then
	△△
elseif ○○ == □□ then
	▲▲
end

こういうものをあります。こちらは『もし○○が××と同じなら△△を実行するが、そうではなく○○が□□と同じなら▲▲を実行する。』といった具合。
注意としてifの中は上から順番に1度しか処理されないので、例えば『○○が××と同じで、なおかつ○○が□□とも同じ』場合は▲▲は実行されず△△だけが実行されます。

とまあ記号で説明しててもアレなのでluaを見てみましょう。今回は001_marisa、つまり公式魔理沙を使います。
開いたらblt1のShotの部分を見てみましょう。これは魔理沙の小弾3連の部分です。

	Shot = function(self,chr_obj_no,chr_id,blt_type,px,py,vx,vy,vec_angle,power,frame)
		if frame==0 then
			C_CreateBullet(BLT_PROC_TYPE_SCR_CHARA,chr_obj_no,chr_id,blt_type,1,px,py,vx,vy,self.add_vec_x,self.add_vec_y-4,self.hit_range,1,1)
			C_PlaySoundSE(self.se[1],0,0)
		elseif frame == 4 then
			C_CreateBullet(BLT_PROC_TYPE_SCR_CHARA,chr_obj_no,chr_id,blt_type,1,px,py,vx,vy,self.add_vec_x,self.add_vec_y,self.hit_range,1,1)
			C_PlaySoundSE(self.se[1],0,0)
		elseif frame == 8 then
			C_CreateBullet(BLT_PROC_TYPE_SCR_CHARA,chr_obj_no,chr_id,blt_type,1,px,py,vx,vy,self.add_vec_x,self.add_vec_y+4,self.hit_range,1,1)
			C_PlaySoundSE(self.se[1],0,0)
			return true
		end
		return false
	end,

早速elseifがありますね。詳しく見て行きましょう。

まずif frame == 0 then、これはframeが0の時、つまり0フレーム目に実行されます。小弾を1発出して発射音を出します。
そしてifはこれで終わりなのでendまで飛びます。するとその下にreturn falseがありますね?中級編のShotの説明でこんな事を書きました

return true   :Shotの処理を終わらせる。これが無いとShotの処理が終わらずループしてしまう。

trueではなくfalseが返った、あるいは何も返っていない場合は、Shotの処理が1度では終わらずに次のフレームでまた上から実行されます。つまり0フレーム目は弾と発射音を出してもう一度1フレーム目にShotを実行といった感じになります。
1、2、3フレーム目はifの条件に合わないので何も起こらず、falseが返ってくるのでまたShotが実行されます。
4フレーム目になるとまた弾と発射音が出ます。しかしここでもtrueは返っていないのでループします。
5、6、7フレーム目も同じく何も起こらずループ。
8フレーム目になると弾と発射音が出ますが、ここでreturn trueの文があるのでようやくtrueが返ります。ここでShotの処理が終わる訳ですね。

つまりまとめると、魔理沙の1番のShot内は
0フレーム目と4フレーム目と8フレーム目に弾を発射&SEを鳴らして、8フレーム目でtrueを返してShotの処理を終わらせる
といった感じになります。弾を複数出す場合の基本形がこの形ですね。

functionに無いものを呼び出す

それぞれのfunctionを比べると分かるかと思いますが、それぞれにあるもの、ないもの、名前の違うものが多々あります。
例えばOnFrameのfunctionは以下ですが

OnFrame = function(self,type,blt_no,frame,px,py,vx,vy,ex1,ex2)

OnFrameのfunction内にはキャラのオブジェクトナンバー(chr_obj_no等)を示すものがありません。つまりOnFrame内では一番上でやった方法では構造体から自分のキャラのHPを参照する事が出来ません。
ではどうするかというと、別のアクセス方法を使います。
上級編の頭では「type_session - キャラ情報構造体」を使ったと思いますが、キャラ以外にも弾、地面にも構造体が存在します。
そして弾の構造体はその弾のオブジェクトナンバーを使用します。今回においては「blt_no」がそれに当てはまります。

C_GetBulletInfo(int obj_no)

弾の構造体にアクセスするAPIはこちら。今回はblt_noを入れて

C_GetBulletInfo(blt_no)

自分のHPを参照するにはキャラの構造体にアクセスする必要があり、それにはキャラのオブジェクトナンバーが必要です。リファレンスを開いて弾の構造体をざっと見てみると

unsigned char chr_obj_no - 弾を発射したキャラのオブジェクト番号。

ありました。青字の部分を.(ドット)の後に繋げれば完成です。

C_GetBulletInfo(blt_no).chr_obj_no

これを

C_GetCharacterFromObjNo(C_GetBulletInfo(blt_no).chr_obj_no)

こう入れてやればキャラの構造体にアクセス出来るわけです。もちろんこんな書き方ではあまりに見辛すぎるので

b = C_GetBulletInfo(blt_no)
c = C_GetCharacterFromObjNo(b.chr_obj_no)
if c.HP_c == ~

こんな感じでしょうか。難しいですが使いこなせるとキャラ製作の幅がグンと広がります!

拡張情報を上手く使う

CreateBulletで作成された弾には拡張情報というものを使う事が出来ます。

C_CreateBullet(BLT_PROC_TYPE_SCR_CHARA,chr_obj_no,chr_id,blt_type,1,px,py,vx,vy,self.add_vec_x,self.add_vec_y,self.hit_range,1,1)

この最後1,1の部分です。この部分は弾のex1、ex2と言って、ここに数字を記憶させて後から引き出したり、別の数字を記憶させ直したりといった事が出来ます。例えば

C_CreateBullet(BLT_PROC_TYPE_SCR_CHARA,chr_obj_no,chr_id,blt_type,1,px,py,vx,vy,self.add_vec_x,self.add_vec_y,self.hit_range,chr_obj_no,1)

こうすると、作成された弾のex1に「キャラのオブジェクトナンバー」を記憶させておく事が出来ます。ここで何となく察しが付いたかもしれません。先ほどのOnFrameのfunctionを見てみましょう。

OnFrame = function(self,type,blt_no,frame,px,py,vx,vy,ex1,ex2)

このfunctionの最後のex1,ex2はそれぞれ弾のex1,ex2の事です。つまり、先にex1にキャラのオブジェクトナンバーを入れておけば弾の構造体からキャラのオブジェクトナンバーを~とやらなくても

C_GetCharacterFromObjNo(ex1)

ex1にキャラのオブジェクトナンバーが入っていればこれで出来てしまうんです。無論他にも様々な使い方があるので自分なりに活用法を見つけてみましょう。
色んなキャラのluaを覗いてみると面白いものが見付かるかもしれませんね。

ちなみに弾だけではなく、キャラにも拡張情報はあります。引き出す方法も記憶させる方法もそれぞれAPIとして存在します。

タグ:

+ タグ編集
  • タグ:
最終更新:2014年12月22日 12:00