LoginSignup
16
2

More than 3 years have passed since last update.

MutationObserver, IntersectionObserver, elementFromPointを使ってクソゲーを作る

Last updated at Posted at 2019-12-02

テックタッチアドベントカレンダーの3日目を担当する @92thunder です。
2日目は @smith-30 による 初めての ECS でした。ちなみに自分は手元のDocker環境が動かなくなったのでバックエンドを触れなくなってしまいました。

できたもの

See the Pen Demon Play with IntersectionObserver , MutationObserver, elementFromPoint by Ryota Kunisada (@92thunder) on CodePen.

  • MutationObserver, IntersectionObserver, elementFromPointを使って鬼ごっこゲームを作りました
  • 素晴らしい名作ゲームが簡単に完成してしまいましたね
  • 所要時間2時間

Mutation Observer

DOMの変更を監視するためのAPI
オプションを設定することで子孫全部やstyleが変わった場合だけ反応するよう設定できる
https://developer.mozilla.org/ja/docs/Web/API/MutationObserver

subtreeオプションを有効にしてdocument.bodyなどに対して使うとページ読み込み時など動作が重くなってしまうので使いどころに気を付けたほうが良さそうです。
今回のゲームではPlayerとEnemyの要素が動くたびにスタイルが変わっていてその変更時に毎回elementFromPointによる衝突判定が行われているので敵を大量に増やすとパフォーマンスが残念なことになりそうです

// コールバックの設定とオブザーバインスタンスの設定
const observer = new MutationObserver(() => {
  console.log('DOMに変更がありました')
})

// document.bodyを対象に監視を開始する
observer.observe(document.body)

// 監視を止める
observe.disconnect()

Document.elementFromPoint

左上を起点として、座標位置にある要素を返す
iframe中の要素だった場合はiframeを返すため、iframeを考慮した使い方が必要
https://developer.mozilla.org/ja/docs/Web/API/Document/elementFromPoint

今回のゲームではPlayerの上にEnemyが重なっているかの判定に使っていて、重なったら負けになるよう実装しています
テックタッチでは、これを使うと座標の上に何の要素が表示されているのかがわかるので、要素が隠れているかどうかなどの判定に使っています

// 100, 100の位置にある要素を返す
const element = document.elementFromPoint(100, 100)

// Node.containsと合わせて使うことがよくあります
const app = getElementById('app')
if (app.contains(element)) {
  // appに含まれているので無視
  return
}

IntersectionObserver

対象の要素と祖先もしくは最上位のビューポートと交差したタイミングでコールバックを実行する
スクロールを使ったコンテンツの遅延読み込みなどに使う
オプションでrootを指定して交差判定に使う要素や交差の閾値を設定できる
IEはサポートされていない

IntersectionObserverを使って画面の範囲外に出たら負けになるよう実装しました
交差の閾値(要素が何%はみ出ているか)を設定できるので50%の0.5を設定しています
https://developer.mozilla.org/ja/docs/Web/API/IntersectionObserver

// コールバック設定
const observer = new IntersectionObserver(() => {
  console.log('交差しました')
})

// #targetの要素とビューポートの範囲外に出るor範囲内に入るたびにコールバック関数を実行
observer.observe(document.getElementById('target'))

// 監視を止める
observe.disconnect()

所感

  • 3つとも今年初めて知ったAPIで普通の開発ではあまり使わなさそうだがとても便利
  • テックタッチは外部サービスにembedして機能するサービスのため、このような普段の開発では使わないような機能をふんだんに使って開発をしています

4日目は @terunuma による「4Kモニタ環境で1年間Web開発してみた所感」です。

16
2
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
16
2