Sato's Tech Memo

備忘録と情報共有を兼ねたメモです

PixiJSでライン描画&クリック判定

ライン描画

var obj = new PIXI.Graphics();
obj.lineStyle(2, 0xff0000);//線幅、線色
obj
    .moveTo(0,0)
    .lineTo(100, 100);

クリック判定

テキストオブジェクト等だと、以下のような感じでクリックイベント取得できるが、
ラインの場合は、単純にこれではできない。

var obj = new PIXI.Text("AAA", {font:'10pt Arial', fill:'white', stroke:'red', strokeThickness :5});
obj.interactive = true;
obj.on('click', function(){
    //クリックされたときにやること
});


PIXI.Graphicsをクリックイベント取得させる場合は、
以下のように、そのオブジェクトがクリックされたと検知する範囲を指定する必要がある。

let rect = new PIXI.Rectangle(x1, y1, x2, y2);
obj.hitArea = rect;

ライン描画しているのと全く関係ないエリアをヒットエリアとして
指定することもできる。
f:id:satoko_szk:20181202200252p:plain
(この性質を利用した、ちょっとしたゲームとかも作れそうだ)


というわけで、こんな感じにヒットエリアのRectangleを生成すればいい。
f:id:satoko_szk:20181202200243p:plain
ラインの実際の幅だとクリック困難なので、幅を広めにしてヒットエリアにする。

var obj = new PIXI.Graphics();

let x=100;
let y1=100;
let y2=200;

//ヒットエリアの描画
let width = 20;//ヒットエリアの幅
let rect = new PIXI.Rectangle(x-width/2, y1, width, y2-y1);
obj.beginFill(0xffffff, 0); //ヒットエリアは透明
obj.drawShape(rect);
obj.endFill();

//線描画
obj.lineStyle(2, 0xff0000);//線幅、線色
obj
    .moveTo(x, y1)
    .lineTo(x, y2);

obj.interactive = true;
obj.hitArea = rect;

obj.on('click', function(){
    console.log('click');
});

そうすると、こんな感じに線の周りのヒットエリアのクリックイベントを検知できるようになる。
f:id:satoko_szk:20181202200247p:plain
※ヒットエリアを半透明で表示しています。

斜め線の場合

まっすぐな線ならば、上述のやり方で四角形を描画すればいいが、
じゃあ、斜め線の場合、どうするか。

以下のようにする。
f:id:satoko_szk:20181202200257p:plain

  1. 原点(0,0)を基準にして、ヒットエリアと線を描画
  2. オブジェクトを移動・回転する

実際のソース

var obj = new PIXI.Graphics();

let width = 20;//選択エリアの幅
let x1=100;
let y1=100;
let x2=200;
let y2=200;

//ラインの長さ
let height = Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));

//原点を基準に四角形を描画
let rect = new PIXI.Rectangle(0-width/2, 0, width, height);

obj.beginFill(0xffffff, 0); //選択エリアは透明
obj.drawShape(rect);
obj.endFill();

//線描画
obj.lineStyle(2, 0xff0000);//線幅、線色
obj
    .moveTo(0, 0)//原点を基準に描画
    .lineTo(0, height);

//起点を移動
obj.position.x = x1;
obj.position.y = y1;

//回転させる
obj.pivot.set(0, 0);//回転の原点をセット
let theta = Math.atan2(x2-x1, y2-y1);
obj.rotation -= theta;

obj.interactive = true;
obj.hitArea = rect;

obj.on('click', function(){
    console.log('click');
});

結果
f:id:satoko_szk:20181202200857p:plain

ラインを再描画する場合は、いったん、回転軸とポジションをリセットしてから新たに描画しなおす。

obj.clear();
obj.rotation = 0;
obj.position.set(0,0);


Box