フワフワソが「ソラとピヨちゃん」や「宮本県」を作るブログ(フワフワソ・ラウンジnew!)

ラノベとテクノを愛するふわふわがノベルゲームを作っています。あと日常のことやイベントの告知なども。スクリプト関連の記事は自分用の備忘録です

キーフレームアニメでイージングを自作する

RPGでよくあるダメージ表示をしたいなと思いました。

敵を殴るとダメージ数値が出てバウンドして消えるあれです。

まずキーフレームアニメでやろうと思いました。

kopacurve.blog.fc2.comこ・ぱんだ様のプラグインがとても便利なので、そういう動きがあるかなと思ったのですが、ないようです。

ソースを拝見すると改造OKと書いてありましたので、このプラグインをもとに改造させていただくことにしました。ありがとうございます。

作ったのがこちら。

[keyframe name="float_ability"]
[frame p=" 0%" y=" 0"]
[frame p="100%" y="-100"]
[endkeyframe]

 

[macro name="ability"]
[eval exp="mp.layer = '0'" cond="mp.layer == undefined"]
[eval exp="mp.time = 1500" cond="mp.time == undefined"]
[kanim name="&mp.name" layer="&mp.layer" keyframe="float_ability" easing="cubic-bezier(.38,1.37,.99,1.09)" time="&mp.time" count="1"]
[layopt layer="&mp.layer" visible="true"]
[endmacro]

キーフレーム名が float_ability

マクロ名がabilityです。

上記の設定をしてから、

[ptext layer=11 text="test" x=360 y=360 size=100 name="abilitypt" time=0 wait=false]

[ability layer=11 name="abilitypt" time=300]

このように記述すると、レイヤー11でabilityptという名前を付けたptextの文字が300ミリ秒でアニメします。

 

 ポイントはまずここ。

[frame p=" 0%" y=" 0"]
[frame p="100%" y="-100"]

キーフレームアニメの設定のところで、時間経過100%(この場合はマクロで設定した300ミリ秒)のところで、y方向に-100ピクセル移動、としておきます。とても単純です。

次に、バウンドしたりする複雑な動きは、マクロの方のeaseの設定でやります。

[kanim name="&mp.name" layer="&mp.layer" keyframe="float_ability" easing="cubic-bezier(.38,1.37,.99,1.09)" time="&mp.time" count="1"]

kanimにはeaseの設定があって、これで結構複雑な動きができると思いました。

こんな感じの↓

https://easings.net/ja

さっそくバウンドするようなイージングを使おうと思いました。

ところが、やってみてもうまくいきません。

よくよく見ると、ティラノのkanimには、基本的なイージングしか実装されてないようです。(kanimではなく、animのほうにはもっと種類があるのですが)

指定できる値としてease(開始時点と終了時点を滑らかに再生する) linear(一定の間隔で再生する)ease-in(開始時点をゆっくり再生する)ease-out(終了時点をゆっくり再生する)ease-in-out(開始時点と終了時点をゆっくり再生する)

困った・・。のですが、先を読むと、

 この他に、cubic-bezier関数を使って、イージングを独自に設定することも可能です

 というわけで、こちらのサイトを参考に、バウンドする動きを作ってみました。

cubic-bezier.com

その結果が easing="cubic-bezier(.38,1.37,.99,1.09)" です。

 

あとは、自動的に数字が消えるアニメを実装したいなと思います。

 

・バウンドと同時に透明から現れていく例

[keyframe name="float_ability"]
[frame p=" 0%" opacity=0]
[frame p="100%" y="-100" opacity=255]
[endkeyframe]

・バウンドと同時に透明から現れていく例(失敗例。バウンドと同時にならない)

[keyframe name="float_ability"]
[frame p=" 0%" opacity=0]

[frame p=" 25%" opacity=255]
[frame p="100%" y="-100" ]
[endkeyframe]

 

その他気づいたところ

・「バウンドして表示後に、自動的に消える」を一気にやるには、透明になる動きまで含めたcubic-bezier関数を作る必要があり、若干面倒

 ・kanimはデフォルトでアニメ終了を待たずに次の処理に進むので、アニメしながら本文を読み進めやボタン処理等ができる。

 animはアニメ終了待ちのためのタグ[wa]がある。

 ・[chara_new][chara_show][chara_mod]など、キャラ表示関連のタグは、name属性を一個しか指定できない。

キャラクターを以後操作するための名前を半角英数で指定します。このnameは他のタグを含めて必ずユニークでなければなりません

 つまり、これらのタグを使って表示させた画像は、全部同じ名前にしておかないと同時にアニメ操作できない。

imageやptextなどのタグでは、名前は複数登録できるので、

name="chara1,chara_all"

name="chara2,chara_all"

name="chara3,chara_all"

 などと登録しておいた3つの画像があるとき、"chara1"で一個だけアニメさせたり、"chara_all"で全部同時にアニメできた。

ところが[chara_new]関連のタグを使うと、名前が一個しか登録できないため、上記のような個別アニメと全体アニメの使い分けができないということになる。

 

ティラノスクリプトで文字列の内容を調べる

ティラノで文字列の内容を調べる方法です。

星取表を作っていました。

