初めてハッカソンに参加して、賞をもらった話

ハッカソンに参加してきた

ちょうど先週、『PLATEAU Hack Challenge 2021』というハッカソンに参加し、審査員奨励賞をいただくことができた。

私はこのハッカソンでリーダー兼エンジニアを務めた。結果は良かったものの、良かったこともモヤっとしたこともあったので、振り返りのメモを残しておきたい。

どんな人が多かったか?

学生から社会人まで、それも若手からベテランまで、かなり幅広い層の方が参加されていた。

第一回は資料を読む限りシミュレーションなどの方面に詳しい方が多かった印象だが、第二回である今回はVR界隈の人がやたらと多く、故にUnityを使うプロジェクトが大半だった。

何らかの開発スキルを持つ人が8割、他が2割くらい。アイデアソン経由で参加される方もいるので、アイデアはあるけど開発スキルはない、という人ももちろんいる。

チーム開発・リーダーの難しさ

元々私は3人のチームで応募をしていた。この3人でハッカソンこそ参加したことはなかったが、某ブランドデザインコンテストや企画コンペに応募したりしており、今回も事前に3人で企画の打ち合わせを週1ペースで行っていた。(このハッカソンは事前にアイデアを提出する珍しい形式をとっていた)

悩みに悩んだ末、私の発案したアイデアで応募することに決まり、ハッカソンへの参加提案とアイデアの発案者としてリーダーを務めることになった。(とはいえリーダー経験はあまりなく、稀にリーダーをやった時もあまりいい思い出がなかった。)

3人のメンバーは私がエンジニア・他2人はデザイナーで、流石に開発が間に合わないだろうということでチーム参加者をハッカソン当日に募ることにした。そして4人のメンバーが新たに加わることになった。年代もバラバラでかなりベテランの方とも一緒に開発ができて、本当に貴重な経験だった。4人に加わって頂いたおかげでこのプロジェクトを形にすることができ、賞までいただけたので、本当に感謝しかない。

…それは一旦置いておいて。

ただチーム開発というのは本当に難しい。皆が皆、「このプロジェクトがより良くなるように」と自分の役割に囚われず積極的に動いてもらえれば一番いいのだが、「リーダーが自分に振った仕事しかやらない」のがほとんどだと思う。オンラインなら尚更。 その点において、7人という人数は多すぎた。今回エンジニアは3~4人くらいで動いていてちょうどよかったのだが、それ以上増やすのは恐らくきつい。そしてデザイナーは1人いれば十分かもしれない。 ハッカソンのデザイン業務を2人で分けると、必ず「暇な時間」が発生してしまう。

暇な人がいるなら、仕事を振らないといけない。開発に追われていた私はあまりリーダーをやっている余裕がなく、暇な彼に「ディレクション頼みたい」と雑に頼んでしまった。彼がなんとなく得意そうなイメージがあったので無理に押し付けてしまったのだと思う。曖昧な指示でうまくいくわけもなく、結局少し開発に余裕ができたら私が全てディレクションをやっていた。

結果的に賞もとれて、チームメンバーの方々も概ね満足されていて、嬉しかった。が、そうじゃない人もいた。でも何が原因かわからない。思いつくことはいくつかあっても、真相はわからず、もやもやしたままだ。

正直、「誰か1人でも傷つけるくらいなら、自分はもうリーダーをやりたくない」とは、思ってしまった。

「物」を見るのか「人」を見るのか

リーダーをやってみて、リーダー(マネジメント・ディレクション)の役割は2つあると気づけた。1つ目は「物」を見る、つまり計画を立ててプロジェクトを正しく遂行する役割。そして2つ目は「人」を見る、つまりチームのモチベーションを保ち、その人の適性を見て正しく仕事を振る役割。

今回、私は前者に振りすぎていたと思う。ただ現時点で後者の適性があるとはあまり思えない。周りを見ていても、後者の才能がある人って結構いて、どんな人とも仲良くできる人、褒めるのが上手い人、まとめるのが上手い人、たくさん見てきた。

