ジェリーゼリーブログ

2018年11月7日

ティラノスクリプトで釣りのミニゲームを作ってみた

ティラノスクリプトでシンプルな釣りゲームを作ってみました。
サンプルデータも配布してますので、よかったらミニゲームを作る参考にしてみてください~。

注意:私は「とりあえず動けばいいや!」という考えでスクリプトを書いてるので、処理が重いとか軽いとか速いとか遅いとか、スクリプトが読みやすいとか読みにくいとか、一切考えていません。


目次


どんなゲーム?

釣り糸を垂らして魚がかかるのを待ち、魚がかかったら(水しぶきがたったら)素早くクリックして魚を釣る、シンプルな釣りのミニゲームです。
魚がちゃんとかかる前にクリックすると逃げられます。
また、魚がかかってからクリックするのが遅すぎても、逃げられます。

→ ブラウザで動くサンプルゲームをプレイする

※ GoogleChromeでのみ動作確認済み

▲上に戻る


サンプルデータのダウンロード

サンプルゲームのデータ(画像ファイルとシナリオファイル)を配布中です。
※ ティラノビルダーでの使用は想定されていません。

■動作方法
 1 ティラノスクリプトのdataフォルダに、このサンプルデータのデータをコピーします。
 2 first.ksなどから「fish.ks」にジャンプする記載を追加します。
 3 ティラノライダーで起動します。
このサンプルデータ単品では動作しません。
ティラノスクリプト公式サイトからティラノスクリプトをダウンロードしてお使いください。

■動作確認をした環境
 ・OS: Windows10 / Android4.4
 ・ブラウザ: GoogleChrome

■使用したティラノスクリプト: ver472

→ サンプルデータのダウンロード

▲上に戻る


ざっくりとした仕組みの説明

サンプルデータに入ってる「fish.ks」の流れを簡単に説明するとこんな感じです。

「fish.ks」はティラノスクリプトの標準タグばかりで書かれたスクリプトです。
そんなに難しい処理はしていない…と思います。

▲上に戻る


詳しい説明

「fish.ks」の上から順番に説明していきます。なお、画面サイズは「960×640」です。

1 いろいろ定義する(10行目あたり~)
;まず色々定義をします

;魚が暴れるキーフレームアニメを定義
[keyframe name="fishact"]
    [frame p=0% x=20 y=20]
    [frame p=50% x=10 rotate="10deg"]
    [frame p=100% x=-10 rotate="-10deg"]
[endkeyframe]

;定数の定義
;魚タイプ(配列番号が画像の番号に該当 / 0:小タイプ / 1:中タイプ / 2:大タイプ)
@eval exp="f.FISH_TYPE=[0,0,0,0,1,1,1,2,2,2]"

;魚の名前(配列番号が画像の番号に該当)
@eval exp="f.FISH_NAME=['青の小魚','緑の小魚','黄色の小魚','ピンクの小魚','青の中魚','黄色の中魚','赤の中魚','水色の大魚','黄緑の大魚','赤の大魚']"

;小タイプ(簡単)の待ち時間
@eval exp="f.EASY_TYPE=1200"

;中タイプ(普通)の待ち時間
@eval exp="f.NORMAL_TYPE=900"

;大タイプ(難しい)の待ち時間
@eval exp="f.HARD_TYPE=700"

まず魚がかかって暴れてる時のキーフレームアニメ「fishact」を定義しときます。一応ばたばた動く感じに作ってます。

次に定数の定義をします。
f.FISH_TYPEは各魚のタイプ(大きさ)を配列で決めます。
0が小魚、1が中魚、2が大魚ということにしています。
サンプルデータのimageフォルダに入っている魚の画像ファイルの名前は「0.png」「1.png」…と数字のファイル名になっていて、 配列番号と連動しています。
つまり、f.FISH_TYPE[0]に「0.png」の魚のタイプの数値が入るように、配列で定義します。
f.FISH_NAMEも同様に、f.FISH_NAME[0]に「0.png」の魚の名前が入るように定義します。

配列についての説明を見る

