バグphina

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81823/479e3ed2-3c63-e107-384c-ac097d714190.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81823/d16712a7-8224-e9b0-3286-983ccee42fd9.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81823/2c1dac7b-1498-4d48-11d0-343354ab3b52.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/81823/114d920a-00ac-a3f2-1138-0b337044928a.png)


あ

https://runstant.com/pentamania/projects/6609da54


## 解説
以下のようなglitchというメソッドを用意し、Spriteクラスの描画元になるTextureをぐちゃぐちゃにすることでバグったっぽくしています。

```javascript
/**
 * @param  {Number} [chipSize] chip粒度ピクセル数 0は無効
 * @param  {Number} [seed] int ランダムシード：結果を固定したい場合に指定
 * @param  {Number} [discreteFreq] int 歯抜けの頻度、高いほど頻度低
 * @return {this}
 */
phina.asset.Texture.prototype.glitch = function(chipSize, seed, discreteFreq) {
  chipSize = chipSize || 16;
  var image;

  if (!this.baseImageElement) {
    image = this.baseImageElement = this.domElement;
    this.glitchedImage = phina.graphics.Canvas().setSize(image.width, image.height);
    this.domElement = this.glitchedImage.domElement;
  }

  image = this.baseImageElement;
  var random = phina.util.Random(seed);
  var canvas = this.glitchedImage;
  var row = Math.floor(image.height / chipSize);
  var col = Math.floor(image.width / chipSize);

  canvas.clear();
  row.times(function(y) {
    col.times(function(x) {
      // たまに歯抜け
      if (discreteFreq && random.randint(0, discreteFreq) === 0) {
        return;
      }
      var sx = random.randint(0, col-1) * chipSize;
      var sy = random.randint(0, row-1) * chipSize;
      var left = x * chipSize;
      var top = y * chipSize;
      canvas.context.drawImage(image,
        sx, sy, chipSize, chipSize,
        left, top, chipSize, chipSize
      );
    }, this);
  }, this);

  return this;
};
```

手法は上のコードから何となく感じ取ってほしいのですが、簡単に言えば元画像からランダムで矩形範囲（chipSizeで決定）を拾い、表示用のcanvasにそれを敷き詰めています。

### Shape系クラスでの実装
タイム部分のphina.display.LabelクラスはShape派生クラスですが、これらのクラスはpostrenderというメソッドを用意していると描画結果にさらなる加工ができます。

これを利用し、postrenderで上のglitchと似たような処理をすることでバグってる感を実現（？）できます。
※ただしpostrenderはオーバーライドされない前提。

```javascript

phina.display.Shape.prototype.isGlitched = false;
phina.display.Shape.watchRenderProperty('isGlitched'); // 変更があったら再描画をかける
phina.display.Shape.prototype.postrender = function(canvas) {
  if (!this.isGlitched) return;

  // パラメータ
  var chipSize = 16;
  var discreteFreq = 0;
  var seed = null;

  var image;
  var random = phina.util.Random(seed);

  if (!this.cachedCanvas) {
    this.cachedCanvas = phina.graphics.Canvas();
  }

  // 加工結果を一旦保存
  this.cachedCanvas
    .setSize(canvas.width, canvas.height)
    .clear();
  this.cachedCanvas.context.drawImage(canvas.domElement, 0, 0);

  image = this.cachedCanvas.domElement;
  var row = Math.floor(image.height / chipSize);
  var col = Math.floor(image.width / chipSize);

  // 元canvasをバグ状態にする
  canvas.resetTransform();
  canvas.clear();
  row.times(function(y) {
    col.times(function(x) {
      // たまに歯抜け
      if (discreteFreq && random.randint(0, discreteFreq) === 0) {
        return;
      }
      var sx = random.randint(0, col-1) * chipSize;
      var sy = random.randint(0, row-1) * chipSize;
      var left = x * chipSize;
      var top = y * chipSize;
      canvas.context.drawImage(image,
        sx, sy, chipSize, chipSize,
        left, top, chipSize, chipSize
      );
    }, this);
  }, this);
};
```


## 参考
- [猫リセットとは - ニコニコ大百科](https://dic.nicovideo.jp/a/%E7%8C%AB%E3%83%AA%E3%82%BB%E3%83%83%E3%83%88)
- [カセット半挿しとは - ニコニコ大百科](https://dic.nicovideo.jp/a/%E3%82%AB%E3%82%BB%E3%83%83%E3%83%88%E5%8D%8A%E6%8C%BF%E3%81%97)