2021年4月20日火曜日

html-to-image で HTML を画像化する

HTML を JavaScript で画像にしたいニーズはそれなりにあります。 スクリーンショットを取りたいとか、案外使います。 そのような時に、これまで html2canvas というライブラリが非常に有名で、私も使っていました。

しかし html2canvas は正直に言って「非常に難しい」アプローチで実装されてるライブラリです。 言ってしまえば HTML/CSS の機能を完全にエミュレートしながら canvas に描画しているようなものです。 仮に一瞬完璧なものができたとしても、メンテが地獄であることは間違いありません。 正直、キツイと思う。 そんな中、ふと html-to-image という神ライブラリを見つけてしまいました。 html-to-image は、 dom-to-image という古のライブラリをメンテしやすく実装し直したライブラリです。

html-to-image は非常に頭の良い HTML の画像化をしています。 具体的には、画像化したい DOM を clone して、SVG の <foreignObject> として読み込みます。 SVG を画像化する API はブラウザに整っているので、特に複雑な処理をするまでもなく、toDataURL() で画像化できるという仕組みです。 考慮するべきは、Web フォントや HTML 内の画像くらいで、html2canvas のような超絶技巧は必要としません。 コードをチラ見してみても、非常にシンプルなコードで記載されていることがわかります。

そんなに簡単な方法があるのになぜ今まで採用されなかったかと言えば、Safari で <foreignObject> がセキュリティ的に動かなかったためのようです。 しかし、dom-to-image の issue を見ていると Safari 12 で動くようになったとのことです。 また私も iPhone Safari で確認してみたのですが、きちんと動いています。 ………つまり、始まったな? と考えて良いのではないでしょうか。

早速適当にページを作って変換してみたところ、ほぼ完璧に画像化できています。 ほんの少し変換が完璧でないところがある気がする (例えば <progress>) のですが、実用上は問題を感じることは少なそうで、かなり期待できそうな状態です。 駄目なケースとかまだよくわかってないのですが、あまりにも簡単な方法で画像化を実現できるので、html2canvas より安定するのではないかという期待もあります。 ライブラリ自体の進化は、dom-to-image の更新が停止しているので、 html-to-image のほうを見ていけば良さそう。

実装例

html-to-image はビルドが必要なので、 dom-to-image の実装例を残しておきます。使い方はほとんど一緒。以下のようにシンプルです。
var input = document.getElementById('dom-to-image-in');
var output = document.getElementById('dom-to-image-out');
domtoimage.toPng(input).then(function (dataUrl) {
  var img = new Image();
  img.src = dataUrl;
  output.appendChild(img);
}).catch(function (error) {
  console.error('oops, something went wrong!', error);
});

2021年4月10日土曜日

フリゲ紹介: ミカゲ・キューブ

ミカゲ・キューブ は、SFノンフィールドカードバトルゲーム。 第1回新人フリーゲームコンテスト「準グランプリ」受賞作品の作品です。 昔は「コンテストパーク」という賞金付きのコンテストがあったようなのですが、 それを彷彿とさせる賞金付きコンテストとして、新人フリーゲームコンテスト ができました。 面白い時代になったものだなあ。



10年前、突如として現れた未確認飛行物体「キューブ」、そしてその脅威を取り払った英雄「ミカゲ」 (左下)。 再び現れたキューブを打破すべく 3人の主人公が立ち向かい、キューブとミカゲの謎を解き明かす物語です (右下)。 1人1プレイ1時間でクリアでき、合計3-4時間くらいの作品。



カードを集め、デッキを組み、カードを駆使して敵を撃破しながら、ノンフィールドで奥に突き進んでいく。 そういえばノンフィールドとカードゲームの組み合わせって、これまで見たことなかったかも? SF なストーリー要素もいい感じに組み合わさっていて、雰囲気も良かったです。

一番良かったのはやはりバトル部分だと思います。 3人の主人公はそれぞれ特性がまったく異なるので、全員プレイしてもまったく飽きることがありません。 私は3人とも特性特化でプレイしましたが、全員とても面白かった (下)。 ちなみにミカゲ・キューブでは行動力加算型のカードバトルを採用しています。 行動力加算型バトルは最近増えてきた気がするのですが、割と評価が両極端に分かれやすいシステムだと思ってます。