私はそういった人たちとは遠いから、と普段は裏方的なポジションでチームを支えることが多かったのだけど、就活していた時インターン(という名のグループワーク)では「裏方ポジションもいいけど、リーダー的ポジションもやっていけると思うよ」とメンターの方から御助言いただいたので、適性が全くないわけではないと思う。

なので最初から諦めず、どうやったら近づけるか、これから少しずつ考えていきたい。

ハッカソンに大事なのは技術力だけじゃない

今回のハッカソンは評価基準があらかじめ定められていた。

そう、これを見ればわかる通り、「技術力」は含まれていない。 このハッカソンで求められるのは、「PLATEAUでないと実現できない価値があるか」だと感じた。それGoogle Mapでできるよね?というアイデアではダメなのだ。私たちのチームではその部分をよく議論していた(ただの3Dモデルとしてではなく建物のデータをどう活かすかを考えていた)ので、良い結果に結びついた。

これは他のハッカソンでも同じだと思う。技術力は大事だが、技術力だけを重視するハッカソンなんてそうない。

なんだかんだ言ってハッカソンは楽しい!

前半で色々書いたものの、1週間たっても熱に浮かされている。知らないメンバーと開発するのも、他のこと全部忘れて徹夜で開発するのも性に合っていて、とにかくアドレナリンがすごかった。(逆にコツコツ開発するのが苦手すぎてどうすれば…)

ハッカソン参加したい欲」が昂って、次に参加する予定のハッカソンの目処も立ててしまった笑 参加する前まで「ハッカソンで足手まといになったらどうしよう…」とか全く勇気が出なかったのが嘘のよう。

こんな風に、短期間でモノを作る機会を作ることが自分のエンジンをかける方法なんだ、と気づけたのはとても大きい。

次もリーダー的役割をするかはわからないけれど、もしなったら今回の反省点は絶対に活かしていこう。

間違えやすいと思う複数クラスに跨るCSSセレクタ

CSSのクラス指定の際、スペースを空けたり空けなかったりすごくややこしいな、と思ったので、整理します。

極端な例ですが以下のhtmlで見ていきます。

<div class="parent">
  <div class="sister elder"></div>
  <div class="me"></div>
  <div class="sister younger"></div>
</div>
<div class="friend elder">友達</div>

子要素を指定したい

.parentの子要素の.meだけを指定したい!

.parent .me {

}

間に半角スペースを入れる。

複数の要素を指定したい

.friendにも.me にも同じスタイルを適用したい!

.friend, .me {

}

間にカンマを入れる。

両方のクラスが含まれている要素を指定したい

.sisterかつ.elderな要素を指定したい!

.sister.elder {

}

間にスペースを入れない。 この場合、.friendかつ.elderな要素は指定に含まれない。

See the Pen classes by Kyoko Sakuma (@maku459) on CodePen.

Swiper.jsで矢印をFont Awesomeに置き換える

実現したこと

前回に引き続き、スライダーを作るのに便利なjsライブラリ、Swiperの話です。

makumakuworks.hatenablog.com

矢印の部分を画像やFont Awesomeに置き換えたい、という記事はいくつか見つけたのですが、どれを試してももとの矢印が消えずうまくいかなったので、現時点でうまくいく方法を書いていきます。

f:id:nubonubo:20210624032542p:plain

前回の記事から流用したものになりますが、CodePenはこちら

つまずきポイント

まずはGoogleデベロッパーツールで矢印のCSSがどのように書かれているか見てみましょう。

f:id:nubonubo:20210624032912p:plain:w300

するとどうやら、.swiper-button-prev、.swiper-button-nextの擬似要素(:after)にて、swiper-iconsという独自のフォントとして矢印アイコンが配置されているようです。

