tag:crieit.net,2005:https://crieit.net/users/h-yoshikawa0724/feed よしの投稿 - Crieit Crieitでユーザーよしによる最近の投稿 2021-02-15T14:38:44+09:00 https://crieit.net/users/h-yoshikawa0724/feed tag:crieit.net,2005:PublicArticle/16064 2020-09-20T19:25:58+09:00 2021-02-15T14:38:44+09:00 https://crieit.net/posts/2-5f672e364d13b ハッカソンイベントで、「2」に近い式をあてるゲームを作ってみた <p>こんにちは、最近「個人開発ガリガリやって実力つけたいなー」と思っているよしです。<br /> 先日、web1week に参加してきました。<br /> 色々とてんやわんやしながらも、なんとか投稿までいけたので、レポートを残しておきますー。</p> <h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2> <h3 id="web1week の概要"><a href="#web1week+%E3%81%AE%E6%A6%82%E8%A6%81">web1week の概要</a></h3> <p>「1週間でお題に沿った Web サービスを作ってみよう」というハッカソン的なイベントです。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">9/7~9/13の1週間でWebサービスを作るイベントです! Hello worldレベルのサービスでもOKですのでぜひご参加をお願いします! <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2?src=hash&ref_src=twsrc%5Etfw">#駆け出しエンジニア</a> 仲間が多い方は是非シェアもお願いします~お題は「2」です。<a target="_blank" rel="nofollow noopener" href="https://t.co/cl4XbPFici">https://t.co/cl4XbPFici</a></p>— だら🎄いろいろつくってる (@dala00) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/dala00/status/1302622342951002115?ref_src=twsrc%5Etfw">September 6, 2020</a> </blockquote> <h3 id="参加したきっかけ"><a href="#%E5%8F%82%E5%8A%A0%E3%81%97%E3%81%9F%E3%81%8D%E3%81%A3%E3%81%8B%E3%81%91">参加したきっかけ</a></h3> <p>前回も参加して楽しかったので。</p> <p>前回参加の時は割と使える時間が多かった一方、今回は仕事が終わった後か休日に開発することになりました。<br /> なので、最初はどうしようかとも思いましたが、他の参加者の皆さんの多くは同じ状況下で開発されているはずなので、まぁどうにかなるだろう...くらいの気持ちで参加してました。</p> <p>※前回参加時のレポート記事<br /> - <a href="https://crieit.net/posts/ac044ef3dd9b2580f6a86c0ac05881c1">ハッカソンイベントで、React Konva 製のジグソーパズルっぽいパズルを作ってみた</a></p> <h2 id="自分が作ったもの"><a href="#%E8%87%AA%E5%88%86%E3%81%8C%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE">自分が作ったもの</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://h-yoshikawa44.github.io/close-to-2/">Close to 2</a></p> <p>今回のお題は「2」ということで、<br /> 計算結果が一番「2」に近い式をあてるゲームを作りました。<br /> 一応、スマホでも遊べます。</p> <p><a href="https://crieit.now.sh/upload_images/cebd6c87a2c39e160ba6ee313b71e37d5f672cc56b863.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/cebd6c87a2c39e160ba6ee313b71e37d5f672cc56b863.gif?mw=700" alt="close-to-2-overview.gif" /></a></p> <p><a href="https://crieit.net/boards/web1week-202009/Close-to-2">イベントボードへの投稿</a>から引用。</p> <blockquote> <p>初級、中級、上級で遊べて、難易度が高いほど長い式になり、30秒で何問正答できるかな?というゲームです。<br /> 自分で作っておいてなんですが、暗算得意じゃないと無理ゲーじゃねーかと思いました。</p> </blockquote> <h3 id="なんでこれを作ろうとしたのか"><a href="#%E3%81%AA%E3%82%93%E3%81%A7%E3%81%93%E3%82%8C%E3%82%92%E4%BD%9C%E3%82%8D%E3%81%86%E3%81%A8%E3%81%97%E3%81%9F%E3%81%AE%E3%81%8B">なんでこれを作ろうとしたのか</a></h3> <p>こちらもボードへの投稿に書いていたので引用。</p> <blockquote> <p>元々は「2」に関するクロスワードを作ろうとしていたのですが、「2」縛りで問題を考えるのがしんどいの極みだったので変えました(しかも土曜...)<br /> その時点ですでに投稿されていた方(特に、きらぷかさんとDE-TEIUさん)の作品を見て、シンプルなゲームでも十分面白いものが作れるんだなぁと思い、今回の作品に至りました。<br /> (他の方の作品を参考にさせていただきましたが、丸パクリレベルになってしまわないよう気を付けたつもりです)</p> </blockquote> <h3 id="技術構成"><a href="#%E6%8A%80%E8%A1%93%E6%A7%8B%E6%88%90">技術構成</a></h3> <p>最初は前回同様、Docker の Node.js コンテナを使おうとしてました。<br /> ただ、yarn コマンドやアプリ自体の動作速度、VSCode で開発する上での環境など色々考えたらめんどくさくなったので、WSL の Node.js を使いました。<br /> (フロント開発でわざわざDocker使う意味ある?という議論も見かけたことがあったので...)</p> <p>本番は GitHub Pages でホスティングしています(gh-pages でデプロイ)</p> <p>使用した主なライブラリはこちら<br /> - React:言わずと知れたUI構築ライブラリ(create-react-app で導入)<br /> - Material UI:UI コンポーネント集<br /> - React Share:各種 SNS のシェアボタン集<br /> - React Snap:SPA の OGP設定<br /> - PropTypes:props のバリデーション<br /> - ESLint:静的解析<br /> - Prettier:コードフォーマッター</p> <p>前回同様、基本的な UI は Material UI で構築。<br /> 一部、前回作ったコンポーネントを流用したものもあります。</p> <h3 id="どんな感じで開発してたのか"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E6%84%9F%E3%81%98%E3%81%A7%E9%96%8B%E7%99%BA%E3%81%97%E3%81%A6%E3%81%9F%E3%81%AE%E3%81%8B">どんな感じで開発してたのか</a></h3> <p>大体こんなでしたが、「8日目」があるところからわかるように、1日遅刻投稿です(苦笑)</p> <h4 id="1日目:9/7(月)"><a href="#1%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F7%28%E6%9C%88%29">1日目:9/7(月)</a></h4> <p>「2」というお題を目にして、何を作るか悩みました。<br /> 前回、React Konva というライブラリを使用したので、今回も何かライブラリを使おうかと Reactのライブラリを調べてました。</p> <p>そこで <a target="_blank" rel="nofollow noopener" href="https://github.com/JaredReisinger/react-crossword">GitHub - React Crossword</a> という、クロスワードを作れるライブラリを見つけ、これで何かやろうかな?となりました。</p> <h4 id="2日目:9/8(火)"><a href="#2%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F8%28%E7%81%AB%29">2日目:9/8(火)</a></h4> <p>クロスワードで何かするのであれば問題を考える必要があります。<br /> とりあえず環境構築だけしておこうと、この日はリポジトリ作って環境構築まで。</p> <h4 id="3日目:9/9(水)"><a href="#3%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F9%28%E6%B0%B4%29">3日目:9/9(水)</a></h4> <p>技術構成のところで書いた通り、わざわざ Docker 環境を使うの微妙だなと思ったので WSL を使う方向へ移行。<br /> React Crossword を試してみたかったので試してみてました。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">おおー、ライブラリでホントにクロスワードできたー。(公式のサンプルコード)<a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a> <a target="_blank" rel="nofollow noopener" href="https://t.co/4dA2snPpzC">pic.twitter.com/4dA2snPpzC</a></p>— よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1303696169445462017?ref_src=twsrc%5Etfw">September 9, 2020</a> </blockquote> <h4 id="4日目:9/10(木)"><a href="#4%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F10%28%E6%9C%A8%29">4日目:9/10(木)</a></h4> <p>「2」をいろんな言語の読み方にして成立するような問題を考えてました。</p> <h4 id="5日目:9/11(金)"><a href="#5%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F11%28%E9%87%91%29">5日目:9/11(金)</a></h4> <p>この日も問題を考えるも、あまり進まず...。</p> <h4 id="6日目:9/12(土)"><a href="#6%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F12%28%E5%9C%9F%29">6日目:9/12(土)</a></h4> <p>さすがに問題をどうにかしないと...と焦り出しました(遅い)</p> <p>「2」をいろんな言語の読み方にして成立するような問題を考えていたものの、思いのほか難しい<br /> ↓<br /> これ無理じゃね?<br /> ↓<br /> 読み方でなく「2」が含まれるものに関する問題(例:2月の和風月名 → キサラギ)に移行してみる<br /> ↓<br /> 縦読み、横読みを成立させるのが難しい<br /> ↓<br /> これ無理じゃね?</p> <p>みたいな感じになった結果、クロスワードは諦めることに...。</p> <p>じゃあ、何を作ろうか?というところで、すでに投稿されていた他の参加者の方の作品を見て、シンプル路線にすることにしました。<br /> ここからやっと当作品を作り始めます。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">元々、2に関するクロスワード作ろうとしてたけど、問題考えるのがしんどすぎて、他のものに切り替え中。明日、とりあえず公開できる程度になればいいなぁ。<a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a></p>— よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1304802019585060864?ref_src=twsrc%5Etfw">September 12, 2020</a> </blockquote> <h4 id="7日目:9/13(日)"><a href="#7%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F13%28%E6%97%A5%29">7日目:9/13(日)</a></h4> <p>何とか実装が進み、一旦デプロイしてみようとなりました。<br /> 前回は Firebase Hosting を使用しましたが、今回は使うまでもないかなということで GitHub Pages にホスティングすることに。</p> <p>GitHub Actions でデプロイする記事を見かけたので、それでやろうと試みるもビルドで失敗。<br /> どうも ESLint の react-hooks/exhaustive-deps ルールに引っ掛かっていたようです(.eslintrc 設定に含まれていなくても、ビルド時にチェックされる?)</p> <p>対応方法を調べて試すも、なかなか解決しなかったので、一旦は無効化で対応(あまりよくないことでしょうが...)<br /> ビルドはパスするようになり、デプロイ自体は成功しているものの、なぜか真っ白なページしか表示されず...。</p> <p>この時点でもうヘロヘロで瀕死だったので、この日は諦めて終わりました。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">ゲームとしてはできてるんだけど、ESLint の新ルールにビルドを阻まれ、GitHub Pages にデプロイできる GitHub Actions 試そうとしたら、デプロイ自体は成功してるっぽいのに、URL にアクセスしても何も表示されないし。やり方悪いんかな...。もう疲れた...。一旦終わろう。 <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a></p>— よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1305160798155673601?ref_src=twsrc%5Etfw">September 13, 2020</a> </blockquote> <h4 id="8日目:9/14(月)"><a href="#8%E6%97%A5%E7%9B%AE%EF%BC%9A9%2F14%28%E6%9C%88%29">8日目:9/14(月)</a></h4> <p>gh-pages を使用して手動デプロイしてみても真っ白ページに。<br /> 試しに S3 にデプロイしたら普通に動作したので、GitHub Pages の問題と切り分け。</p> <p>真っ白ページの原因を特定。<br /> GitHub Pages 特有の注意点を見落としていただけだったようです。<br /> こちらの記事にまさしくなことが書いてありました。<br /> - <a target="_blank" rel="nofollow noopener" href="https://qiita.com/rhirayamaaan/items/cdbda70670157a8fb705">create-react-appとTypeScriptでサラッと作ったSPAをgh-pagesにスルッとデプロイすっぞ!</a></p> <p>ただ、これでもなぜか GitHub Actions でのデプロイは真っ白<br /> ページのままだったので、以降は手動デプロイでやるように。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">GitHub Pages のデプロイで動いたー。どうも package.json に homepage キーで URL を指定する必要があったらしい。そういえば Jekyll をデプロイするうえでの注意点とかで、前に見たことあったような…。なんか URL がずれておかしくなる的な。<a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a></p>— よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1305355374346661890?ref_src=twsrc%5Etfw">September 14, 2020</a> </blockquote> <p>無事動作確認できたし投稿するかと思いましたが、こういうのはやはり OGP 設定や Twitter シェア機能を付けた方がいいよなぁ...ということで対応することに。<br /> この時点でもヘロヘロ気味だったので、やっつけで対応して、日が変わる直前に何とか投稿しました。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">なんとか形にできたー。計算結果が一番「2」に近い式をあてるゲームを作りました。よろしければ遊んでやってください🙏Close to 2 - (9/7~9/13)1週間でWebサービスを作るイベント - お題「2」 - Boards - Crieit <a target="_blank" rel="nofollow noopener" href="https://t.co/HDSKmfCsWo">https://t.co/HDSKmfCsWo</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/Crieit?src=hash&ref_src=twsrc%5Etfw">#Crieit</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a></p>— よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1305520904642805760?ref_src=twsrc%5Etfw">September 14, 2020</a> </blockquote> <h2 id="おおよそどんなことをやっているのか"><a href="#%E3%81%8A%E3%81%8A%E3%82%88%E3%81%9D%E3%81%A9%E3%82%93%E3%81%AA%E3%81%93%E3%81%A8%E3%82%92%E3%82%84%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%8B">おおよそどんなことをやっているのか</a></h2> <p>特に変わったことはしてないと思いますので、ソースコード見てもらった方が早いかとー。<br /> - <a target="_blank" rel="nofollow noopener" href="https://github.com/h-yoshikawa44/close-to-2">GitHub - close-to-2</a></p> <p>参考にさせていただいた記事はこちらなど<br /> - <a target="_blank" rel="nofollow noopener" href="https://keizokuma.com/js-array-object-sort/">JavaScriptで要素がオブジェクトの配列を日付や数値でソートする方法</a><br /> - <a target="_blank" rel="nofollow noopener" href="https://qiita.com/netebakari/items/7c1db0b0cea14a3d4419">JavaScriptで重複排除を自分で実装してはいけない(Setを使う)</a></p> <h3 id="課題"><a href="#%E8%AA%B2%E9%A1%8C">課題</a></h3> <p>React Hooks のこととか、もうちょっとわかったら、全体的にもっとスマートに書けるんでしょうかね...。なんかごちゃついてる感。</p> <p>OGP はやっつけで5分くらいで作りました(笑)</p> <p>Twitter シェアボタンは、公式のものを SPA で使うには少し工夫がいるということで、なんかうまくいきませんでした...。<br /> なので今回は React Share を頼りました。<br /> 本当は Twitter アイコンとともにツイートと書かれたボタンにしたかったのですが、React Share だとできないっぽい?ということで妥協することに。</p> <h2 id="今回参加してどうだったか"><a href="#%E4%BB%8A%E5%9B%9E%E5%8F%82%E5%8A%A0%E3%81%97%E3%81%A6%E3%81%A9%E3%81%86%E3%81%A0%E3%81%A3%E3%81%9F%E3%81%8B">今回参加してどうだったか</a></h2> <p>楽しかったですが、前回以上にてんやわんやしてたなぁと(笑)<br /> 特に最後の方。まぁ、自分が前半悠長にやってたせいなんですが。</p> <p>Twitter シェアボタンを導入したおかげて、遊んでくださってる方の存在を確認することができました。<br /> 確認できるとやはり嬉しいですね!</p> <p>他の方の投稿を見るのも楽しい + 勉強になりますし、こういったイベントに参加するのはいい経験になりますね。<br /> web1week はほどよくゆるい感じの雰囲気があるので、敷居が低くて参加しやすいなと。<br /> また開催されることがありましたら、余程忙しくない限りはなるべく参加していきたいなーと思います。</p> <p>ありがとうございました!</p> <h2 id="参考リンクまとめ"><a href="#%E5%8F%82%E8%80%83%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%BE%E3%81%A8%E3%82%81">参考リンクまとめ</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/JaredReisinger/react-crossword">GitHub - React CrossWord</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://keizokuma.com/js-array-object-sort/">JavaScriptで要素がオブジェクトの配列を日付や数値でソートする方法</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/netebakari/items/7c1db0b0cea14a3d4419">JavaScriptで重複排除を自分で実装してはいけない(Setを使う)</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/rhirayamaaan/items/cdbda70670157a8fb705">create-react-appとTypeScriptでサラッと作ったSPAをgh-pagesにスルッとデプロイすっぞ!</a></li> </ul> よし tag:crieit.net,2005:PublicArticle/15915 2020-05-29T13:19:06+09:00 2021-02-15T14:36:20+09:00 https://crieit.net/posts/ac044ef3dd9b2580f6a86c0ac05881c1 ハッカソンイベントで、React Konva製のジグソーパズルっぽいパズルを作ってみた <p>個人開発って何作るか悩んだり、モチベを保つのが難しかったりしますよね。<br /> そんな自分が、先日web1weekというイベントで個人開発にチャレンジしました。<br /> 何とかリリースまでできたので、使用した技術やどんなことをやったのかといった内容を残しておきます。</p> <h2 id="はじめに"><a href="#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB">はじめに</a></h2> <h3 id="web1weekって?"><a href="#web1week%E3%81%A3%E3%81%A6%EF%BC%9F">web1weekって?</a></h3> <p>簡単に言うと「1週間でお題に沿ったWebサービスを作ってみよう」というイベントです。<br /> 当コミュニティ Crieit の運営者である、だらさん主催で行われました。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">5/18~5/24の1週間でWebサービスを作るイベントです! Hello worldレベルのサービスでもOKですのでぜひご参加をお願いします! <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/%E9%A7%86%E3%81%91%E5%87%BA%E3%81%97%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2?src=hash&ref_src=twsrc%5Etfw">#駆け出しエンジニア</a> 仲間が多い方は是非シェアもお願いします~お題は「Like」です。 <a target="_blank" rel="nofollow noopener" href="https://t.co/ORZQGb6Yu2">https://t.co/ORZQGb6Yu2</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/Crieit?src=hash&ref_src=twsrc%5Etfw">#Crieit</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/StayHome?src=hash&ref_src=twsrc%5Etfw">#StayHome</a> </p>— だら🎄サービスづくりひたすら (@dala00) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/dala00/status/1262035532386689025?ref_src=twsrc%5Etfw">May 17, 2020</a> </blockquote> <h3 id="参加しようと思ったきっかけ"><a href="#%E5%8F%82%E5%8A%A0%E3%81%97%E3%82%88%E3%81%86%E3%81%A8%E6%80%9D%E3%81%A3%E3%81%9F%E3%81%8D%E3%81%A3%E3%81%8B%E3%81%91">参加しようと思ったきっかけ</a></h3> <p>主な背景としては<br /> - 個人開発に使える時間があった<br /> - 前回の開催時も面白そうと気になっていた(今回は2回目の開催)<br /> - 個人開発をやってみたかった(+こういったイベントならモチベも保てるかなと思った)<br /> といった感じです。</p> <p>個人開発は以前からやりたいと思うことはありつつ、結局モチベが続かなくて止めてしまったりということが多かったのです...。<br /> もし何か作ることができたら、1つの実績にできて自分の財産になるかなーと思いました。</p> <p>これは...やるしかない。</p> <p>ということで参加。</p> <h2 id="自分が作ったもの"><a href="#%E8%87%AA%E5%88%86%E3%81%8C%E4%BD%9C%E3%81%A3%E3%81%9F%E3%82%82%E3%81%AE">自分が作ったもの</a></h2> <p><a target="_blank" rel="nofollow noopener" href="https://jigsaw-like-puzzle.web.app/">Jigsaw Like Puzzle</a></p> <p>ちょっとしたパズルを作りました。<br /> PC向け。スマホ対応は現状してません。</p> <p><a href="https://crieit.now.sh/upload_images/d57cb2f3cdd1b7e92ccbbb0fa0d4565e5ed0aab957fa9.gif" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/d57cb2f3cdd1b7e92ccbbb0fa0d4565e5ed0aab957fa9.gif?mw=700" width="80%" alt="パズルのプレイ画面GIF"></a></p> <h3 id="なんでパズル?"><a href="#%E3%81%AA%E3%82%93%E3%81%A7%E3%83%91%E3%82%BA%E3%83%AB%EF%BC%9F">なんでパズル?</a></h3> <p><a href="https://crieit.net/boards/web1week-202005/41152da9fccdaae73e45967feced2e2a">イベント記事への投稿</a>にも書いていたので引用します。</p> <blockquote> <p>「Like」ということで<br /> 好きなもの → 趣味とかかな? → 絵を描くこと(最近全然描いてないけど) → Canvasでお絵描き実装ができるらしい → でも、ただ絵を描くだけじゃつまらない → もしかしてジグソーパズル作れそう? といった感じで行きつきました。</p> <p>ジグソーパズル特有の形は再現できてないので、あくまで「ジグソーパズルっぽいもの」ですね。<br /> 完全に後付け理由ですが、Like って「~ようなもの」って意味もありますし、意図せずテーマに沿ったものになりました(笑)<br /> こんなことあるんですねー。</p> </blockquote> <h3 id="構成"><a href="#%E6%A7%8B%E6%88%90">構成</a></h3> <p>構成図描こうかなとも思ったんですが、大した構成でもないのでざっくり文面で書きます。</p> <p>開発はDockerのNode.jsコンテナで。<br /> 本番はFirebase Hostingでホスティングしています。</p> <p>使用した主なライブラリはこちら(正確には他にもあります)<br /> - React:言わずと知れたUI構築ライブラリ(create-react-appで導入)<br /> - React Konva:Canvasを扱うライブラリであるKonva.jsのReact版<br /> - React Router:ルーティング<br /> - Material UI:UIコンポーネント集<br /> - PropTypes:propsのバリデーション<br /> - ESLint:静的解析<br /> - Prettier:コードフォーマッター</p> <p>基本的なUIはMaterial UIで構築しました。<br /> Boxコンポーネントがすごい便利でしたね。おかげであまりCSSを書かずにすみました。divがその分増えましたが。<br /> パズル部分はReact Konvaで構築しています。</p> <p>React KonvaとFirebaseについては初めて使ったので、まだまだちゃんとわかってないことも多いです。</p> <h3 id="どんな感じで開発してたのか"><a href="#%E3%81%A9%E3%82%93%E3%81%AA%E6%84%9F%E3%81%98%E3%81%A7%E9%96%8B%E7%99%BA%E3%81%97%E3%81%A6%E3%81%9F%E3%81%AE%E3%81%8B">どんな感じで開発してたのか</a></h3> <p>ざっくりこんな感じでした。</p> <h4 id="1日目:5/18(月)"><a href="#1%E6%97%A5%E7%9B%AE%EF%BC%9A5%2F18%28%E6%9C%88%29">1日目:5/18(月)</a></h4> <p>お題に沿って何を作るか案がなかなか出てこなかったです。<br /> React Konvaに行きついてからドキュメントをひたすら読んで、夕方くらいにやっとパズルいけるかも?ってなりました。</p> <h4 id="2日目:5/19(火)"><a href="#2%E6%97%A5%E7%9B%AE%EF%BC%9A5%2F19%28%E7%81%AB%29">2日目:5/19(火)</a></h4> <p>午後からやっと手元の環境で動かしてみました。<br /> 色々試してみて、なんとなくいけそうかな?という手ごたえがありました。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">パズルっぽいものを作成チャレンジ。 <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a> <a target="_blank" rel="nofollow noopener" href="https://t.co/JL4D2noURE">pic.twitter.com/JL4D2noURE</a> </p> — よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1262635512889610241?ref_src=twsrc%5Etfw">May 19, 2020</a> </blockquote> <p>ただ、そこからパズルの元となる画像の適切なサイズ割り出しに時間かかりました...。3パターンできれいに割れて、適度な大きさのサイズがいいよねってなりまして。</p> <h4 id="3日目:5/20(水)"><a href="#3%E6%97%A5%E7%9B%AE%EF%BC%9A5%2F20%28%E6%B0%B4%29">3日目:5/20(水)</a></h4> <p>ようやく画像サイズを決定。</p> <p>720 * 480<br /> 初級:120 * 120 → 6 * 4 = 24<br /> 中級:80 * 80 → 9 * 6 = 54<br /> 上級:60 * 60 → 12 * 8 = 96</p> <p>その後、ストップウォッチの実装をどうやるかめっちゃ悩みました...。<br /> 記事を参考にしながら試すも、うまくいかずドはまり。<br /> 時間かかりつつも一応実装できました。</p> <p>この時点でいまだにリポジトリを作っていなかったので、とりあえず作成だけ。</p> <h4 id="4日目:5/21(木)"><a href="#4%E6%97%A5%E7%9B%AE%EF%BC%9A5%2F21%28%E6%9C%A8%29">4日目:5/21(木)</a></h4> <p>ルーティングやOGP、画像の取り扱いをどうしようか悩みました。<br /> 結果的には、最低限遊べるレベルのリリースができればいいやということで、一旦は妥協することにしました。</p> <p>午後からやっとプロジェクトのセットアップ。<br /> Issueやプルリクのテンプレ、Dockerで開発環境構築ともろもろ必要な準備を整えました。</p> <p>ピース位置チェック(正解位置に置かれたらはまる)のやり方がなんとなくわかって、よーし作っていくぞーという流れへ。</p> <h4 id="5日目:5/22(金)"><a href="#5%E6%97%A5%E7%9B%AE%EF%BC%9A5%2F22%28%E9%87%91%29">5日目:5/22(金)</a></h4> <p>パズル画面に背景テクスチャをいれようとしましたが、迷ったので結局止めました。</p> <p>黙々と進めて、ぼんやりとしたイメージで作っていった画面のモックがおおよそできました。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">やっとモック的なものができた <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a> <a target="_blank" rel="nofollow noopener" href="https://t.co/r9GK4fwEuM">pic.twitter.com/r9GK4fwEuM</a> </p> — よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1263709728640610305?ref_src=twsrc%5Etfw">May 22, 2020</a> </blockquote> <p>モックに続いて、難易度選択モーダル、ピース生成ロジックを作成。</p> <h4 id="6日目:5/23(土)"><a href="#6%E6%97%A5%E7%9B%AE%EF%BC%9A5%2F23%28%E5%9C%9F%29">6日目:5/23(土)</a></h4> <p>ポーズモーダル、クリアモーダルを作成。</p> <p>ここまでで、とりあえず最低限遊べることは確認できたのでリリースすることに。<br /> コンポーネントを多少分けてはいましたが、ファイル分割とか全然できてなかったので、そこまでリファクタやってからリリースするかとも考えたのですが、もうやっちゃえとなりました。</p> <p>ホスティングに関しては、多少慣れてるNetlifyでやる手もあるなと思いました。<br /> ただ、今後機能拡張していくとしたらFirebaseの方が色々やれてよさそうと思い、こちらにすることにしました。</p> <p>リリース(v0.1.0)して投稿。<br /> リリースと言いつつ、色々と足りてないものがまだあるのでプレリリースみたいなものですね。</p> <blockquote class="twitter-tweet"> <p lang="ja" dir="ltr">パズルリリースしましたー。 <a target="_blank" rel="nofollow noopener" href="https://t.co/028WAbS7W9">https://t.co/028WAbS7W9</a> よかったら遊んでみてください。 PC向け。簡易的なものなので、クオリティはご容赦ください🙏(5/18~5/24)1週間でWebサービスを作るイベント - お題「Like」 - Boards の投稿 - Crieit <a target="_blank" rel="nofollow noopener" href="https://t.co/FldwX4odRN">https://t.co/FldwX4odRN</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/Crieit?src=hash&ref_src=twsrc%5Etfw">#Crieit</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/web1week?src=hash&ref_src=twsrc%5Etfw">#web1week</a> <a target="_blank" rel="nofollow noopener" href="https://twitter.com/hashtag/StayHome?src=hash&ref_src=twsrc%5Etfw">#StayHome</a> </p>— よし (@yoshi44_lion) <a target="_blank" rel="nofollow noopener" href="https://twitter.com/yoshi44_lion/status/1264144419818573825?ref_src=twsrc%5Etfw">May 23, 2020</a> </blockquote> <h2 id="おおよそどんなことをやっているのか"><a href="#%E3%81%8A%E3%81%8A%E3%82%88%E3%81%9D%E3%81%A9%E3%82%93%E3%81%AA%E3%81%93%E3%81%A8%E3%82%92%E3%82%84%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E3%81%AE%E3%81%8B">おおよそどんなことをやっているのか</a></h2> <p>ソースコードはリファクタやったりして変わる可能性があるので、リポジトリ見ていただいた方が確実かもしれません(あまりきれいなコードではないですが...)<br /> 一応、Issue書いたりしながら進めました。<br /> - <a target="_blank" rel="nofollow noopener" href="https://github.com/h-yoshikawa44/jigsaw-like-puzzle">GitHub - jigsaw-like-puzzle</a></p> <p>以下の内容は執筆時点(v0.1.4)での実装のものとなります。<br /> 有識者の方からすると、この実装イケてないとかあると思いますがご容赦ください。</p> <h3 id="ストップウォッチ"><a href="#%E3%82%B9%E3%83%88%E3%83%83%E3%83%97%E3%82%A6%E3%82%A9%E3%83%83%E3%83%81">ストップウォッチ</a></h3> <p><a href="https://crieit.now.sh/upload_images/7296a1e13c3ba9f86e222e09f2c2e8c85ed0abacd6412.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/7296a1e13c3ba9f86e222e09f2c2e8c85ed0abacd6412.png?mw=700" width="80%" alt="パズル画面のストップウォッチ部分画像"></a></p> <h4 id="概要"><a href="#%E6%A6%82%E8%A6%81">概要</a></h4> <p><code>setInterval()</code>と<code>clearInterval()</code>を使って実装。<br /> 恥ずかしながら自分はこの関数を使用したことがなかったこともあり、最初はストップウォッチってどうやって実装したらいいんだろう?という状態でした。</p> <p>実装のやり方についてはこちらの記事をとても参考にさせていただきました。<br /> - <a target="_blank" rel="nofollow noopener" href="https://blitzgate.co.jp/blog/805/">【1から始めるReact】ストップウォッチを作る</a></p> <p>1秒ごとに秒数カウントを+1して、その秒数カウントをもとに時、分、秒を計算して更新していくというものです。</p> <h4 id="問題点"><a href="#%E5%95%8F%E9%A1%8C%E7%82%B9">問題点</a></h4> <p>同画面で開始と停止を行う上では問題なかったのですが、今回の場合は<br /> - パズル画面の「一時停止」ボタンを押す → ストップウォッチを停止してポーズモーダルを開く<br /> - ポーズモーダルの「復帰」ボタンを押す → ポーズモーダルを閉じて、ストップウォッチ再開</p> <p>という仕様だったので、再開時に時間が最初からになってしまう問題が起きました。</p> <p>秒数カウントはstateで管理してない変数だったので、再レンダリング時に値がリセットされていたんだろうなと。<br /> そのため、秒数カウントの値をバックアップを取っておく感じでstateでも保持するようにしました。<br /> 1秒ごとの更新処理の際に、秒数カウント(変数)が0 だったらstateを確認して、バックアップがあればそこから復元するイメージです。</p> <p>秒数カウントを最初からstateで管理すればいいのでは?となるかもしれませんが、stateでやるとうまく動いてくれなかったので、こういった形をとりました。</p> <h3 id="パズル"><a href="#%E3%83%91%E3%82%BA%E3%83%AB">パズル</a></h3> <p><a href="https://crieit.now.sh/upload_images/a753b71f782fdb5bf171c87c58829a4d5ed0ac2d7633b.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/a753b71f782fdb5bf171c87c58829a4d5ed0ac2d7633b.png?mw=700" width="80%" alt="パズル画面のパズル部分画像"></a></p> <h4 id="概要"><a href="#%E6%A6%82%E8%A6%81">概要</a></h4> <p>React Konvaで実装していますが、その実体はCanvasです。<br /> Canvasを扱う<code>Konva.js</code>というライブラリがあり、そのReact版だそうです。</p> <p>Canvasを扱うには<code>Konva.js</code>が便利らしいみたいな記事は複数見かけたんですが、自分はCanvas自体を使ったことがなかったため、いまいちピンとこず...。<br /> なので、最初はひたすらドキュメントを読んで、おおよそどんなことができるものなのかを見ていきました。<br /> その結果、パズルいけそうだなという目途がついたので使ってみたという背景があります。</p> <p>Konva.jsの構造としては、以下のようになっています(<a target="_blank" rel="nofollow noopener" href="https://konvajs.org/docs/overview.html">公式</a>より引用)</p> <p><a href="https://crieit.now.sh/upload_images/d4558c875c94cb3594a9cd556d3393435ed0ac8deeece.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/d4558c875c94cb3594a9cd556d3393435ed0ac8deeece.png?mw=700" width="60%" alt="Konva.jsの構造画像"></a></p> <p>Shapeは複数種類があり<br /> - Rect(長方形)<br /> - Circle(円)<br /> - Ellipse(楕円)<br /> - Line(線)<br /> - Image(画像)<br /> - Text(テキスト)<br /> - Star(星)</p> <p>などがあてはまります。</p> <p>これらは上位の要素を基準とした x、y座標であったり、横幅、縦幅、色、影などを指定することで、Canvasに描画をしていけるようになっています。</p> <h4 id="パズルの元画像"><a href="#%E3%83%91%E3%82%BA%E3%83%AB%E3%81%AE%E5%85%83%E7%94%BB%E5%83%8F">パズルの元画像</a></h4> <p>Imageコンポーネントを使用。<br /> 普通に画像パスを渡すのではダメらしく、<code>use-image</code>ライブラリの<code>useImage</code>フックを使って生成した、DOM画像を渡すようにしています。<br /> - <a target="_blank" rel="nofollow noopener" href="https://github.com/konvajs/use-image">GitHub - use-image</a></p> <p>ちなみにピース数の計算との兼ね合いで、画像サイズおよびこのImageコンポーネントのサイズは 720 * 480 で固定しています。</p> <h4 id="パズルの額縁"><a href="#%E3%83%91%E3%82%BA%E3%83%AB%E3%81%AE%E9%A1%8D%E7%B8%81">パズルの額縁</a></h4> <p>Lineコンポーネントを使用。<br /> 4つの点の座標を指定して繋ぐことで図形を描画。これを上下左右で4つ作成しています。<br /> ただの塗りつぶしだと安っぽくなるので、グラデーション指定にしてみました。</p> <h4 id="パズルのピース"><a href="#%E3%83%91%E3%82%BA%E3%83%AB%E3%81%AE%E3%83%94%E3%83%BC%E3%82%B9">パズルのピース</a></h4> <p>Imageコンポーネントを使用。<br /> <code>useImage</code>フックによる DOM 画像を渡しているのは同様ですが、cropを指定することで画像の切り抜きをしています。</p> <p>例として初級の場合であれば、ピースサイズは 120 * 120 なので<br /> 1行目<br /> - {x:0 y:0 width:120 height:120}<br /> - {x:120 y:0 width:120 height:120}<br /> - {x:240 y:0 width:120 height:120}<br /> .<br /> .<br /> .</p> <p>2行目<br /> - {x:0 y:120 width:120 height:120}<br /> - {x:120 y:120 width:120 height:120}<br /> - {x:240 y:120 width:120 height:120}<br /> .<br /> .<br /> .</p> <p>みたいな感じです。<br /> 合わせてコンポーネント自体のサイズも 120 * 120 を指定になります。</p> <p>draggableを有効化してドラッグアンドドロップができるように。<br /> そのうえ、onDragStartとonDragEndでイベント処理を実装しています。</p> <h4 id="ピースドラッグ時の挙動"><a href="#%E3%83%94%E3%83%BC%E3%82%B9%E3%83%89%E3%83%A9%E3%83%83%E3%82%B0%E6%99%82%E3%81%AE%E6%8C%99%E5%8B%95">ピースドラッグ時の挙動</a></h4> <p>scaleを変えて、少しだけピースが大きくなるようになっています。<br /> (公式デモのコードそのまま持ってきた感じです)</p> <p>それに加えて、ドラッグしているピースが必ず最前面に来るような処理をしています。<br /> Canvas要素は、あとに定義したものが前面に来るようになっているようです。<br /> そのため、この処理をやらないと場合によっては、はめ込まれたピースの背面にドラッグ中のピースが隠れてしまい操作不能になってしまうことがあります。<br /> そんなことなったら一気に萎えちゃいますよね。</p> <h4 id="ピースドロップ時の挙動"><a href="#%E3%83%94%E3%83%BC%E3%82%B9%E3%83%89%E3%83%AD%E3%83%83%E3%83%97%E6%99%82%E3%81%AE%E6%8C%99%E5%8B%95">ピースドロップ時の挙動</a></h4> <p>scaleを元に戻します。durationも設定してるので、ポヨンと大きさが戻るような見た目になってます。<br /> (これも公式デモのコードをそのまま持ってきた感じです)</p> <p>加えて、ドロップされた座標と正解位置の座標を比較。<br /> 誤差の範囲内であれば、draggableを無効 + ピースの座標を正解位置の座標に更新 することで、ピースがはめこまれるような挙動を実現しています。<br /> この処理はこちらの公式デモを参考にしました。<br /> - <a target="_blank" rel="nofollow noopener" href="https://konvajs.org/docs/sandbox/Animals_on_the_Beach_Game.html">Konva.js - Animals on the Beach Game</a></p> <h3 id="ゲームの流れ"><a href="#%E3%82%B2%E3%83%BC%E3%83%A0%E3%81%AE%E6%B5%81%E3%82%8C">ゲームの流れ</a></h3> <p>これまでの内容を踏まえて、ゲームの流れとしてはおおまかにこんな感じです。<br /> (並列で処理しているところもあります)</p> <p>難易度選択<br /> ↓<br /> 難易度に応じたピース数(縦、横)、ピースサイズの値をセット<br /> ↓<br /> この3つの値の変更を検知して、初期化ロジック実行<br /> ピースの情報を持ったオブジェクトの配列を生成後、その順番をシャッフル<br /> ↓<br /> ピースの情報を持ったオブジェクトの配列をもとにピースのコンポーネントが描画される<br /> ↓<br /> ゲーム開始(ストップウォッチ開始)<br /> ↓<br /> ピースのドラッグアンドドロップ<br /> ドロップ座標が正解位置の座標の誤差範囲であればはめこまれ、正解ピース数が+1される<br /> (これを全てのピースがはめ込まれるまで繰り返す)<br /> ↓<br /> 正解ピース数の値の変更を検知して、総ピース数と一致すればクリア(ストップウォッチ停止)</p> <h2 id="今回参加してみてどうだったか"><a href="#%E4%BB%8A%E5%9B%9E%E5%8F%82%E5%8A%A0%E3%81%97%E3%81%A6%E3%81%BF%E3%81%A6%E3%81%A9%E3%81%86%E3%81%A0%E3%81%A3%E3%81%9F%E3%81%8B">今回参加してみてどうだったか</a></h2> <p>楽しかったです!ただ、疲れました(笑)<br /> お題があったとはいえ、ほぼ一から自分で考えて作る必要があったので、普段よりもいっぱい頭使ったからかなと思います。</p> <p>とはいえ、個人開発として無事にリリースまでできたのはこれが初めてなので素直に嬉しいですね。<br /> 他の方の投稿を見るのも楽しいですし、学ばせていただく機会にもなりました。<br /> こういった機会を設けてくださり、ありがとうございました!</p> <hr /> <p>ちょっとしたレポート記事を書くつもりがすっかり長くなってしまいました...。<br /> ここまで読んでくださった方、ありがとうございます!</p> <p>パズルの方は今後も合間を見つけて改修していこうかなと思ってます。<br /> ちなみに最初に導入したGoogle Analyticsがちゃんと動いておらず、投稿時のアクセス数を見られなかったというヘマをやらかしていましたが、修正して現在は無事に動いてます(冷や汗)</p> <p>もしお暇な時があれば、パズル部屋を覗いてみてください。</p> <h2 id="参考リンクまとめ"><a href="#%E5%8F%82%E8%80%83%E3%83%AA%E3%83%B3%E3%82%AF%E3%81%BE%E3%81%A8%E3%82%81">参考リンクまとめ</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://blitzgate.co.jp/blog/805/">【1から始めるReact】ストップウォッチを作る</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://konvajs.org/docs/react/">Konva.js</a></li> </ul> よし