見出し画像

2体のあかねを物理エンジンで回転させる【ティラノスクリプト+mattar.js】

こんにちは、箱詰九分です!ティラノスクリプトでゲームを作るとき、どんな人でも一度は必ず「ものを回転させる」局面が出てくると思います。前回の記事では、[keyframe][kanim]タグを用いた方法と、 javascript を用いた方法であかねを回転させました。(お暇であれば読んでみてね↓)

しかし、これを読んでいるあなたは、さらなる方法での回転を望んでいるのではないでしょうか。ティラノスクリプトでゲームを作った方ならすべからく持っている欲求…そう、物理エンジンの導入です!(あってますよね?)この記事では、軽量な物理エンジンである "matter.js" をティラノスクリプトに導入し、2体のあかねを物理的に回転させます。(本当です。)少し長くなりますがお付き合いください。

※この記事を理解するにはティラノスクリプトと javascript (jQuery) の知識が必要となります。そのため、少し敷居が高くなるかもしれませんが、なるべく分かりやすく書くのでご容赦ください。

画面収録 2021-04-08 19.41.01

準備

ティラノスクリプトV5 を元に説明します。まずは、ティラノスタジオなどで新規プロジェクトを作成します。そしてゲーム起動し進めると、シナリオファイルの"scene1.ks" ("data/scenario/scene1.ks") にたどり着くと思います。

スクリーンショット 2021-04-08 18.32.55

今回はこの "scene1.ks" と "first.ks" ("data/scenario/first.ks")を編集していきます。早速ですが、この"scene1.ks" 、説明をするにはちょっと長いので、以下のように書き換えます。

;ティラノスクリプトサンプルゲーム

*start