配列というのは、複数のデータを持つ変数です。
f.NAME = ['イルカ','ペンギン','アシカ']
のように、[]の中でカンマで区切って複数のデータを定義できます。
各データには左から順に番号が振られます。番号はゼロから始まります。
上の例では、
f.NAME[0]が'イルカ'
f.NAME[1]が'ペンギン'
f.NAME[2]が'アシカ'、となります。
また、f.NAME.lengthと書くと配列のデータの数を表します。
上の例ではデータが3つあるので、f.NAME.lengthは3になります。

f.EASY_TYPEf.NORMAL_TYPEf.HARD_TYPEは魚がかかってから逃げるまでの時間を定義しています。
数字が大きいほど、逃げるまでの時間が長いので、釣りやすくなります。
ミリ秒単位なので1000で1秒です。
なんとなく小さいほど釣りやすい=逃げるまでの時間が長い、という設定にしてあります。


2 メイン画面を表示する(37行目あたり~)
*main
;メイン画面
[wait_cancel]
[clearstack]
[cm]
[freeimage layer=0]
[freeimage layer=1]
[layopt layer=0 visible=true]
[layopt layer=1 visible=true]
[layopt layer=message0 visible=false]

;空を表示(背景)
[bg storage="sky.png" time=0]

;水を表示(レイヤー1)
[image layer=1 storage="sea.png" folder="image" x=0 y=290]

;タッチボタン
[clickable target="*start" width=960 height=640 x=0 y=0]

[s]

背景レイヤーに空の画像(sky.png)を表示し、レイヤー1に水の画像(sea.png)を表示しています。
水の画像はアルファ付きPNGで、あらかじめ半透明にしたファイルを用意します。
これはレイヤー0に魚影や釣り糸の画像を表示したとき、見えるようにするためです。

clickableタグでゲーム画面全域にクリック判定用のボタン的なやつを作っておきます。
これでゲーム画面のどこかをクリックすればラベル*startにジャンプし、釣りが開始します。


3 糸を表示して、水の中に垂らす(60行目あたり~)
*start
;釣りをスタートする
[wait_cancel]
[clearstack]
[cm]
[freeimage layer=0]
[free name="effect" layer=1]

;糸を垂らす準備
@eval exp="f.tutu=0"
@eval exp="f.hit=0"
@eval exp="f.tutumax=Math.floor(Math.random()*4)"

;糸を表示(レイヤー0)
[image name="line" layer=0 storage="line.png" folder="image" x=470 y=-430]
[anim name="line" top="+=390" time=200]
[wait time=200]

;タッチボタン
[clickable target="*up" width=960 height=640 x=0 y=0]


*wait
;魚が来るまで待つ
@eval exp="tf.ran=Math.floor(Math.random()*1000)+500"
[wait time="&tf.ran"]

「糸を垂らす準備」のあたりで定義している変数は、ぶっちゃけ糸とあんまり関係ないんですが、 f.tutuが魚がつついた回数、f.hitが現在の魚の状況、f.tutumaxが魚がつつく回数、を表す変数になっています。
f.tutuは後のラベル*fish_poke(116行目あたり)で魚が釣り針をつつく度にプラス1されていく変数です。ここでは0と定義しておきます。
f.hitは現在の状況を表していて、0は魚がいない状況、1は魚がいるけどまだ釣り針にかかっていない状況、2は魚がかかってる状況、を表すことにしています。ここでは0を定義します。
f.tutumaxは魚が釣り針をつつく回数を表していて、ここでは「0~3」の乱数を振っています。
後のラベル*fish_pokef.tutumaxの数だけ釣り針をつついたら、魚がかかるようにします。

乱数についての説明を見る

ここではJavaScriptのMath関数を使って乱数を振っています。
Math.floor(★)と書くと、★の部分に書いた数値を整数にしてくれます。
Math.random()は0以上1未満の乱数を振ります。
例えば、
tf.ran = Math.floor(Math.random()*4)
とすると、0~3の整数の乱数をtf.ranという変数に代入することになります。
ちなみに、
th.ran = Math.floor(Math.random()*4)+1
とすると、1~4の整数の乱数をth.ranに代入します。

「糸を表示」のあたりではimageタグで画面外(表示範囲より上)に釣り糸の画像を設置し、 animタグで上から下に降ろします。