色々な作品をやってみて重要かなと思うのは、低行動力の時に様々な行動ができることじゃないかと思ってます。 低行動力のときに何もできなくなってしまうことが結構あるのですが、ミカゲ・キューブでは低行動力のときのカードが豊富で良かったです。 というより低行動力のカードに好きなものが多かったので、私は低行動力重視でプレイしていました。 あとはやはり状態異常ですね、行動力に関する状態異常を用意したのは凄く面白かった。 プレイヤーを常に考えさせ、面白さを引き出していたのが印象的でした。



カードバトルの自由度を生み出す仕組みが凄く上手で、面白かった作品でした。

フリゲ紹介: GRASLAY

GRASLAY はレトロ風横スクロールシューティングゲームです。 パワーアップは無く、3種類の武器組み合わせだけでクリアできるのが特徴です。 名前からして、アクスレイとグラディウスのオマージュなのかな?



非常にカジュアルなステージ、ボス構成で、サクサクプレイできる作品でした。 難易度はサクサク感とは裏腹に、意外と難しいかも? ステージはギミックが非常に効いていて、作者様の意図通り、だいたいの罠にハマりました。 ぐぬぬ…トラップがよくできている…。 あとは高速ステージがやはり死亡率高く、NORMAL では最終ステージに結構てこずりました。 とはいえ EASY モードを選べるので、初心者にも優しい設計になっています。

パワーアップがないのは、難易度の高いステージで大量死を防ぐ意味でわかりやすい気がします。 最初は最終ステージとラスボスでコロコロ死んでいたので、そういう時にはありがたさを感じました。 最近はサクサクなシューティングゲームがたくさん出てきて、でも凄い面白いものが多くて、とても参考になりますね。 ゲームのプレイ感覚は作者様の動画を見ると何となくわかると思う。



そしてこのつぶやきにもある通り、なんと GitHub でコードが公開されています。 これはゲ制沼の住人も、超々参考になるのではないかと思います。 コードは Pygame で作られており、1万4000行 (空白を無視すると11500行くらい) でした。 シューティングゲームって作ったことないんですが、そんなに少ないコードで書けるんだなあ。 とはいえコード以外の事に悩むことのほうが多いでしょうから、通常のコードと比較すると数倍換算すべきと思います。 凄く参考になりました。

フリゲ紹介: Stick Robot

Stick Robot新人フリーゲームコンテスト に投稿されていた作品。 ブロックをくっつけて、はなすことができるロボットを操作してゴールを目指すパズルゲームです。



シンプルでとても面白い作品と思いました。 パズルゲームって色々なものがありますが、私は面白い作品ってだいたい以下のようなルールがあると思ってます。
  • ルールのシンプルさ
  • 状態破壊が少なくリトライ性が高い
  • スタートから終盤までのゲームバランス

日本には最強のパズルゲーム: 詰将棋がある訳なんですが、詰将棋の名作はパズルの面白さをわかりやすく説明してくれます。 詰将棋って幅=選択肢、深さ=手数とすると「深さは浅いけど幅が広い」とか「幅は狭いけどわかりやすい深さ優先探索問題」というのが重要だと思うんですよね。 ちなみに幅も深さも広すぎると、問題としては難しくなり過ぎるので、適度な難しさが必要です。 パズルゲームのゲームバランスにも同じことが言えます。

そしてつい最近、詰将棋的に解ける ネコトパズル を遊んで痛感したのは、状態が崩れると一気に読みにくくなるというところ。 それが面白さに通じる時もあるけど、崩れすぎると難しくなり過ぎる。 何より状態破壊が多すぎると、リトライする時に最初からになって手間が増える問題があります。 なので適度に状態を破壊しつつ、読んでけばきちんと解けるというのがパズルとして一番面白いのではないかと思ってます。

Stick Robot はまさに上記のルール通りのパズルゲームで、非常に面白かったです。 ゴール条件がわかりやすいため、逆算して読めるのがポイントだと思います。 そして状態破壊もほとんどなく、ルールもシンプル。失敗してもすぐにリトライできる。まさに王道。 どんなゲームかは以下の画像を見ればだいたいわかると思う。

itch.io より引用


難易度はかんたんめと思いますが、解き終わった後にすっきり感のある作品でした。

フリゲ紹介: Clean Out The House

Clean Out The House は、マウスを使ってゴミ(ほぼ空き缶)を狙い、クリックでゴミを撃って飛ばし、ゴミ箱に入れるゲームです。 フリーウェアというよりはカンパウェアになっているので、面白かった人はぜひ投げ銭も。