[cm  ]
[clearfix]
[start_keyconfig]
;背景画像のクリア
[freeimage layer="base"]
;メニューボタンの表示
@showmenubutton
;メッセージウィンドウの設定
[position layer="message0" left=160 top=500 width=1000 height=200 page=fore visible=true]
;文字が表示される領域を調整
[position layer=message0 page=fore margint="45" marginl="50" marginr="70" marginb="60"]
;メッセージウィンドウの表示
@layopt layer=message0 visible=true
;キャラクターの名前が表示される文字領域
[ptext name="chara_name_area" layer="message0" color="white" size=28 bold=true x=180 y=510]
;上記で定義した領域がキャラクターの名前表示であることを宣言(これがないと#の部分でエラーになります)
[chara_config ptext="chara_name_area"]

;このゲームで登場するキャラクターを宣言
;akane
[chara_new  name="akaneA" storage="chara/akane/normal.png" jname="あかね"  width="200", height="300"]
[chara_new  name="akaneB" storage="chara/akane/normal.png" jname="あかね"  width="200", height="300"]

;キャラクター登場
[chara_show  name="akaneA"  ]
#?
こんにちは。[p]
[chara_show  name="akaneB"  ]
#?
こんにちは。[p]
私の名前はあかね。[p]
#あかね
もしかして、ノベルゲームの開発に興味があるの?[p]
[s]

この時点で、回転させる対象のあかねが2体出てくるようになりました。背景の画像については、後々に当たり判定を確認するときに邪魔になるので非表示にしています。キャラクターの name は、片方をakaneA、もう片方を akaneB とします。また、そのままのあかねではサイズが大きすぎるので、width="200", height="300" を指定して小さく表示しています。

こんな感じ。

スクリーンショット 2021-04-08 19.05.34

このままでは物理的挙動はできませんので、次は matter.js を導入しましょう!

matter.js の導入

matter.js 公式サイトのダウンロードリンクから matter.js 本体をダウンロードします。公式サイトはこちら。↓

スクリーンショット 2021-04-08 18.41.11

左側のリストの一番上 "Latest Build" をクリック。

スクリーンショット 2021-04-08 18.43.13

Github の mattar.js のソースが出てくるので、画像中赤線で囲った "Raw" をクリック。

スクリーンショット 2021-04-08 18.52.06

表示されたファイルを Ctrl + S で 保存します。保存先は "data/others/"配下 としてください。 

スクリーンショット 2021-04-08 18.54.58

次に、"first.ks" を編集します。以下の行を追加すると、"data/others/mattar.js"が読み込まれます。

[loadjs storage="./matter.js"]

"first.ks" 全体は以下のようになります。

;一番最初に呼び出されるファイル

[title name="ティラノスクリプト解説"]

[stop_keyconfig]

[loadjs storage="./matter.js"]

;ティラノスクリプトが標準で用意している便利なライブラリ群
;コンフィグ、CG、回想モードを使う場合は必須
@call storage="tyrano.ks"

;ゲームで必ず必要な初期化処理はこのファイルに記述するのがオススメ

;メッセージボックスは非表示
@layopt layer="message" visible=false

;最初は右下のメニューボタンを非表示にする
[hidemenubutton]

;タイトル画面へ移動
@jump storage="title.ks"

[s]

以上で matter.js の導入は完了です!やったね!

さあ回転させよう!

めんどいのでとりあえずソース全体貼り付けます!どん!

;ティラノスクリプトサンプルゲーム

*start

[cm  ]
[clearfix]
[start_keyconfig]
;背景画像のクリア
[freeimage layer="base"]
;メニューボタンの表示
@showmenubutton
;メッセージウィンドウの設定
[position layer="message0" left=160 top=500 width=1000 height=200 page=fore visible=true]
;文字が表示される領域を調整
[position layer=message0 page=fore margint="45" marginl="50" marginr="70" marginb="60"]
;メッセージウィンドウの表示
@layopt layer=message0 visible=true
;キャラクターの名前が表示される文字領域
[ptext name="chara_name_area" layer="message0" color="white" size=28 bold=true x=180 y=510]
;上記で定義した領域がキャラクターの名前表示であることを宣言(これがないと#の部分でエラーになります)
[chara_config ptext="chara_name_area"]

;このゲームで登場するキャラクターを宣言
;akane
[chara_new  name="akaneA" storage="chara/akane/normal.png" jname="あかね"  width="200", height="300"]
[chara_new  name="akaneB" storage="chara/akane/normal.png" jname="あかね"  width="200", height="300"]

;キャラクター登場
[chara_show  name="akaneA"  ]
#?
こんにちは。[p]
[chara_show  name="akaneB"  ]
#?
こんにちは。[p]

[iscript]
 let engine = Matter.Engine.create();
 let akaneAbox = Matter.Bodies.rectangle(200, 200, 200, 300);
 let akaneBbox = Matter.Bodies.rectangle(800, 200, 200, 300);
 Matter.Body.setAngularVelocity(akaneAbox, 0.3);
 Matter.Body.setVelocity(akaneAbox, {x : 10 , y : 0});
 Matter.Body.setAngularVelocity(akaneBbox, -0.3);
 Matter.Body.setVelocity(akaneBbox, {x : -10 , y : 0});
 let floor = Matter.Bodies.rectangle(640, 715, 1280, 10, { isStatic: true });
 let ceiling = Matter.Bodies.rectangle(640, 5, 1280, 10, { isStatic: true });
 let wall_l = Matter.Bodies.rectangle(5, 360, 10, 720, { isStatic: true });
 let wall_r = Matter.Bodies.rectangle(1275, 360, 10, 720, { isStatic: true });

 Matter.World.add(engine.world, [akaneAbox, akaneBbox, floor, ceiling, wall_l, wall_r]);

 var render = Matter.Render.create({
  element: $(".0_fore")[0],
  engine: engine,
  options: {
       width: 1280,
       height: 720,
     }
 });
 Matter.Render.run(render);

 f.id = 0;
 let update = () =>  {
     Matter.Body.setAngularVelocity(akaneAbox, 0.3);
     Matter.Body.setAngularVelocity(akaneBbox, -0.3);
     Matter.Engine.update(engine);
     $(".akaneA").css( { "transform": "rotate("+ (akaneAbox.angle * ( 180 / Math.PI ) )  +"deg)","left":  (akaneAbox.position.x -100) + "px", "top":  (akaneAbox.position.y -150) + "px",  } )
     $(".akaneB").css( { "transform": "rotate("+ (akaneBbox.angle * ( 180 / Math.PI ) )  +"deg)","left":  (akaneBbox.position.x -100) + "px", "top":  (akaneBbox.position.y -150) + "px",  } )
     f.id = requestAnimationFrame(update);
 }
 f.id = requestAnimationFrame(update);
[endscript]

私の名前はあかね。[p]
#あかね
もしかして、ノベルゲームの開発に興味があるの?[p]
[s]

するとこうなる。

では、順を追ってソース([iscript]〜[endscript]の部分)をみてみましょう。

まず、mattar.js の物理エンジンを create します。

 let engine = Matter.Engine.create();

あかねに同期させる物理オブジェクト(Box)をつくります。

 let akaneAbox = Matter.Bodies.rectangle(200, 200, 200, 300);
 let akaneBbox = Matter.Bodies.rectangle(800, 200, 200, 300);

Box たちに速度、角速度を設定します。

 Matter.Body.setAngularVelocity(akaneAbox, 0.3);
 Matter.Body.setVelocity(akaneAbox, {x : 10 , y : 0});
 Matter.Body.setAngularVelocity(akaneBbox, -0.3);
 Matter.Body.setVelocity(akaneBbox, {x : -10 , y : 0});

床、天井、壁をつくります。

 let floor = Matter.Bodies.rectangle(640, 715, 1280, 10, { isStatic: true });
 let ceiling = Matter.Bodies.rectangle(640, 5, 1280, 10, { isStatic: true });
 let wall_l = Matter.Bodies.rectangle(5, 360, 10, 720, { isStatic: true });
 let wall_r = Matter.Bodies.rectangle(1275, 360, 10, 720, { isStatic: true });

オブジェクトたちを物理エンジンに追加します。

 Matter.World.add(engine.world, [akaneAbox, akaneBbox, floor, ceiling, wall_l, wall_r]);

ワイヤーフレームを描画するキャンバスを追加します。

 var render = Matter.Render.create({
  element: $(".0_fore")[0],
  engine: engine,
  options: {
       width: 1280,
       height: 720,
     }
 });
 Matter.Render.run(render);

requestAnimationFrame を使って 物理エンジンを update & あかねを Box の位置・角度にアジャストします。ついでに角速度もセットして、永続的に回転するようにしています。あかねの取得には jQuery を使用。

 let update = () =>  {
     Matter.Body.setAngularVelocity(akaneAbox, 0.3);
     Matter.Body.setAngularVelocity(akaneBbox, -0.3);
     Matter.Engine.update(engine);
     $(".akaneA").css( { "transform": "rotate("+ (akaneAbox.angle * ( 180 / Math.PI ) )  +"deg)","left":  (akaneAbox.position.x -100) + "px", "top":  (akaneAbox.position.y -150) + "px",  } )
     $(".akaneB").css( { "transform": "rotate("+ (akaneBbox.angle * ( 180 / Math.PI ) )  +"deg)","left":  (akaneBbox.position.x -100) + "px", "top":  (akaneBbox.position.y -150) + "px",  } )
     f.id = requestAnimationFrame(update);
 }
 f.id = requestAnimationFrame(update);

ここで注意すべきは以下の2行。


$(".akaneA").css( { "transform": "rotate("+ (akaneAbox.angle * ( 180 / Math.PI ) )  +"deg)","left":  (akaneAbox.position.x -100) + "px", "top":  (akaneAbox.position.y -150) + "px",  } )
$(".akaneB").css( { "transform": "rotate("+ (akaneBbox.angle * ( 180 / Math.PI ) )  +"deg)","left":  (akaneBbox.position.x -100) + "px", "top":  (akaneBbox.position.y -150) + "px",  } )

Box の angle はラジアンなので、度に変換する必要があります。また、Box の position は Box の中心であるのに対し、top、left は左上なので、そこも調整する必要があります。

ソースコードの説明はこんなところかな。

さいごに

いかがでしたか?今回は2体のあかねを回転させただけですが、物理エンジンを導入することでティラノスクリプトでの表現の幅がぐっと広がったと思いませんか?思いますよね!よっしゃ!
この記事の例を回転以外にも応用すれば、いろいろ楽しいことができるんじゃないかなーと思ってます。物理エンジン最高!ティラノ最高!

以上、2体のあかねを物理エンジンで回転させる記事でした!お疲れ様!

この記事が気に入ったらサポートをしてみませんか?