またclickableタグでゲーム画面全域にクリック判定用のボタン的なやつを置きます。
今度はクリックしたら後ろの方のラベル*up(170行目あたり)という釣り上げて結果を表示するラベルにジャンプさせます。
釣りに成功したか否かの判定はジャンプ先のラベル*upの方で行います。

そしてclickableタグの後、いつもの[s]ではなく、waitタグを書くのがポイントです。
このwaitタグで設定した時間が経過すると、次のラベル*fish_showに行き、魚が表示されます。 時間が経過する前に画面をクリックするとラベル*upにジャンプし、まだ魚が出現していないので「何も釣れなかった…」と表示されます。また、ラベル*upの最初の方にwait_cancelタグを書いておくのも大事なことです。

今回のように、選択肢(clickableタグも含む)を表示した時、[s]で止めずにwaitタグで制限時間を設ける場合、ジャンプ先でwait_cancelタグを書いておくのが重要みたいです。

尚、ここでは、糸を垂らしてから魚が表示されるまでの時間にランダム要素を持たせるために、乱数を使用しています。
ちなみにティラノスクリプトのタグのパラメータには先頭に&を付けることで変数を使用できます。


4 魚が表れて釣り針の付近まで来る(88行目あたり~)
*fish_show
;魚が来る準備
@eval exp="f.hit=1"

;魚の種類を決める乱数
@eval exp="f.number=Math.floor(Math.random()*f.FISH_TYPE.length)"

;魚の大きさ判定
;---小タイプ:簡単
[if exp="f.FISH_TYPE[f.number]==0"]
    [eval exp="f.type='fish1.png'"]
    [eval exp="f.wait=f.EASY_TYPE"]
;---中タイプ:普通
[elsif exp="f.FISH_TYPE[f.number]==1"]
    [eval exp="f.type='fish2.png'"]
    [eval exp="f.wait=f.NORMAL_TYPE"]
;---大タイプ:難しい
[else]
    [eval exp="f.type='fish3.png'"]
    [eval exp="f.wait=f.HARD_TYPE"]
[endif]

;魚を表示(レイヤー0)
[image layer=0 name="fish" storage="&f.type" folder="image" x=-80 y=360]
[anim name="fish" left="+=405" time=1000]
[wait time=1000]

「魚が来る準備」でf.hitを1を代入しています。
f.hitが1の時は「魚が表示されている状態」を表すことにしています。

「魚の種類を決める乱数」では、今から表示される魚の種類を決定するために、f.numberに0~9の乱数を代入しています。 f.FISH_TYPE.lengthf.FISH_TYPEが持っているデータの数を表します。ここではf.FISH_TYPEは10個のデータを持っていますので、10ということになります。
これは魚の種類と同じ数になっているはずですので、魚の種類の数の範囲内で乱数を振ることになります。 このf.numberという変数は、後で魚の画像ファイル名を設定する際にも使用します。

「魚の大きさ判定」では、f.numberに代入された魚の種類を表す数値と、配列変数のf.FISH_TYPEを使って魚のタイプを判定します。 0であれば小タイプなので、魚影の画像ファイル名を代入するf.typeに該当するファイル名「fish1.png」を代入し、魚がかかってから逃げるまでの時間を表すf.waitには定数のf.EASY_TYPEを代入しています。
中タイプ、大タイプの同様の処理をします。

「魚を表示」で、今の判定で決まった魚影の画像ファイルを、imageタグanimタグを使って表示させます。


5 魚が釣り針をつつく(116行目あたり~)
*fish_poke
;魚の行動を待つ
@eval exp="tf.ran=Math.floor(Math.random()*1000)+500"
[wait time="&tf.ran"]

;魚がつつく
[anim name="fish" left="+=70" time=300]
[wait time=300]

;f.tutumaxの数だけ繰り返しつつく
[if exp="f.tutu>=f.tutumax||f.tutu>=5"]
    [jump target="*hit"]
[else]
    [eval exp="f.tutu+=1"]
    [jump target="*fish_back"]
[endif]

[s]

表示された魚は「魚の行動を待つ」で1~1.5秒くらい待機したあと、「魚がつつく」のanimタグで釣り針に近づきます。

その後のif構文で、つついた回数であるf.tutuが、f.tutumax以上になったら(もしくは5以上になったら)、ラベル*hitにジャンプして、魚がかかった時の状況になります。f.tutuの回数がf.tutumaxより少なければ、f.tutuをプラス1し、ラベル*fish_backにジャンプして、魚が一旦釣り針から離れる処理をします。


