p5.play のSpriteクラスを継承させたい

# p5.play のSpriteクラスを継承させるには？

p5.play のSpriteはなかなか便利なものですが、Spriteクラスを継承したクラスを作ることができたらもっと便利ですよね？

(2023/10/21 修正) p5.registerMethod('init')を使った Spriteクラス継承ができないと思い込み元記事を投稿しましたが、勘違いでしたので訂正しています。

## 前提条件

|  | Right align |
|:-----------|:------------:|
| p5.js       | 1.7.0        |
| plank.js     | v1.0.0-beta.16      |
| p5play.js     | 3.14     |

p5 をインスタンスモードで動かしたい。


## p5.js Web Editorでやってみた

### index.html

Web Editor を使って検証します。
p5.play を使う前提で 次のように index.html を作ります。

```: index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/addons/p5.sound.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/planck@latest/dist/planck.min.js"></script>
    <script src="https://p5play.org/v3/p5play.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />
  </head>
  <body>
    <main>
    </main>
    <script src="sketch.js"></script>
  </body>
</html>
```

### sketch.js

p5 をインスタンスモードで起動させます。

```: sketch.js
window.onload = () => {
  new p5( sketch );
};

const sketch = function( p ) {

　p.preload = function(){
  };
  
  p.setup = function(){
  };
  
  p.draw = function(){
  };

};

```

注意）p5 のインスタンスを作るところは、`window.onload` のタイミングでないと いろいろまずいです。


## p5.playのSprite はいつ定義されるのか？

p5play.js をみてみますと、いきなり先頭にこんなものが書かれています。

```
p5.prototype.registerMethod('init', function p5playInit() {
	if (typeof window.planck == 'undefined') {
		throw 'planck.js must be loaded before p5play';
	}
    ：
　（略）
    ：
	this.Sprite = class {
    ：
　（略）
    ：

```
p5.js の `init`処理が動くなかで、Spriteクラスが定義されています。
つまり p5.jsの`init`処理の前では Spriteクラスを参照することはできません。

## 処理の順番

### init
```
p5.prototype.registerMethod('init', 処理 );
```
init処理は registerMethod() で複数登録ができます。
登録した順に実行されます。

### preload()
initで登録した処理が終わった後に、preload 関数 が１回だけ動きます。

### setup()
preload 内の　`load`する処理が全て終わったあとにsetupが動きます。
setup の名前をもつ関数 は１回だけ動きます。

### pre
```
p5.prototype.registerMethod('pre', 処理 );
```
pre処理は registerMethod() で複数登録ができます。
draw処理が実行される都度、その前に毎回動きます。
pre処理は registerMethod() で登録しないと動作しません。

### draw()
preloadの後、pre処理の後に draw が動きます。
draw処理は、設定されたFPSに従い（FPSに近くなるように）呼び出されます。

### post
```
p5.prototype.registerMethod('post', 処理 );
```
post処理は registerMethod() で複数登録ができます。
draw処理が実行される都度、その後のpreが開始される前に毎回動きます。
post処理は registerMethod() で登録しないと動作しません。

### remove
```
p5.prototype.registerMethod('remove', 処理 );
```
remove処理は registerMethod() で複数登録ができます。
p5のremove()が実行されるタイミングで実行されます。
remove処理は registerMethod() で登録しないと動作しません。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294946/563521fc-1721-fb42-51e8-c85310e9f512.png)

## p5.playのSprite はどのタイミングで使えるのか？


結論：preload()処理が動く直前、以降で使えます。

結論：p5のinitのタイミング以降で p5PlayのSpriteクラスが使えます。

## p5.play Spriteを継承したクラスを作れるのは、どのタイミングですか？


結論：preload()処理が動く直前以降であれば次の形で継承できます。

結論：p5のinitのタイミング以降で p5PlayのSpriteクラスを継承できます。

```
const Clazz = class extends p.Sprite {

};

```

# 継承したクラスを作る

## 【Ａ】p5のinitのタイミングで作る

こんな感じでかけそうです。

```:js/pico.js (名前は任意)
p5.prototype.registerMethod('init', function (){

  this.PicoSprite = class extends this.Sprite {
      
      constructor(...args){
        
        super(...args);
        // 追加処理があれば書く。
      }      
      
    };
});

```

```:sketch.js
const sketch = function( p ) {

    p.setup = function() {
        pico = new p.PicoSprite();

    }

```
```:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/addons/p5.sound.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/planck@latest/dist/planck.min.js"></script>
    <script src="https://p5play.org/v3/p5play.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />
  </head>
  <body>
    <main>
    </main>
    <script src="./js/pico.js"></script> <!-- ここで 継承クラスを定義 -->
    <script src="sketch.js"></script>
  </body>
</html>


```


### ちょっとした説明

registerMethod() へ渡すファンクションは、アロー関数ではNGです。
p5Playで作ったSpriteクラスを参照できなくなります。
registerMethod() へ渡すファンクションの中での this は p5 です。

上の例では sketch.jsの先頭に registerMethod() を 書いていますが、この部分を別JSファイルとして外だしにしてもＯＫです。 むしろ外だしにしたほうがすっきりするかも。

## 【Ｂ】setup の中で作る

こんな感じでかけそうです。

```:sketch.js
    p.setup = function() {

        PicoSprite = class extends p.Sprite {

            constructor(...args) {
                super(...args);
                // 追加処理があれば書く。
            }
        };

        pico = new PicoSprite();

    }

```

## 【Ｃ】setup の中のタイミングで生成、別ファイルにする

こんな感じでかけそうです。

```:js/PicoSprite.js

const createPicoSpriteClass = function(p){

    return class Pico extends p.Sprite {

        constructor(...args) {
            super(...args);
            // 追加処理があれば書く。
        }
    };
};

```

```:sketch.js
    p.setup = function() {
        PicoSprite = createPicoSprite(p);
        pico = new PicoSprite();
    }

```
```:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.7.0/addons/p5.sound.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/planck@latest/dist/planck.min.js"></script>
    <script src="https://p5play.org/v3/p5play.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css">
    <meta charset="utf-8" />
  </head>
  <body>
    <main>
    </main>
    <script src="js/PicoSprite.js"></script>
    <script src="sketch.js"></script>
  </body>
</html>
```


# まとめ


## Spriteを使えるのは？

p5 の Initフェーズの最後以降

## Spriteの継承クラスを書くやり方は？

【Ａ】、【Ｂ】、【Ｃ】のうち、お好きなやり方でどうぞ。