このため、.swiper-button-prev、.swiper-button-nextにCSS側で背景画像を設定したりimgタグを間に入れても、擬似要素側で描かれている元の矢印が消えることはありません。

どうやったか

無理矢理と言えば無理矢理ですが、.swiper-button-prev、.swiper-button-nextの擬似要素をdisplay: none;で消します。

.swiper-button-next:after, .swiper-button-prev:after {
   display: none;
}

その後、FontAwesomeを読み込みます。

<div class="swiper-button-prev fa-2x"><i class="fas fa-arrow-circle-left"></i></div>
<div class="swiper-button-next fa-2x"><i class="fas fa-arrow-circle-right"></i></div>

たったこれだけ!


参考

Swiper.jsで矢印だけをスライドの外側に配置する

実現したこと

Web制作においてスライダーを作るのに便利なjsライブラリ、Swiper。

swiperjs.com

Swiperを使い、以下のように「スライドは中央に寄せられているが、矢印は外側にある」状態を作りました。

f:id:nubonubo:20210623025611g:plain

ブログ上でうまく展開できなかったのですがCodepenのリンクはこちら

つまずきポイント

まずは公式ドキュメントのDemosのSlides per viewなどを参考にしながら、一回に3つスライドが表示され、かつ矢印ボタンが表示されるようにjs側で設定します。

const swiper = new Swiper('.swiper-container', {
    // Optional parameters
    slidesPerView: 3,
    spaceBetween: 10,

    // Navigation arrows
    navigation: {
      nextEl: '.swiper-button-next',
      prevEl: '.swiper-button-prev',
    },
  });

SwiperのHTML・CSS構造がどうなっているかを見ておきましょう。

  <div class="swiper-container">
    <!-- Additional required wrapper -->
    <div class="swiper-wrapper">
      <!-- Slides -->
      <div class="swiper-slide"></div>
      <div class="swiper-slide"></div>
      <div class="swiper-slide"></div>
      <div class="swiper-slide"></div>
      <div class="swiper-slide"></div>
    </div>
  </div>
  <div class="swiper-navWrap">
  <!-- If we need navigation buttons -->
  <div class="swiper-button-prev"></div>
  <div class="swiper-button-next"></div>

まずはswiper-container。

f:id:nubonubo:20210623030111p:plain

(画像上では完成しています)

.swiper-container {
    width: 770px;
    height: 100px;
}

widthには各スライドの幅×3+スライドの間の幅 で770pxを指定しました。 .swiper-container にはライブラリ側でoverflow: hiddenが適用されているため、widthより外側=margin部分は表示されません。

続いてswiper-wrapper。

f:id:nubonubo:20210623030829p:plain

(画像上では完成しています)

wrapperにはcontainerで隠されているスライドも含めた、全スライドが入っています。 ここではライブラリ側で指定されているもの以外、特にCSSを指定していません。

これでスライド部分は大体完成、あとはswiper-button-prevとswiper-button-nextの位置を変えればいいのでは、という話なのですが、 実はswiper-containerにoverflow: hiddenが適用されているため、矢印ボタンを外にはみ出させようとすると要素が表示されなくなってしまうのです。

overflow: visibleなどを別途設定しても、挙動が変わってしまいます。

どうやったか

そこで対処策としては、swiper-button-prevとswiper-button-nextの2つを別のdivで覆ってしまうこと。

<div class="swiper-navWrap">
    <!-- If we need navigation buttons -->
    <div class="swiper-button-prev"></div>
    <div class="swiper-button-next"></div>
  </div>
.swiper-navWrap{
    display: flex;
    position: absolute;
    width: 100%;
    height: 50px;
    top: 0;
    left: 0;
}

これで矢印が隠れることなく表示されます。あとは位置を微調整するだけ。

f:id:nubonubo:20210623025611g:plain

【Oculus Quest2開発】HMDの視界に枠をつける

実現したこと

HMDで全天球映像を見る際に、あえて視界を狭くしたかったので、視界に黒い枠を固定でつけることを考えました。