6 魚が少し離れる(136行目あたり~)
*fish_back
;魚が離れる
[anim name="fish" left="-=70" time=300]
[wait time=300]
@jump target="*fish_poke"
[s]

animタグを使用して、魚が釣り針から少し離れる処理をします。
その後、ラベル*fish_pokeに戻って、また釣り針に近づきます。上述のように、ラベル*fish_pokeでは魚がつついた回数であるf.tutuが一定以上になると、ラベル*hitにジャンプして魚がかかった状態に移行します。


7 魚が食いつく(144行目あたり~)
*hit
;ヒットした!
[kanim name="fish" keyframe="fishact" time=200 count="infinite"]
[anim name="line" top="+=20" time=200]
[image layer=1 name="sibuki" storage="hit.gif" folder="image" x=330 y=250]
@eval exp="f.hit=2"
[wait time="&f.wait"]

;時間オーバーで逃げられる
[cm]
@eval exp="f.hit=1"
[free layer=1 name="sibuki"]
[stop_kanim name="fish"]
[anim name="fish" left="-90" time=500]
[wait time=500]
[freeimage layer=0]

;逃げられたメッセージ表示
[ptext layer=1 name="effect" text="逃げられた…" width=960 x=0 y=200 size=28 align=center color="black"]

;タッチボタン
[clickable target="*start" width=960 height=640 x=0 y=0]

[s]

「ヒットした!」では、まず、kanimタグでスクリプト冒頭で定義したキーアニメ「fishact」を呼び出して、魚がかかって暴れだすアニメーションの処理をしています。imageタグで水しぶきの画像も表示します。ちなみに水しぶきの画像はGIFアニメです。

そして、f.hitに2を代入して、魚がかかっている状態であることを表します。

さらに、ラベル*fish_showで定義したf.waitの秒数だけ、待機します。
この待機時間内に画面をクリックすれば、ラベル*upにジャンプして魚を釣り上げる処理をします。
時間内にクリックされなければ、そのまま進んで「時間オーバーで逃げられる」処理に移ります。

「時間オーバーで逃げられる」では、まず[cm]で画面クリック判定用のclickableボタンを削除します。そしてf.hitに1を代入し、もう魚がかかっている状態じゃないことを表します。
あとはfreeタグで水しぶきを消したり、stop_kanimタグanimタグで魚が左側に逃げて消える処理をしたりして、魚に逃げられたことが視覚的にわかるようにします。
「逃げられたメッセージ表示」ではptextタグで「逃げられた…」という文章を表示します。
そして、clickableタグでラベル*startに戻るための画面クリック判定用のボタン的なのを置いておきます。


8 釣り上げる&結果表示(170行目あたり~)
*up
;糸を引く
[wait_cancel]
[free layer=1 name="sibuki"]
[anim name="line" top="-=150" time=200]

[if exp="f.hit==2"]
;---魚釣り成功の場合
    [stop_kanim name="fish"]
    [anim name="fish" top="-=130" time=200]
    [wait time=500]
    [freeimage layer=0]
    [ptext layer=1 name="effect" text="お魚ゲット!!" width=960 x=0 y=30 size=50 align=center color=black]
    [image layer=1 name="effect" storage="&f.number+'.png'" x=405 y=200]
    [ptext layer=1 name="effect" text="&f.FISH_NAME[f.number]" width=960 x=0 y=370 size=40 align=center color=black]

[elsif exp="f.hit==1"]
;---逃げられてしまう場合
    [stop_kanim name="fish"]
    [anim name="fish" left="-90" time=500]
    [wait time=500]
    [freeimage layer=0]
    [ptext layer=1 name="effect" text="逃げられた…" width=960 x=0 y=200 size=28 align=center color="black"]

[else]
    [freeimage layer=0]
;---まだ魚が来ていなかった場合
    [ptext layer=1 name="effect" text="何も釣れなかった…" width=960 x=0 y=200 size=28 align=center color="black"]

[endif]

;タッチボタン
[clickable target="*start" width=960 height=640 x=0 y=0]

[s]

