Jasmine Teaでアニメーション!

この記事は、 [Jasmine Tea アドベントカレンダー 2023](https://qiita.com/advent-calendar/2023/jasminetea) の第8日目です。

# はじめに

[Jasmine Tea](https://jasminetea.app) (ジャスミンティー) は、プログラミングの楽しさを多くの人に知ってもらうために作られたプログラミング言語です。初心者が学びやすい仕組みで、実際に社会で使われている多くのプログラミング言語に応用できる基礎が身に付きます。

ここでは、Jasmine Teaを実際に開いて、簡単なアニメーションを作ってみようと思います。

まず、Studio 画面を開いてください。もし Studio 画面をまだ開いたことがなければ、 [Studio画面を表示する - Jasmine TeaでHello, world!](https://qiita.com/yoichiro6642/items/3dc478726f4f73941b46#studio%E7%94%BB%E9%9D%A2%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%99%E3%82%8B) を参考にして Jasmine Tea の試用を開始してください。

# 星空を作ってみよう

冬の夜空は、とてもきれいです。夏よりも冬の方が、星が多くきれいに見えます。そんな夜空を、Jasmine Tea で表現してみましょう。

星は、黄色の点（ドット）としましょう。夜空には、肉眼で見える星の数は約3,000個だと言われています。Jasmine Tea では、決まった回数だけ命令を繰り返し実行するときは、[`for` 命令](https://jasminetea.app/docs/references/command-for) を使います。また、グラフィック画面に点を表示するために、ここでは [`pset` 命令](https://jasminetea.app/docs/references/command-pset) を使います。

では、Studio画面の左にあるエディターに、以下のプログラムを入力してください。

```vb
for i=1 to 3000
  x=random(0,639)
  y=random(0,399)
  pset (x,y),6
next
```

`for` 命令のループ変数 `i` には、`1` から `3000` までの数が次々と代入されていきますので、合計で 3,000 回繰り返されることになります。

2行目と3行目では、それぞれ [`random` 関数](https://jasminetea.app/docs/references/function-random) を使って、横軸（`x`）と縦軸（`y`）の位置をランダムに決めています。

`pset` 命令のパラメータは、以下となります。

* `(x,y)` 点を表示する座標（横の座標、縦の座標）
* `,6` 点の色（6: 黄色）

`pset` 命令の座標や色には、式を使うことができます。式の中で変数の名前を書くと、そのときに変数に代入されている数が使われます。つまり、`(x,y)` はそれぞれ `x` という式の計算結果、`y` という式の計算結果が座標値として使われます。

では、実行してみましょう。エディターの下にある青色の「実行」ボタンを押して、プログラムを実行してください。

![stars.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632303/bb5f7b67-5acd-f6aa-cb38-0496145480e0.gif)

星が次々と表示されました。

これだけでは面白くないので、星をゆっくりと右に流してみましょう。エディターの6行目、先ほどのプログラムの続きとして、以下のプログラムを追加してください。

```vb
do
  roll (0,0)-(639,399),5,0,-1
  pause 1000
loop
```

[`do` 命令](https://jasminetea.app/docs/references/command-do) と [`loop` 命令](https://jasminetea.app/docs/references/command-loop) の間にある命令は、ずっと繰り返し実行し続けられることになります。新しく使っている [`roll` 命令](https://jasminetea.app/docs/references/command-roll) は、グラフィック画面をスクロールしてくれる便利な命令です。`roll` 命令のパラメーターは、以下となります。

* `(0,0)-` スクロールしたい領域の角の座標（横の座標、縦の座標）
* `(639,399) スクロールしたい領域の対角の座標（横の座標、縦の座標）
* `,5` 横方向にスクロールさせたいドット数（正の数は右方向、負の数は左方向、`0` は移動なし）
* `,0` 縦方向にスクロールさせたいドット数（正の数は下方向、負の数は上方向、`0` は移動なし）
* `,-1` スクロールした後にできる余白を塗りつぶす色（-1: 塗りつぶさずに、はみ出た部分を反対側から表示する）

上記では、スクロールさせる領域をグラフィック画面全体としています。また、最後の `-1` を指定していることにより、円柱をぐるぐる回しているかのように、グラフィック画面を延々とぐるぐるスクロールさせるように指定しています。

無限ループの中でスクロールをさせてしまうと、結構な高速で星が流れてしまいます。それでも良いのですが、ここでは1秒ごとにスクロールしてみましょう。そのために、[`pause` 命令](https://jasminetea.app/docs/references/command-pause) を使います。`pause` 命令のパラメーターにミリ秒単位で数を指定することにより、プログラムの実行を一時的に停止させることができます。繰り返しの中で `pause` 命令を使うことにより、繰り返しの頻度を調整しています。

では、実行してみましょう。「実行」ボタンを押して、プログラムを実行してください。

![roll.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632303/23d2da2b-2642-ab33-5bbd-219f26ade27e.gif)

星が横に流れるようになりました。しばらく、ぼぉ〜っと、眺めましょう。

# レーザー光線を動かそう

もう少しアニメーションっぽいプログラムを作ってみましょう。2本の緑色の線を、レーザー光線に見立てて、動かしてみます。直線は、[`line` 命令](https://jasminetea.app/docs/references/command-line) を使って描きます。

では、エディターに書かれているプログラムを一度消去して、以下のプログラムを入力し直してください。

```vb
do
  for x=0 to 639
    cls 2
    line (x,0)-(639-x,399),4
    line (639-x,0)-(x,399),4
  next
loop
```

`for` 命令で、ループ変数 `x` に代入される数を `0` から `639` まで変化させています。この変数 `x` に代入された数を、直線を描く際の横方向の座標として採用しています。

![Screenshot_20231208_083629.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632303/393a5c62-f316-16f0-e843-031146a60c71.png)

例えば、変数 `x` に代入されている数が `150` のときは、4行目の `line` 命令では、`(150,0)-(489,399)` が指定されます。つまり、直線の始点（縦の座標が `0`）は、変数 `x` の値が増えていくので、グラフィック画面の左から右に移動します。そして、直線の終点（縦の座標が `399`）は、`639` から変数 `x` に代入されている数を引いた数としているため、その式（`639-x`）の計算結果は減っていきますので、グラフィック画面の右から左に移動します。5行目の `line` 命令で描かれる直線は、その逆です。

3行目の [`cls` 命令](https://jasminetea.app/docs/references/command-cls) は、実行画面を消去するための命令です。パラメーターに `2` を指定していますが、これにより、グラフィック画面に描かれていたものがすべて消去されます。

実行してみましょう。「実行」ボタンを押して、プログラムを実行してみてください。

![Peek 2023-12-08 08-31.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632303/75ed5bfe-c901-aeaf-2492-f368f9145b67.gif)

レーザー光線が中央から出ているように見えましたか？

さて、緑の線が「チラチラ」しているのに気がついたかと思います。リアルなレーザー光線っぽいので、これはこれで良いのかもしれません。しかし、コンピューターグラフィックスのアニメーションとしては、ちらついてしまうのは良くないですね。

このチラツキは、「画面に描かれたものが一度全部消去されている」ことに原因があります。「描いて、消して、描いて、消して、...」と繰り返されているので、消したタイミングを人間が見ても認識できてしまい、チラツキの原因となってします。このチラツキは、気になりだすとすごいストレスかと思いますので、なんとかしたいですね。

一般的に、チラツキは「（ダブル）バッファリング」という手法で解決することができます。「描いて、消して、...」を繰り返すのではなく、次に描くべきものを「表示されない画面 = バッファ」に描いておき、実際に描かれているものを消すのではなく、バッファに描かれた画面で「上書き」することにより、「描いて、描いて、描いて、...」とすることができる、とします。

Jasmine Tea のグラフィック画面は、実は「裏にあるバッファに描かれた後にグラフィック画面に転送される」という仕組みになっています。

![Screenshot_20231208_085427.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632303/3d8b9e16-a737-c237-6664-56c93225a525.png)

バッファからグラフィック画面への転送は、「命令を1つ実行する」度に行われています。つまり、プログラムが1行実行され、次の行が実行されるまでの間に転送されています。

今回のチラツキを防ぐためには、

1. `cls` 命令でグラフィック画面を消去する。
1. `line` 命令を実行して、直線を描く。
1. `line` 命令を実行して、直線を描く。

この一連の処理の間には転送処理を止めて、上記が終わった後に転送する、というようにすれば良いです。

Jasmine Tea では、転送処理の ON/OFF をするために、[`render` 命令](https://jasminetea.app/docs/references/command-render) が提供されています。パラメーターとして `0` を指定すると、転送処理が止まります。そして `1` を指定すると、転送処理が再開されます。

では、エディターの中で、`for` 命令が書かれた行の次の行に `render 0` を、`next` 命令が書かれた行の前の行に `render 1` を、それぞれ追記してください。

![Screenshot_20231208_090056.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632303/a9cfe33a-0a1a-1d93-7d56-fe74527f6634.png)

実行してみましょう。「実行」ボタンを押して、プログラムを実行してください。

![Peek 2023-12-08 09-01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632303/c1b7977d-9457-e641-31d0-7c9eb4d18040.gif)

チラツキが抑えられたことがわかるかと思います。

# 明日は何をつくるの？

今日は、グラフィック画面をスクロールさせてみたり、直線を動かしてみたりしました。また、ちょっと難しかったかもしれませんが、コンピューターグラフィックスでアニメーションをさせる際に起きがちな「チラツキ」を Jasmine Tea で防ぐためのテクニックについても紹介しました。どんなに高度なアニメーションでも、その原理をたどっていくと、今回の内容のようなシンプルなプログラムにいきつきます。

明日は、Jasmine Tea の特徴である「スプライト」を紹介する予定です。