f:id:nubonubo:20210621022359g:plain

周囲が黒い枠で囲まれているのがお分かり頂けるでしょうか。 PCで見るとそうでもないのですが、VRで見るとさらに周囲の枠が太くなり視界が狭まっています。

どうやったか

やっていることは簡単で、VRカメラの子オブジェクトとして黒枠を配置すればいいだけです。 詳しく見ていきましょう。

まずillustratorなどで真ん中を抜いた黒枠を作り、Unityに読み込んでおきます。(結構黒枠を太めに作らないと枠が見えません。。)

f:id:nubonubo:20210621023222p:plain

VRカメラ(ここではXR Interaction Toolkitを利用しているため、XRRigDemo > CameraOffset > Main Camera)を右クリックし子オブジェクトとしてCanvasを追加します。

f:id:nubonubo:20210621023407p:plain

Canvasのインスペクターから、Render Modeを「Screen Space - Camera」、Render Cameraに先程のMain Cameraをドラッグ&ドロップして設定します。

f:id:nubonubo:20210621023518p:plain

下部の「Add Component」からImageコンポーネントを割り当てます。Source Imageに黒枠の画像をドラッグ&ドロップでセットします。セットできない場合、黒枠の画像のインスペクターからTexture Typeを「Sprite(2D & UI)」に変更してください。

f:id:nubonubo:20210621023703p:plain

するとエディタ上ではこうなります。

f:id:nubonubo:20210621023900p:plain

これで設定は完了です。

f:id:nubonubo:20210621022359g:plain

Render Modeの「Screen Space - Camera」は他のオブジェクトとの前後関係が考慮されるため、今回はUIを黒枠より手前に配置しており、UIは黒枠の中からはみ出ても見えるようになっています(これがいいか悪いかは別として)。

(7/16追記)実際にどこまで見えるのか検証

実はHMDで見ると枠は見えづらいです。

HMDでの見え方を検証するために、3Dモデリングによく使われるグリッドと、枠を重ね合わせた画像を作り検証してみました。

上で使用しているグリッドより少し見える範囲を広くしたものを利用しています(単純に間違えました)

f:id:nubonubo:20210717070152p:plain

f:id:nubonubo:20210717064825p:plain

これをHMDで見ると…

f:id:nubonubo:20210717065336j:plain

HMDの視野は、正方形に近いです。一方で枠は長方形のため、横はあまり視野が狭まっていません。 その代わり縦には狭くなっているので、ちゃんと「枠がある」ことは認識できます。

ちなみに、グリッドは歪まず綺麗に見えていました。


参考

PerlでPukiWikiからMarkdownに半自動変換する

PukiWikiMarkdown移行の経緯

少し前になりますがバイト先でPukiWikiに溜めてきたノウハウをプリザンターというプラットフォームに移行することになりました。

しかしPukiWikiPukiWiki記法で書かれているのに対し、プリザンターはMarkdown記法。手動で直すにはあまりに膨大な量で、なんとか半自動で移行できないかと調べてたらこちらのワンライナーというものを発見。

qiita.com

Macのターミナルで実行できました。

基本構文は以下(wikiの文章はあらかじめtxtデータとして保存しておきます)

cat pukiwiki.txt | sed -e 's/ \[#[0-9a-z]\+\]$//g' -e 's/~$//g' | less > markdown.txt
  • cat:ファイルまたは標準入力の内容をそのまま標準出力に出力するコマンド。
  • |:通称パイプ。複数のコマンドをつなぎ、標準出力を次のコマンドに渡す。
  • sed:文字列を全置換したり、行単位で抽出したり、削除したり、いろいろなテキスト処理のできるコマンド。
  • -e:perlワンライナーとして利用する。その後ろに実行したいperlスクリプトを''で囲って指定。
  • less:入力の全部をターミナル上でスクロールしながら見る。catだとターミナル上を一瞬で流れてしまうので、最後の1画面分以外は見ることができない。
  • >:表示されている内容をファイルに書き込む。

