こんにちは、フロントエンドエンジニアのはっちゃんです。最近は抜け毛を気にすることもなくなりました。
突然ですが今回は、canvas用ライブラリを使って「canvasに頭皮と一本の毛をおいて、ドラッグして引っ張って抜く」アクションを作ってみようと思います。
準備するもの
ゲーム用ライブラリ「phina.js」
-アイディアを即座に形にできるゲームライブラリです
-初心者でも手軽にゲームを開発できます
-様々な Web コンテンツ, アプリで多数の採用実績があります
-大学や専門学校といった教育機関で利用されています
-国産かつオープンソースでTwitter 駆動開発なので気軽にコントリビューターになれます
以前シスコくんが使い方を書いてくれているので、こちらも読んでおくといいでしょう。 はじめてのphina.js – JavaScriptゲームライブラリを使ってみた!
1本の毛
イラレでサクッと作りました。こいつを引っこ抜いていきます。
HTML、CSS、JSコーディング
ではコーディングしていきましょう。
HTML
<div id="example"></div>
<div id="js-modal-bg" class="modal-bg dn">
<div class="modal">
<img src="https://82mou.github.io/src/images/moukon.png" alt="">
<p class="modal__text">毛が抜けました</p>
<span id="js-btn" class="btn">もう一回抜く</span>
</div>
</div>
CSS
.modal-bg {
position: fixed;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
padding: 20px;
background: rgba(255, 255, 255, 1);
border-radius: 6px;
z-index: 1;
text-align: center;
img {
width: 40px;
}
}
.modal__text {
margin-top: 20px;
}
.btn {
display: inline-block;
margin-top: 10px;
padding: 0.3em 1em;
text-decoration: none;
color: #67c5ff;
border: solid 2px #67c5ff;
border-radius: 3px;
transition: .4s;
}
.btn:hover {
background: #67c5ff;
color: white;
}
.dn {
display: none;
}
JS
それではJSで機能を実装していきます。
作る前に、必要なイベント、関数を洗い出しておきましょう。
-
- phina.jsを使用する準備
- 1本の毛画像の読み込み
- 毛画を抜いた時の効果音の読み込み
- シーンの作成
- 頭皮レイヤー作成
- 毛レイヤーを作成
- マスクを作成
- タッチした時のイベントを作成
- タッチ中のイベントを作成
- 一定数動かした時にモーダルを表示させる
- タッチ後のイベントを作成
- codepenのリセット
- レンダリング
あとはこれにそってコードをガンガン描いていくだけです!
// グローバルに展開
phina.globalize();
// アセット
var ASSETS = {
// 画像
image: {
'moukon': 'https://82mou.github.io/src/images/moukon.png',
},
sound: {
'sound': 'https://82mou.github.io/src/sound/cork-plug1.mp3',
},
};
/*
* メインシーン
*/
phina.define("MainScene", {
// 継承
superClass: 'DisplayScene',
// コンストラクタ
init: function(option) {
_this = this; // thisを保存
this.pullFlg = false; // 抜いたかどうかのフラグ
// 親クラス初期化
this.superInit(option);
// CircleShapeを作成
let circle = CircleShape({
radius: 1000,
fill: "#FFD8BD",
stroke: 0
}).addChildTo(this).setPosition(this.gridX.center(),this.gridY.center(15));
// スプライト画像を作成
this.sprite = Sprite('moukon').addChildTo(this);
// スプライト画像の初期位置設定
this.sprite.x = this.gridX.center();
this.sprite.y = this.gridY.center(-1.5);
this.sprite.width = 80;
this.sprite.height = 204;
this.sprite.backgroundColor = 'red';
// スプライト画像の初期設定を保存
this.firstInitialPositionX = this.sprite.x;
this.firstInitialPositionY = this.sprite.y;
this.firstHeight = this.sprite.height;
// スプライト画像の原点を左上に設定
this.sprite.origin.set(0.5, 0);
// マスクを作成
let mask = RectangleShape({
fill: '#FFD8BD',
stroke: 0,
width: 120,
height: 300
}).addChildTo(this).setPosition(this.gridX.center(),this.gridY.center(2));
// スプライト画像のドラッグ可能にする
this.sprite.draggable;
// ドラッグ開始時
this.sprite.ondragstart = () => {
// ドラッグで中心より左右にずれたら中心に戻す
this.sprite.x = this.gridX.center();
// ドラッグで中心より下にずれたら中心に戻す
if(this.sprite.y > this.gridY.center()) {
this.sprite.y = this.gridY.center();
}
};
// ドラッグ中
this.sprite.ondrag = () => {
// ドラッグで中心より左右にずれたら中心に戻す
this.sprite.x = this.gridX.center();
// ドラッグで中心より下にずれたら中心に戻す
if(this.sprite.y > this.gridY.center()) {
this.sprite.y = this.gridY.center();
}
// spriteの移動量を保存
this.afterPositionX = this.firstInitialPositionX - this.sprite.x;
this.afterPositionY = this.firstInitialPositionY - this.sprite.y;
// spriteの移動量 + 補正値でドラッグ後の高さを保存
this.afterHeight = this.firstHeight + (this.afterPositionY + 100);
// spriteの移動後の高さが元の高さより小くならないように設定
if(this.afterHeight < this.firstHeight) {
this.sprite.height = this.firstHeight;
} else {
this.sprite.height = this.afterHeight;
}
// 一定数毛を上にドラッグしたら発火
if(!this.pullFlg && this.sprite.y < 150) {
this.pullFlg = true;
// spriteのheightを1.5秒かけて元に戻す
this.sprite.tweener.to({height: _this.firstHeight}, 1500, 'easeOutElastic')
// 音再生
SoundManager.play('sound');
setTimeout(() => {
document.querySelector('#js-modal-bg').classList.remove('dn');
},700);
}
};
// ドラッグ終了時
this.sprite.ondragend = () => {
// ドラッグで中心より左右にずれたら中心に戻す
this.sprite.x = this.gridX.center();
// ドラッグで中心より下にずれたら中心に戻す
if(this.sprite.y > this.gridY.center()) {
this.sprite.y = this.gridY.center();
}
};
// codepenをリセット
document.querySelector('#js-btn').addEventListener('click', () => {
history.go(0);
});
}
});
/*
* メイン処理
*/
phina.main(function() {
// アプリケーションを生成
var app = GameApp({
// MainScene から開始
startLabel: 'main',
width: 2000,
height: 1000,
// アセット読み込み
assets: ASSETS,
})
// 実行
app.run();
});
完成
See the Pen
pull out animation by k_hatsushi (@hatsushi_kazuya)
on CodePen.
- 操作方法
- 毛を引っ張ってみよう!
まとめ
いかがでしたか? 引っ張るときや抜けるときのアニメーションをこだわるとよりリアルになりそうですね! みなさんもよろしければ試してみてください! はっちゃんでした。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。