6月10日の池袋晶葉誕生日祭が終わったと思ったらその翌日にデレステでSSRが実装されました。
なんてこった。
ソーシャルゲームのスクリーンショットです pic.twitter.com/AZrMu88Ijp
— ud (@youdie) 2018年6月11日
引きました。
お財布的には大丈夫な範囲です。
ええ、大丈夫です。
ところでこの衣装すごくて、晶葉ちゃんの背負っているランドセル改めニャンドセルのお顔が動くんですよ。
— ud (@youdie) 2018年6月16日
こんな感じ。
可愛い。
で、前回の記事で使ったobnizさん。
池袋晶葉ちゃん誕生日に向けてobnizで動くウサちゃんロボを作った
obniz自体にもディスプレイがついているので、ニャンドセルのお顔が再現できるのでは?と思いやってみました。
canvasでアニメを作ろう
obnizのディスプレイはHTML5のcanvasを利用して描画ができます。
canvasなら好き放題できるし、アニメーションも作りやすそうなのでこれでいってみましょう。
というわけで今回はひたすらにcanvasでアニメを作るやつです。
obnizがどうこうというより初心者がやってみたcanvasアニメーションって感じになりそう。
流れとしてはこんな感じ。
- canvasでニャンドセルの顔を作る
- 差分を作る
- obniz.repeatでループする
やっていきます。
1. canvasでニャンドセルの顔を作る
まずobnizでのcanvasの扱い方です。
obnizのクラスからcanvasのcontextが取れます。
const ctx = obniz.util.createCanvasContext(obniz.display.width, obniz.display.height);
obnizのディスプレイは128*64なので、その中でいい塩梅になるようにひったすらにcanvasでパスを引きまくります。
canvasでのお絵描きの方法は世の中にいっぱい情報があると思うので割愛しますね。
ちなみにまあまあ大変。
ニャンドセルを再現すべくcanvasにパスを引きまくってたらこんな時間かよ pic.twitter.com/174zDR6h3L
— ud (@youdie) 2018年6月12日
単純にJavaScriptでcanvas使ってるだけなので、obnizに適用する前にローカルでブラウザデバッグできるのもいいですね。
2. 差分を作る
canvasでアニメを作るときの基本は、
- 描画する
- 全部消す
- 差分を描画する
の繰り返しです。
というわけでアニメにするための差分を作ります。
今回動かすのは目と口ですね。
なので目と口を描画するメソッドをそれぞれ作って、引数で描画パターンを変えられるようにします。
var drawEye = (ctx,ptn) => {
switch(ptn){
case 0: //開いてるパターン
//左目
ctx.beginPath();
ctx.arc(37, 37, 7, (Math.PI/180)*0, (Math.PI/180)*360, false);
ctx.fill();
//右目
ctx.beginPath();
ctx.arc(91, 37, 7, (Math.PI/180)*0, (Math.PI/180)*360, false);
ctx.fill();
break;
case 1: //閉じてるパターン
//左目
ctx.beginPath();
ctx.moveTo(44,42);
ctx.lineTo(30,42);
ctx.stroke();
//右目
ctx.beginPath();
ctx.moveTo(84,42);
ctx.lineTo(98,42);
ctx.stroke();
break;
case 2: //半開きパターン
//左目
ctx.beginPath();
ctx.arc(37, 37, 7, (Math.PI/180)*315, (Math.PI/180)*225, false);
ctx.fill();
//右目
ctx.beginPath();
ctx.arc(91, 37, 7, (Math.PI/180)*315, (Math.PI/180)*225, false);
ctx.fill();
break;
}
return ctx;
}
こんな感じでcontextとパターンを引数にして描画を変えてます。
円を描くためのラジアン計算をベタで書いてるのは許してください。
最後にcontextを返却してるのは特に意味はありません。なんとなくです。
これで描画素材がそろいました。
3. obniz.repeatでループする
ループアニメを作ります。
JavaScriptでループといえばsetIntervalとかがありますが、obnizさんはそれ独自のループ用メソッドobniz.repeat
を持っています。
使い方はsetIntervalと変わりませんが、こちらはobnizとの通信が切れたところでループを止めてくれるという親切なラッパーメソッドになっています。
せっかくなのでこっちを使いましょう。
はい、最終的にこんなソースになりました(canvasの描画処理は割愛)
var obniz = new Obniz("XXXXXXXX");
obniz.onconnect = async () => {
const ctx = obniz.util.createCanvasContext(obniz.display.width, obniz.display.height);
//ループで使う描画メソッド
var draw = (ctx, ePtn, mPtn) => {
//canvasをクリア
ctx.clearRect(0,0,128,64);
// 線の塗りを設定する(単一色)
ctx.strokeStyle = "#fff";
ctx.fillStyle = "#fff";
// 線の太さを設定する
ctx.lineWidth = 1.0;
ctx.beginPath();
//耳とか日がどかぶちとか動かないものを描画(割愛)
//目を描画メソッド
var drawEye = (ctx,ptn) => {
switch(ptn){
case 0:
//開いてるパターン
break;
case 1:
//閉じてるパターン
break;
case 2:
//半開きパターン
break;
}
return ctx;
}
//目を引数のパターンで描画
ctx = drawEye(ctx,ePtn);
//口を描画メソッド
var drawMouth = (ctx,ptn) => {
//開くパターンの時はちょっと上にずらす
var y = 0;
if(ptn == 1){y = -2;}
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.arc(58, 50 + y, 7, (Math.PI/180)*30, (Math.PI/180)*150, false);
ctx.stroke();
ctx.beginPath();
ctx.arc(70, 50 + y, 7, (Math.PI/180)*150, (Math.PI/180)*30, true);
ctx.stroke();
//開いたときの口の下の線
if(ptn == 1){
ctx.beginPath();
ctx.arc(64, 50, 9, (Math.PI/180)*30, (Math.PI/180)*150, false);
ctx.stroke();
}
return ctx;
}
//口を引数のパターンで描画
ctx = drawMouth(ctx, mPtn);
}
var eyePtn = 0;
var mouthPtn = 0;
var counter = 0;
//ループスタート
obniz.repeat(()=>{
switch (counter) {
case 0:
eyePtn = 0;
mouthPtn = 0;
counter++
break;
case 1:
eyePtn = 1;
mouthPtn = 0;
counter++
break;
case 2:
eyePtn = 2;
mouthPtn = 0;
counter++
break;
case 3:
eyePtn = 0;
mouthPtn = 0;
counter++
break;
case 4:
eyePtn = 0;
mouthPtn = 1;
counter++
break;
case 5:
eyePtn = 0;
mouthPtn = 0;
counter = 0;
break;
}
//描画処理
draw(ctx, eyePtn, mouthPtn);
//描画したcontextをobnizに渡す
obniz.display.draw(ctx);
},300);
}
ちょっぴり補足解説。
今回のアニメは
- 初期顔
- 目を閉じる
- 目が半開きになる
- 目が開く(初期顔)
- 口が開く
- 口を閉じる(初期顔)
の6コマあります。
目:3パターン、口:2パターンを順番に描画していけばいいわけですね。
そこでobniz.repeat
メソッドの中でカウンターを使って状記6パターンの描画を切り替えています。
最後の300は切り替えのミリ秒数でsetIntervalとまんま同じ使い勝手です。
ワハハ完成したぞ
池袋晶葉のSSR実装祝いに新衣装のニャンドセルの顔をobniz上で再現してみました pic.twitter.com/xbehMVBtqG
— ud (@youdie) 2018年6月13日
かーわいーー
はい、そんな感じでできました。
最初のcontext生成とループ処理以外はほとんどcanvasの描画処理なので、あんまりonbiz特有っぽさはないですね。
逆に言うとcanvasでできることは全部obniz上にも描画できるということですけれど。
obnizから他のディスプレイを操作したりできるともっと色々夢が広がりそうですね。