誰でも一度は考える、ゴミ捨ての自動化、そして空き缶の射撃。 その2つを組み合わせてゲームにしたのは、うまいなーと思いました。 リアルでは大変ですが、ゲームではそれほど難易度が高くなく、ゲームとして単純に面白い。 そしてなんと 100ステージ以上も用意されているので、長く楽しめます。



操作方法やシステムはゲーム内で解説をしてくれるので、非常にわかりやすいです (左下)。 空き缶を射撃するにしても、高く飛び上がらせたり、吸い寄せたり、マウスの左右クリックだけで操作するにしては、結構色々な要素があって新鮮でした。 空き缶の下を射撃して高く飛び上がらせるとか、リアルでやったら超難しそう…。 リアルじゃできないことができるゲームって素晴らしい。

各ステージは何個かの空き缶を片付けることがクリア条件になっています。 時には難しいステージもあり、失敗をくり返すと片付けているのか散らかしているのかわからなくなることも。 空き缶の耐久力が少ないステージは、たまに残骸で埋め尽くされます (右下)。



シンプルながら面白いゲームでした。

2021年4月7日水曜日

JavaScript で Drag & Drop

JavaScript で Drag & Drop をしようとして少しハマりました。 まずライブラリなどを使わなくても Drag & Drop は API で実装できる のですが、 サポート状況が微妙なので今のところあまり使えません。 また Web 標準で用意されている機能は Drag を開始しても元のオブジェクトを表示したままで、Drop した瞬間に元とのオブジェクトの表示を消すという動作をします。 少し直感的でない動作で、API もわかりにくい部類に入る気がする。 そんな訳で API を使わずマウスイベントで作るのが普通で、作り方は以下がわかりやすいですね。

巷のライブラリが提供する最低限のこと

それではほとんどの Drag & Drop ライブラリは何をやってくれるのでしょう。 Drag した瞬間に要素をマウスカーソルに追随して、Drop した瞬間にイベントで処理をします。 このへんの機能を提供するのが巷の Drag & Drop ライブラリという訳です。 あとは実際触ってみると、どのライブラリもイベント周りを自作するより簡単にしてくれていますね。 例えばクリックなのかドラッグなのかは、必ずチェックが必要です。 普通に実装すると動いたか動いてないかで場合分けが必要でちょっと面倒。そういう細々としたところを改善してくれる。

多くのライブラリの仕様はちょっと不思議

Drag & Drop ライブラリは、例えば以下のようなライブラリがあります。 多くのライブラリはソートを基本動作にしていることが多く、 案外融通の効かないライブラリが多い印象です。 私は別にソートとかいらないんだよなあ。 そうでないものも、Drag 要素と Drop 要素を宣言的に扱っていることが多く、A→B への Drag 機能を提供するもの、しかも A の中の要素群に対してまとめてイベントを発行するものが多いです。 これ Drag 要素と Drop 要素がたくさんあると、扱いが大変な気がする。 たぶん1対Nでイベントを貼って、Drop したらイベントを貼り直すという作業が必要になる。 やはりあまり融通が効かない感はあります。 どうしてそういう実装になってるのかよくわからないのですが、何か難しいところがあるのかも知れません。 そんな中、desandro/draggabilly はかなり融通が利くライブラリに見えました。

overflow: hidden; に注意

desandro/draggabilly は実際、非常に融通の利くライブラリで、 要素それぞれに Drag & Drop のイベントを設定できます。仕様としても非常にわかりやすい。 ただ実際に実装してみると色々な課題があることがわかりました。 ちなみにこれは自前実装するときにも起きる問題です。 真っ先にハマったのは、overflow: hidden; なオブジェクトから Drag & Drop をするときの表示でした。 Drag & Drop を開始すると、そのオブジェクトの外に出た時点で表示が消えてしまいます。 他にも z-index などの影響は受けやすいです。 移動中にあえて表示を消したい時もあるかもしれませんが、普通はそのような動作は望まないだろうと思う。

上記の問題を避けるには、ほとんどのケースでいったん別のオブジェクト (document.body など) に Drag 要素を移動して、 移動ぶんの座標をずらしながら絶対座標でマウスカーソルに表示を移動するのがより良い動作とわかります。 そのへんだけ修正すると結構いい感じに動作しました。 無理やり絶対座標に変換するので、イベントを張り直す必要があって多少面倒だけど、それくらい。 直すのが少し面倒そうだし、他のライブラリを使ってもどうせ張り直す必要があるので、効率が少し悪いけど別にいいやと。 desandro/draggabilly はサンプルも多いし、たぶん現時点で一番使いやすいライブラリと思う。

