LoginSignup
12
11

More than 3 years have passed since last update.

phina.jsのclipとblendModeで遊んでみた

Last updated at Posted at 2017-08-05

はじめに

まずは以下のゲームをやってみていただきたいです。(音が出ます)

https://pentamania.github.io/find-shimauma-chan

注目してほしいのは画面遷移する際などの円形のエフェクトと、ゲーム中にスポットライトが当たったように周りが暗くなる演出の部分です。

shima-trans-anim.gif

shima-spotlight.gif

これらはそれぞれclipblendModeという機能を使って実現しています。

環境

phina.js v0.2.2

clip

clip()はcanvasAPIのclipと同じで、指定したパスの範囲内だけを描画するメソッドです。

phina.jsでclipを使うには以下のようにDisplayElement派生クラス(例えばSpriteクラス)にclipというメソッドを定義し、引数で渡されるCanvas(phina.graphics.Canvas)を使ってパスを設定します。

phina.define('ClippedImage', {
  superClass: 'phina.display.Sprite',

  init: function(src) {
    this.superInit(src);
    this.clipCenter = phina.geom.Vector2(0, 0);
    this.clipRadius = 160;
  },

  clip: function(c) {
    var cc = this.clipCenter;
    c.beginPath();
    c.arc(cc.x, cc.y, this.clipRadius, 0, Math.PI*2, false);
  }
});

するとスプライトは指定したパスの範囲内しか描画されなくなります。

phina-clip-sample.png

実行例

さらにクリップ範囲を動的に変えることで(例えば円の半径など)、前出のようなエフェクトが実現できます。

ただ基本的に毎フレーム実行されるため、複雑な処理をさせたり、beginPathでのパスリセットなどを忘れると激重になることがあるので注意が必要です。

blendMode

blendModeはDisplayElement派生クラスのプロパティの一種で、指定した値に応じて「自分自身」と「自身より前に描画されたオブジェクト群」とを相互に影響させることが出来ます。(説明が難しい…)
使い方はDisplayElement系クラスのblendmodeプロパティに値を指定するだけです。

/* blendModeを指定したオブジェクト */
phina.define('SpotLight', {
  superClass: 'phina.display.CircleShape',

  init: function() {
    this.superInit({
      radius: 180,
    });
    this.blendMode = 'destination-in';
  },
});

phina.define('MainScene', {
  superClass: 'DisplayScene',

  init: function(options) {
    this.superInit(options);

    // サンプル用ロゴ
    var logo = Sprite("logo")
    .setPosition(this.width/2, this.height/2)
    .addChildTo(this);

    // blendModeを変えた描画オブジェクト
    this.spotLight = SpotLight()
    .setPosition(this.width/2, this.height/2)
    .addChildTo(this);

    // ※以下LabelクラスはspotLightより後にaddChildされるので影響を受けない
    Label("phina.js blendMode sample")
    .setPosition(this.width/2, this.height/2)
    .addChildTo(this);
  },

  /* 省略 */

});

上の例では"destination-in"を指定することで、SpotLight自身より前に描画されたオブジェクト(logo)の、自身(円)の範囲と重なる部分だけが表示されるようになります。(phina.jsではaddChildした順に描画されます)

実行例

blendModeで指定できる値はcanvasAPIのglobalCompositeOperationプロパティと一緒です。

canvas全体に影響することに注意が必要ですが、photoshopなどいうところの「乗算」や「焼き込み」効果などが使え、clipと比べて応用できる範囲が広そうです。

clipとblendModeは上手く使えばいい感じのエフェクトやギミックが作れそうなのでがんばります。

おまけ

ゲームのリポジトリ

某夢の国風トランジションエフェクト

mickey-spot-sample.gif

  clip: function(c) {
    var cc = this.clipCenter;
    var edgeLength = 40;
    var sr = this.spotRadius;

    c.beginPath();
    c.arc(cc.x, cc.y+edgeLength, sr, 0, Math.PI*2, false); // 中心
    c.closePath();
    c.arc(cc.x+edgeLength+sr, cc.y-edgeLength-sr, sr, 0, Math.PI*2, false); // 右耳
    c.closePath();
    c.arc(cc.x-edgeLength-sr, cc.y-edgeLength-sr, sr, 0, Math.PI*2, false); // 左耳
  },
12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11