相撲で勝敗を記録するあれです。文字列変数に勝負の終了ごとに○や●を加えていって、

f.hoshi=f.hoshi+'○'

f.hoshi=f.hoshi+'●'

という感じで試合を繰り返すと、f.hoshiの内容が'○●●○○○'となっていきます。

文字列変数ですから、星取表を表示するにはそのまま変数の内容を表示すればいいのですが、じゃあ何番目の取り組みが○なのか●なのか、みたいに、勝敗の内容を取り出すときには工夫がいります。

 

変数を別に用意する方法

試合ごとに数字の変数を用意して、勝ったら1、負けたら0、を変数に代入していく方法もあります。(for文でいじりやすいように配列変数を使う)

f.shiai[1]=1

;1試合目勝

f.shiai[2]=0

;2試合目負け

f.shiai[3]=0

;3試合目負け

 これだと何試合目が勝ったか負けたかダイレクトに調べることができるのでわかりやすいですが、変数が増えてしまうのが面倒かもしれません。

 

文字列変数の内容を調べる方法

こちらが本題です。f.hoshiに入っている'○●●○○○'という文字列を直接調べます。

tyrano.wiki.fc2.comwikiから引用させていただきました。

[eval exp="f.itemname='うすよごれたコップ'"]
[if exp="f.itemname.indexOf('コップ')!=-1"]
コップなら持ってる。
[endif]

このように、調べたい変数の後ろに .indexOf('調べたい文字列')をつけると、

調べたい変数の「何文字目」に「調べたい文字列」があるかわかるのです。

上記に引用したサンプルでは、-1文字目以外に 'コップ' があれば、「コップなら持ってる。」のメッセージ表示となります。( !=-1で評価しているので、-1以外なら、となります)

つまり、うすよごれたコップでも、きれいなコップでも、「コップ」という文字列の含まれるアイテムを所有していれば「コップなら持ってる。」になります。

 

[eval exp="f.itemname='うすよごれたコップ'"]
[if exp="f.itemname.indexOf('コップ')==6"]
6文字目に「コップ」がある。(文字列の先頭は0なので0から数えて6文字目)
[endif]

 ちょっと改造しました。調べたい変数のN文字目に「調べたい文字列」があるかどうか。の判定です。==6のところを7とか5にすると、何も起きません。6のときだけ、「6文字目に「コップ」がある。(文字列の先頭は0なので0から数えて6文字目)」という表示になります。

 

[eval exp="f.itemname='うすよごれたコップ'"]
[eval exp="f.n=f.itemname.indexOf('コップ')"]
文字列の先頭から[l]
[emb exp="f.n"][l]
文字目にコップがある。(文字列の先頭は0なので0から数えて)

また別な改造です。調べたい変数の「何文字目」に「調べたい文字列」があるか、を調べます。結果は、「文字列の先頭から6文字目にコップがある。(文字列の先頭は0なので0から数えて)」となります。

f.itemname='うすよごれたコップ'を、f.itemname='すごくうすよごれたコップ'にすると、「文字列の先頭から9文字目にコップがある。(文字列の先頭は0なので0から数えて)」となるかと思います。

 

以上の方法を使うと、「f.hoshiに入っている'○●●○○○'という文字列」の何番目が○で何番目が●なのか、を調べることができます。

 

こういった文字列に対する操作は、吉里吉里のサイトも参考にさせていただきました。

文字列に対する操作

buttonをfix=trueで使いたかったら[call]ではなく[jump]を使う

f:id:fuwafuwaso:20181016210103p:plain

buttonはfix=trueにすることで常駐ボタンとしていつも表示させておくことができます。

シナリオは分岐などで*ラベルを行ったり来たりする構造になると思いますが、メインのシナリオ(*main)からサブのシナリオ(*sub)に行ったとき、そこで「新たに」常駐ボタンを表示させるには注意点があります。

サブのシナリオ(*sub)に移動するときには、[call]ではなく[jump]でやらなくてはいけません。

[call]でサブのシナリオ(*sub)に飛んで、そこで新たに常駐ボタンの定義[button fix=true]をすると、ボタンが働かなくなります。

これは[button]の仕様で「コール先からリターンするまで全てのボタンは有効にならない」というのが影響してると思われます。

[button]

注意→fixにtrueを指定した場合はコールスタックに残ります。コール先からリターンするまで全てのボタンは有効にならないのでご注意ください

つまり、サブのシナリオ(*sub)を呼び出した時[call]のコールスタックが残っているので、[return]するまではボタンが働かないということですね。

単なるcallだけならcall先でまたcallみたいな、コールスタックを多重にすることも大丈夫ですが、buttonの場合はコールスタックを多重に働かせることはできないように思われます。

おかしな感じもしますが、自分のスクリプトではこうなってしまいますので自分用の注意です。

 

まとめ

*mainで[button fix=true]を定義して、[call]で*subに飛んでも、ボタンは正常に働きます。

*mainで[button fix=true]を定義して、[call]で*subに飛んで、*subで新たに[button fix=true]を定義すると働かなくなります。

これを回避するには、

*mainで[button fix=true]を定義して、[jump]で*subに飛んで、*subで新たに[button fix=true]を定義する、という手順になります。