このラベル*upは釣り糸を垂らした状態で画面をクリックした時の処理がまとめて書いてあります。
まず、waitタグを放置してこのラベルにジャンプしてくると思うので、最初にwait_cancelタグを書いておきます。 そして、freeタグで水しぶきを消して、animタグで釣り糸を上に移動します。

f.hitの数値によって、if構文で違う処理を行います。

まずf.hitが2の場合は、魚がかかってる状態なので、「魚釣り成功の場合」の処理を書いています。
stop_kanimで暴れる魚のアニメーションを停止して、animタグで釣り糸と同様に上に移動します。
このアニメの終了をwaitタグで待った後、freeimageタグでレイヤー0(釣り糸と魚影の画像)を削除して、ptextタグimageタグでゲットした魚を表示します。
この時、魚の種類を表すf.numberの数値が、魚の画像ファイルと同じなので、画像ファイル名として使います。&f.number+'.png'と書けば、例えばf.numberが3の時は「3.png」がstorageパラメータに入ることになります。
また、冒頭で定義したf.FISH_NAMEを使って、ptextタグで釣った魚の名前を表示します。 例えばf.numberが3の時は、&f.FISH_NAME[f.number]f.FISH_NAME[3]なので、ptextタグのtextパラメータには「ピンクの小魚」が入ることになります。

f.hitが1の場合は、魚が表示されてるけどまだ食いついていない状態ですので、「逃げられてしまう場合」の処理を書いています。
stop_kanimタグで暴れる魚のアニメーションを止め、animタグで魚を左の画面外へ移動させ、waitタグでアニメが終わるのを待ったらfreeimageでレイヤー0(釣り糸と魚影の画像)を消し、ptextタグで逃げられたことを文章で表示します。

elseの場合、f.hitが2でも1でもない、つまり0の場合は、釣り糸は垂れてるけどまだ画面に魚が表示されていない状態なので、「まだ魚が来ていなかった場合」の処理を書きます。
といってもptextタグで何も釣れなかった旨を表示するだけです。

if構文endifで閉じた後は、共通の処理として、 clickableタグで画面クリック判定用のボタン的なやつを置いておきます。これで、クリックするとラベル*startにジャンプして、また釣りが始まります。 ジャンプ先のラベル*startでは、freeタグで文章や魚の画像を消す処理を書いています。「お魚ゲット!!」といった文章や魚の画像はnameパラメータを「effect」、layerパラメータを1、で統一しているので、[free name="effect" layer=1]と書くだけで結果表示はつるっと消えます。

詳しい説明は以上です。

▲上に戻る


サンプルデータの利用規約(2018/11/7版)

このサンプルデータは、ティラノスクリプトでのミニゲーム製作の際の参考資料となることや、データを加工・編集してからゲームに組み込まれることを想定して配布しています。

OKなこと
  • 「このサンプルデータを元にしたミニゲーム」を組み込んだゲームを、公開したり販売したりすること。
  • 画像データやシナリオデータを加工したり編集したりして使用すること。

禁止事項
  • サンプルをそのままの状態で再配布したり販売したりすること。
  • サンプルを全くそのままの状態で組み込んだだけのゲーム(この記事で公開中のゲームと全く同じ内容の物)を、公開したり販売したりすること。
  • サンプルの自作発言。
  • 違法性のある作品での使用。

ご注意
  • 本サンプルデータを使用したことで発生したいかなる問題に対しても、製作者は一切の責任を負いかねます。

補足
  • この利用規約を守っていただければ、無料でお使いいただけます。
  • 年齢制限のある作品でも使用可能です。
  • 利用報告は不要です。
  • クレジット表記は任意です。
  • 利用規約の内容は予告なく変更する場合があります。
  • ご不明な点は下記の連絡先にお問い合わせください。

連絡先(Twitter):@jellyjellynews

▲上に戻る


…以上です。思っていたよりめちゃくちゃ長くなってしまいました。
サンプルデータのバグや不明点については、お問い合わせいただければ答えられる範囲でお答えます。 ただ、私自身、あんまり詳しくないのと、いろいろ勘で書いてるせいで言語化して説明するのが下手ということもあって、ちゃんと解決できるかどうかはわかりません…申し訳ないです。


カテゴリ:製作者向け情報/ティラノスクリプト関係