今後再び Drag & Drop を実装したり、やっぱ自前で実装しようとなったときに overflow: hidden; と z-index あたりの知見を残しておきたかったので、メモを書いておきます。

2021年4月1日木曜日

2025年からの大学入学共通テストが面白い

2025年からの大学入学共通テストは、出題教科・科目の再編に伴い、 初めて出題される「情報」「歴史総合」「地理総合」「公共」が新設されます。 サンプル問題 も公表されましたが、これがなかなか面白く、 今後の日本で求められる力がよく表れています。

情報処理能力さえあれば解ける

サンプル問題を解いてみた印象を一言で言ってしまえば、この4教科に暗記知識はほぼ必要なくなりました。 常識的な範囲の知識だけあれば十分で、 情報処理能力さえあれば問題が解けます。 一定以上の思考力さえあれば余裕。 暗記的要素があるのは、むしろ再編されていない英語・理科・数学のほうなくらい。 ただ英語も読めれば解けるみたいな感じで、かなり楽になってますよね。 良い時代 (?) になったものです。

また先ほど「情報処理能力」と短く書いてしまいましたが、平たく言えば論理的な国語能力ではあります。 グラフなんかも複雑なものは出てこないので、文章が読めるかどうかという話。 ただ筆者の気持ちを答えるようなこれまでの国語能力とは異なります。 求められているのは分散した数多くのデータと文章を頼りに、論理的に正解を導き出す力です。

飛び級がより現実的になった

情報処理能力さえあれば解けるので、 文系学部は文章を正確に読めるハイレベル小学生はもしかすると合格できるのではないかと感じます。 ハイレベル中学生はかなり余裕を持って合格できるはず。 逆に文章を正確に読めない子は、今の大学生でも解けないことも、あるのかも知れません。 これ中学受験のトップ層とか、いきなり大学受験いけるんじゃないのかね。 まあ昔からそんな気はしているのですが、より現実的になりました。 特殊算やるくらいなら大学受験しようみたいな。

今後は飛び級入試がどんどん広がっていきそうですし、 広げていくべきではないかと感じる内容でした。 あくまで同じような路線で文系大学のレベルを維持し高めていくには、より高度な情報処理能力が求められます。 なぜならサンプル問題は、中学生でも高得点取れると思うから。 文章力だけで高めることには限界があるので、より高度な処理能力となると、数学か情報しかありません。 そして文理問わず統計を扱うには高校数学がわからないと話にならない以上、どちらかと言えば数学が重視されるかと思います。 早稲田が数学必須になりましたが、新設のサンプル問題を解いてみると、必然の判断な気がする。

大学ってなんなん?

中学生でも余裕を持って入れるとなると、大学ってなんなん?という気は正直してきます。 今後は以下のような路線が増える気はしますね。 以下の記事はかなり本質的なことを書いてあって、数学やってると成績も上がり、就職も良くなった、と。



情報処理能力、思考力、我慢力

情報処理能力は物事の本質を考えるための必須能力であり、 学問を学び続けたり、研究を行うためにも必須能力とも言えます。 暗記ではなく考える習慣がどんどん重要性を増していることは間違いないでしょう。 またあまり語られませんが、もう一つ重要な能力があるんじゃないかと思っています。 それは答えを導き出すまで我慢強く考える粘り強さです。 答えをすぐに知れる現代社会では、思考力と我慢力が弱くなっています。

情報処理能力、思考力は昔の日本教育でも要求されなかった力です。 ただ代わりに熾烈な競争と、上昇志向があったので、我慢力だけで機能していたのだろうと思います。 今はそれらがないので、本来必要だった力を重視されるようになったとも言えます。

一生懸命遊べば大学行けそう

問題を解いていて思ったのですが、プログラミングや囲碁将棋の頭脳ゲームをやってる人は、受験勉強とか何もしないでクリアできるかも。 この3つはわかりやすくすべての能力を鍛えられる。 まあ頭を使う他の分野も、レベルが上がってくるとだいたい上記の能力は絶対条件として求められます。 例えば作曲とかもそうだよね。

数学やレベルに関しては気になるところが色々ありますが、多くの人にとっては大学の意味を考える良い機会なのかなと思います。 良いところだけを見れば、趣味に没頭してるだけで大学受験はクリアできる人が増えそうな気はしてます。 そして大学でさらに趣味に磨きを掛けられる。いいなーこれ。