今回の記事は、phina.jsで用意されているShape系クラスの一つ、線を描画する際に使用するPathShapeクラスを読み解きつつ、描画をしていこうと思います。以前の[phina.js]基本 — 色んな図形オブジェクトについての記事で上手く説明できなかったリベンジです!
もしphina.jsが分からない方は、[phina.js]基本 — テンプレートについてをご一読いただくことをおすすめいたします。
※2018年9月29日 加筆・修正を行いました。
※2018年10月18日 加筆・修正を行いました。
※2020年9月11日 加筆・修正を行いました。
目次
準備
コーディングは、Runstantや、またはRunstant liteを使って試されることをおすすめします。
一応雛型として置いておきます。
<script src='https://cdn.jsdelivr.net/gh/phi-jp/phina.js@0.2.3/build/phina.js'></script>
// グローバル領域に展開
phina.globalize();
/*
* メインシーン
*/
phina.define("MainScene",{
// 継承
superClass:"DisplayScene",
// コンストラクタ
init: function(){
// 親クラスの初期化
this.superInit();
// ここに処理を書く
},
// 更新
update: function(){
},
});
/*
* メイン処理
*/
phina.main(function(){
// アプリケーションを生成
const app = GameApp({
// MainSceneから開始
startLabel: "main",
});
// fps表示
//app.enableStats();
// 実行
app.run();
});
PathShapeクラスのプロパティやメソッド一覧
プロパティ
プロパティ名 | 説明 | デフォルト値 |
---|---|---|
paths | 線を描きたい座標。Vector2(x, y)の形で配列で指定する | null |
lineCap | 線の端の形 ※補足もお読みください。 |
‘round’ |
lineJoin | 線が描く角の形 ※補足もお読みください。 |
‘round’ |
padding | CSSとかのpaddingと同じ、図形の周りの空白領域の幅 | 8 |
fill | 塗りつぶす色 | false |
stroke | 図形を縁取る色 | ‘#aaa’ |
strokeWidth | 図形を縁取る線の幅 | 4 |
shadow | 図形の周りに落とす影の色 | false |
shadowBlur | 図形の周りに落とす影のぼかしレベル | 4 |
backgroundColor | 背景の色 | ‘transparent’ |
補足
- lineCapに指定できる値は、CanvasでのlineCapプロパティと同じで、’butt’、’round’、’square’の様です。
- lineJoinで指定できる値は、CanvasでのlineJoinプロパティと同じで、’bevel’、’round’、’miter’の様です…が、このプロパティは現在の仕様では、使うのに少々手間がかかります。
親クラスであるShapeクラスの描画設定で、lineJoinの値が’round’に指定されているので、子クラスであるPathShapeのlineJoinで違う値を指定しても’round’で描画されてしまうのだそうで、このプロパティを使うには、Shapeクラスに少々手を加えないといけないようです。
この事をご教授いただいたalkn203氏が、lineJoinを使う時のためのサンプルを作ってくださいました。リンクを下に張らせていただきますので、lineJoinを使いたい方はご参照ください。
メソッド
- setPaths(paths)
- 線を描きたい座標を複数まとめて設定します。その際、既にpathsプロパティに入っていた座標を全部上書きしてしまうので注意してください。
[引数]
paths:線を描きたい座標をVector2(x, y)の形で配列で指定します。 - clear()
- メソッド名そのまま、線を消します。
- addPaths(paths)
- 線を描きたい座標を追加で複数まとめて設定します。既にpathsプロパティに入っていた座標の後から追加する形になります。
[引数]
paths:線を描きたい座標をVector2(x, y)の形で配列で指定します。 - addPath(x, y)
- 線を描きたい座標を追加で設定します。既にpathsプロパティに入っていた座標の後から追加する形になります。
[引数]
x:x座標を指定します。
y:y座標を指定します。 - getPath(i)
- pathsに設定されている配列のi番目の座標を取得できます。
[引数]
i:取得したいpathsの配列の添え字を指定します。 - getPaths()
- pathsに設定されている座標を全部取得できます。
- changePath(i, x, y)
- pathsに設定されているi番目の座標を変更します。
[引数]
i:変更したいpathsの配列の添え字を指定します。
x:x座標を指定します。
y:y座標を指定します。
その他の直接触らなくて良さそうなメソッド
- calcCanvasSize()
calcCanvasWidth()
calcCanvasHeight()
prerender(canvas) - Canvasへの描画の為にいろいろ変換してくれているようです。
凄くシンプルに描画したもの
ソースコード
PathShape({
paths:[
Vector2(-100, 0),
Vector2(100, 0)
]
}).addChildTo(this).setPosition(this.gridX.center(), this.gridY.center());
色々といじって作ってみたもの
shioleap氏のこちらの作品を今回のサンプルを作るのに大変参考にさせていただきましたm(_ _)m
※注意:マウスカーソルやタッチ位置に反応して、模様や色などが変わりますが、あまり早く動かし過ぎると酔う可能性があります。(酔いましたorz)
ソースコード
// グローバル領域に展開
phina.globalize();
const W_HALF = 320; // スクリーン横幅の半分
const H_HALF = 480; // スクリーン高さの半分
/*
* メインシーン
*/
phina.define("MainScene", {
// 継承
superClass: "DisplayScene",
// コンストラクタ
init: function () {
// 親クラスの初期化
this.superInit();
// 背景の色
this.backgroundColor = "black";
// fill用PathShape
this.path = PathShape({
stroke: null
}).addChildTo(this).setPosition(W_HALF, H_HALF);
this.path.rotation = 45;
// stroke用PathShape
this.path2 = PathShape({
strokeWidth: 2,
}).addChildTo(this).setPosition(W_HALF, H_HALF);
this.path2.rotation = 45;
// 半径
this.radius = 100;
this.vr = 5;
},
// 更新
update: function (app) {
// マウスカーソルの位置取得
const p = app.pointer;
// 中心からマウスまでの距離
const x = p.x - W_HALF;
const y = p.y - H_HALF;
// (x, y)のベクトルを角度に変換
const deg = Vector2(x, y).toDegree();
// パスのクリア
this.path.clear();
this.path2.clear();
(16).times((i) => {
(15).times((j) => {
// 中心からの距離で算出した角度をラジアンへ変換して
const t = deg * Math.PI / 180;
// パスの位置へ加算・減算する
const r = (i) * 2 * Math.PI / 16 + t;
const r2 = (i + j) * 2 * Math.PI / 16 - t;
// パスの座標を算出
const x = Math.cos(r) * this.radius;
const y = Math.sin(r) * 100;
const x2 = Math.cos(r2) * 100;
const y2 = Math.sin(r2) * this.radius;
// パスの座標を追加
this.path.addPath(x, y);
this.path.addPath(x2, y2);
this.path2.addPath(x, y);
this.path2.addPath(x2, y2);
});
});
// 中心からの位置によって色を変える
this.path.fill = "hsla({0},100%,90%,1.0)".format(Math.floor(deg) - 150);
this.path2.stroke = "hsla({0},100%,85%,1.0)".format(Math.floor(deg));
// fill用のPathShapeの全体の位置とスケールをマウスの位置によって変える
this.path.setPosition(W_HALF - x / 4, H_HALF - y / 4);
this.path.setScale(1 + Math.abs(x) / W_HALF, 1 + Math.abs(y) / H_HALF);
// 半径の増減をさせて拡大縮小させている
this.radius += this.vr;
this.vr = (this.radius === 300 || this.radius === 0) ? -this.vr : this.vr;
},
});
/*
* メイン処理
*/
phina.main(function () {
// アプリケーションを生成
const app = GameApp({
// MainSceneから開始
startLabel: "main"
});
// fps表示
//app.enableStats();
// 実行
app.run();
});
補足
上のソースコード中に出て来るapp.pointerなどのマウスカーソルやタッチの位置を取得する方法や、同じくソースコード中で出てきたsetScale(…)のような、スケール変更等の方法については下記の記事でそれぞれ説明しておりますので、よろしければご覧ください。
ご意見・ご感想、また、ここ間違ってるよとか、もっといい方法あるよといったご指摘などございましたら、お手数ですがコメント欄や当twitterアカウントへお願いしますm(_ _)m