Scratch3 『もし端に着いたら跳ね返る』で何が起こる？

# はじめに

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/5ecd26a8-c145-2dbb-6e97-6482d3252d2a.png)



Scratch3 の『もし端に着いたら跳ね返る』の角度について、しつこく・しつこく調べてみました。自分でもくどいくらいに調べてみた。


# よくありがちな説明

ネットとかScratch本をみると、反射角だよとの説明がありました。

こんな感じで　入射角＝反射角 になるよ　と説明されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/73fea20e-bbd3-bb8d-8f7a-826378ef403e.png)

# しつこく調べてみるのが面白い

そうですか？本当ですか？としつこく調べてみるのが面白いと思いませんか？

# ４５度の角度で

では ４５度の角度（向き）で端にぶつけてみましょう。スプライトの軌跡をわかりやすくするために「ペン機能」を使います。

## コード

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/a910b6c7-6e71-caef-50a5-e138f3c366fa.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/72d063f9-f57f-ff1f-fa44-8eb8435b406b.png)

## 結果
４５度で跳ね返るようですね。「入射角＝反射角」でした。（当たり前か）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/35ac2497-cfb9-afa6-c53a-c112979cc421.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/fd285816-85e0-6047-4425-b4cfcbd9d227.png)

# 次は８５度だ
では ８５度の角度（向き）で端にぶつけてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/6adf8538-a0dd-9cae-f418-19daf34d4660.png)

## コード
変えたスクリプトだけをUPします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/6ac385fc-d57b-bf8c-4fb0-260f4946f065.png)

## 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/efc2ec72-55c5-317e-65b2-2ddfb442c521.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/3a439f34-c4ef-cd39-9f8d-92be27628995.png)

８５度で上の端に着いたら１０１度で跳ね返りました。
いつでも「入射角＝反射角」ではないようですね

# いろんな角度で試してみよう

入射角をいろいろと変えてみて、反射するときの「向き」がどうなるかを調べてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/1ff62191-c278-0ff3-8839-046e1eeb7e61.png)

## 調べた結果

前提：「上の端に着いたとき」の反射です。

| 入射 | 反射 |  |
|:-----------:|:------------:|:------------:|
| 0～78   | 入射角と同じ        |          |
| 79     | 78      |        |
| 80～90 | 79        | 90 - 79 = 11 |

「入射角＝反射角」とはならない入射角がありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/db097c35-62e1-8024-5d60-83b7514dda16.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/f3c07d58-1df1-983f-9d3c-bc582741fab9.png)

入射角が 90度に近いときは 反射角 = 入射角 + α　
というか、80度≦入射角 のときは、反射角＝79度(固定) です。

わざと 少し大きな角度で反射させているようです（Scratch3 の仕様かな)
入射角が小さいときに 反射を強くさせることで「動き」を強調しているのかも。
なぜなのかはScratch3 の実装者にきかないとわからないですが、そんな反射をすると覚えておくと、いいことがあるかもね。

# もっと追及してみる

『もし端に着いたら跳ね返る』ブロックが実行されると何が起こるのでしょうか？
反射して向きが変わるだけでしょうか。

## 前後で少し止めて動きを観察する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/408f95e3-cc02-94cc-e464-3346eff92ffc.png)

## 経過
### (1)開始
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/69bf5650-7bc6-0292-61a8-6754f9118b73.png)
### (2)右上の端に触った
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/6c169e89-6247-81d4-febe-fdb156164806.png)
### (3)向きが変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/10436afa-0e20-32c3-ecf9-7f8fd5fc12b0.png)
### (4)移動が起こる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/2c705c64-a2a4-92f0-174a-aca12b657ce7.png)
(2)で変わった「向き」の方向へ移動していないことに注目してください。
「向き」は維持したまま、スプライトが端に（上下左右）触れないぎりぎりのところをみつけ、そこに移動しています。
## 仮説（推論）
端の隅から跳ね返るときは向きの方向に跳ね返るわけではなくて、隅に触れるぎりぎりの場所へ移動する！

## 仮説の検証

こんなコスチュームにしてみよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/13929557-fabc-b14d-9d7b-c0429d655112.png)
### (1)開始
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/2ffd42ee-439d-eeca-7822-1d2836d0781f.png)
### (2)右上の端に触った
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/0009b244-3e61-a2a5-9206-e75972f0e6f2.png)
### (3)向きが変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/981fec8f-5e0f-ab46-bd3b-8efd9501c74d.png)
### (4)移動が起こる
ここが重要！ひげが伸びているわけだが。
- 向きの変化は ひげを伸ばす前と変わらない。
- でも ひげが伸びた分、移動する位置に変化が生じている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/93030e8f-a02d-0432-c32d-e566f940b29d.png)

# 隅っこに触ったときの整理

## 右上の隅なら？
直前で調べているとおり、右上の隅に触ったときは、上の端で反射するように角度が変わる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/e734fe48-2532-091f-8aaa-158fb457ca01.png)


## 右下の隅なら？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/ce413d71-11aa-b058-6a3a-c0495214a7a5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/2ccc4fb1-43af-8542-11cf-9144922bdb34.png)



#### 角度はどうなった？
右下の隅に触ったときは、右側の端で反射しているように角度が変わる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/84ec3074-6a8f-4154-5d07-b1692794dc4c.png)

## 左上の隅なら？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/0b312815-e065-0192-aacb-f57ce1cb03a3.png)　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/abf578de-a330-5ea2-15d3-5e3ee9cb6685.png)

#### 角度はどうなった？
左上の隅に触ったときは、左側の端で反射しているように角度が変わる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/b8a5d51d-86e2-fac1-47dc-445a727479f0.png)

## 左下の隅なら？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/d8b2d13b-e2ae-c019-a34f-3587859e4415.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/e5810ced-836a-85a3-35ed-4dd8ae86d2cc.png)

#### 角度はどうなった？
- 右上の隅⇒上の端で反射するように角度が変わる
- 右下の隅⇒右の端で反射するように角度が変わる
- 左下の隅⇒？？？（下の端で反射するのかな？）
- 左上の隅⇒左の端で反射するように角度が変わる

左下の隅に触ったときは、下の端で反射しているように角度が変わる
と思いきや、「左の端で反射しているように角度が変わる」のでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/77a45f80-90d7-d338-e42d-0039ac5a0b5f.png)

## まとめ（隅に触ったときの反射）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/352be01c-4a49-ca6a-ad63-ca03aad8b5f0.png)

左上の隅、左下の隅、ともに「左端で反射！」です。変じゃない？

### どういうこと？

どういうこと？（美しくないな）、実験のミスか？と何度もやり直したけど、結果は変わらず。しょうがないので、Scratch-vm 実装をみてみる。

```:scratch-vm/src/blocks/scratch3_motion.js
    ifOnEdgeBounce (args, util) {
        ～
        if (nearestEdge === 'left') {
            dx = Math.max(0.2, Math.abs(dx));//x
        } else if (nearestEdge === 'top') {
            dy = Math.max(0.2, Math.abs(dy));
        } else if (nearestEdge === 'right') {
            dx = 0 - Math.max(0.2, Math.abs(dx));
        } else if (nearestEdge === 'bottom') {
            dy = 0 - Math.max(0.2, Math.abs(dy));
        }
        const newDirection = MathUtil.radToDeg(Math.atan2(dy, dx)) + 90;
        util.target.setDirection(newDirection);
　　　　～
    }
// 【解説】
// もし 左端についている ならば
//   　左端で反射する
// でなければ
//     もし  上端についている　ならば
//          上端で反射する
//     でなければ
//          もし 右端についている　ならば
//              右端で反射する
//          でなければ
// 　　　　　　　もし 下端についている ならば
//                  下端で反射する
// 　　　　　　　でなければ
//                  反射しない
```
下端に触れていてもいなくても、「左端に触れている」ならば、左端で反射することになる。
なるほど。こんな実装だったら左上隅も左下隅も「左端で反射」するね。納得した。


# 次の確認

次は「ひとつの端」に触れたときの「跳ね返り」を確認する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/6f255ef9-9b73-384d-f253-ca4b759236a6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/2a006c6a-a16d-0f45-00fc-bf045511af1b.png)

# まとめ：「もし端に着いたら跳ね返る」ブロックの動きとは？

- 向きを反転させる（向きは 80度 ≦入射角 のときは 反射角= 79度)
- 触れている端に（上下左右で）触らないぎりぎりのところに、スプライトを移動させる

の２つを実行するブロックでした。

## 追加ルール
複数の端にふれているときの反射角は どの端で反射した角度なのか？についてはScratchなりのルールがある。でした。