ただし上のコマンドだと一部の拡張正規表現が使えません。 なので、以下のように変えます。

cat test.txt | perl -pe 's/ \[#[0-9a-z]+\]$//g; s/~$//g;' | less > markdown.txt
  • sedは文字列に特化したコマンドだが、perlならさらに複雑な処理も覚えればできる。
  • -p :perlsedっぽくするオプション。

コマンドの''内の読み方

上のコマンドで特に''で囲まれている部分は何やら訳のわからない文字列の集合に見えますが、以下の法則を元に作られています。

変換の基本構文

s/hogehoge/fugafuga/g;

という文があれば、hogehogeがfugafugaに変換されます。

正規表現

これに関してはいろんな方がまとめてくださっているので、そちらを参考にしてください!

userweb.mnet.ne.jp

メタ文字

上の正規表現で使われている記号(=メタ文字)は普通に書いただけでは検索対象として認識されません。

. ^ $ [ ] * + ? | ( )

を検索対象としたい場合は、以下のように表記します。

\. \^ \$ \[ \] \* \+ \? \| \( \)

\ 自体は、\と書きます。

なお、Windowsの場合は上の\は全て¥です。

実例から学ぶ

以下、実際に使った正規表現のコマンドをまとめておきます。

末尾のハッシュを削る

-e 's/ \[#[0-9a-z]+\]$//g'
  • []で囲むと、[]内のいずれかという意味になる。[0-9][a-z]を連続して書くとこうなる。
  • +は直前のパターンの1回以上繰り返し
  • 最後の$は文末であるという意味。

末尾の~を削る

-e 's/~$//g'

#で始まる文一括削除

-e 's/^#.*//g'
  • 最初の^は文頭であるという意味。
  • .は任意の一文字、*は直前のパターンの0回以上繰り返しという意味なので、.*で任意の文字列という意味。

太字を変換(''→**)

-e 's/\'\'/\*\*/g'
  • この時、コマンド全体を囲む'を"に変更すること!

見出しを# に変更(*→# )

-e 's/^\*\*\*/### /g' -e 's/^\*\*/## /g' -e 's/^\*/# /g'
  • 半角スペースはそのまま半角空ければOK

箇条書きを*に変更(-→* )

-e 's/^---/ \* /g' -e 's/^--/ \* /g' -e 's/^-/\* /g'

1.の箇条書き(+→1. 、++→ *)

-e 's/^+++/ \* /g' -e 's/^++/ \* /g' -e 's/^+/1\. /g'

サイズ表記を削除(&size(20){文字}→文字)

-e 's/&size\(\d+\)\{(.*)\}/$1/g'
  • 文字の部分をそのまま維持したい場合、その部分を()で囲む。この場合は(.*)の部分。変換後の正規表現では該当箇所を$1と表記する。

リンク表記を変換

-e 's/\[\[(.*)>http:\/\/(.*)\]\]/\[$1\]\(http:\/\/$2\)/g'
-e 's/\[\[(.*)>https:\/\/(.*)\]\]/\[$1\]\(https:\/\/$2\)/g'
  • サイズ表記の項と同様。複数の文字を維持する時は$1、$2…と使える。

参考

GitHub for Unityでコミットできない時

起こった現象


プロジェクトの途中でGitHub for Unityを導入したところ、Commitボタンを押しても「Staging Changes...」のまま動かず、しばらく経つとコミット自体が自動キャンセルされる。

GitHub for Unityの導入方法は以下の記事を参考にさせていただきました。)

qiita.com

 

解決策


結局このプロジェクト内では何をやっても直らず、新しいプロジェクトを作って移植したらうまくいきました。

プロジェクトの最初にGitHub for Unityを導入するのがおすすめです。

途中から入れた場合でもコミットできるようになる方法があれば、コメント頂けると幸いです。