Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

アカツキのクライアントエンジニアインターンに参加した話

こんにちは.9月1日〜9月18日までアカツキのクライアントエンジニアインターンに参加しました,高橋と申します.今回は大人気スマホゲーム「八月のシンデレラナイン(以下ハチナイ )」のプロジェクトでUnityを用いたUI関連の機能の追加や改修の業務に関わらせていただきました.本記事ではその際に取り組んだことや感じたことなどを書いていきたいと思います.

はじめに

私は現在修士1年生で,普段はヒューマンインタフェースの研究室で電気刺激(神経に電気を流して感覚を作る技術)の研究をしています.もともと趣味でUnityを使ったゲーム開発などをしていましたが,就活を始めるにあたって仕事としてのゲーム開発を体験してみたいと考え,今回のインターンに参加させていただきました. 

やったこと

冒頭でも述べましたが,私は今回ハチナイのプロジェクトでUI関連のいくつかの業務に関わらせていただきました.具体的な内容としては主に次の3点になります.

  • 選手育成画面で溢れた経験値を表示する機能の開発
  • スカウト画面のピックアップ選手の表示数削減
  • ダイアログ外タップ機能の実装についての検討

以下ではそれぞれの項目について詳しく説明していきたいと思います.

選手育成画面で溢れた経験値を表示する機能の開発

概要

インターンが始まって私が最初に取り組むことになったのは選手育成画面で溢れた経験値を表示する機能の開発でした.ハチナイでは選手のレベルを上げる際に強化相手を選択して経験値を与えるということをするのですが,選手のレベルには当然上限があるため,必要以上の経験値を与えると経験値が溢れてしまいます.ところが現状ではこの溢れた経験値を画面に表示する仕組みが存在せず,ユーザさんは気づくことができません.そのため,何らかの方法でこれをユーザさんに知らせようというのが今回の目的でした.

f:id:ytfkbc:20200921162302p:plain

改修前の選手育成画面

仕様の決定

この機能についてはまだ仕様など何も決まっていなかったため,まずデザイナさん,プランナさんと詳しい仕様について話し合うところから始めました.この頃はまだ開発の進め方などよく分かっていない事が多かったのですが,デザイナさんの方からミーティングを設定してくれたり,ゲームの仕様について説明してくれたりなどとサポートをしていただいたおかげでスムーズに議論を進める事ができたと思います.話し合いの結果,溢れた経験値を数字で表示すると同時にその程度をゲージで表す機能を実装することに決まりました.

機能の実装

仕様が決定したため,次はそれに従って実装をしていきます.実装を行うには,まず選手育成のための経験値の表示がどのオブジェクトで行われており,その値はどのクラスのどの位置で計算されているのかを把握した上で,必要な処理を追加する必要があります.複雑な計算をするわけではないし比較的簡単に終わるだろうと楽観的な気持ちでプロジェクトを開いたところ,とにかくファイルが多い,オブジェクトの階層が深い,そしてクラスがでかい.普段個人で作っているようなゲームとはスケールが全く違い,まず該当する処理を探し当てる段階で苦戦してしまいました.やっとの思いで位置を特定しても他人が書いて動作しているプログラムに手を加えるのは緊張感を伴うもので,なかなか思い切った改変を加える事ができませんでした.そうは言いつつも,溢れた経験値を計算する処理自体は最初に言った通り比較的シンプルなものであったため,大きな問題にぶつかることもなく実装を終え,レビューをいただく事ができました.終わってみれば,プロジェクトの概要を把握しつつ,仕様の決定→実装→レビューという開発の1サイクルを回す事ができたという点で入門編として最適な課題だったと思います.

スカウト画面のピックアップ選手の表示数削減

概要

1つ目の課題が終わり,次に取り組むことになったのはスカウト画面のピックアップ選手のサムネイル表示数削減でした.ハチナイにはスカウトという仕組みが存在し,スカウト画面でナインスターなどのアイテムを消費することで新しい選手を手に入れる事ができます.スカウトには複数の種類がありますが,それぞれのスカウトにおいて手に入る可能性のある選手の一部をピックアップ選手として一覧で表示する機能があります.このピックアップ選手は1画面中に5~7枚程度がサムネイルとして表示され,スワイプによって他の選手を見る事ができる仕組みになっています.つまりスワイプが起こるまでは今現在画面に表示されているピックアップ以外はオブジェクトとして生成しなくても良い訳ですが,現状では表示をする予定の全ピックアップ選手のサムネイルがオブジェクトとして生成され,画面外で待機しているという状態でした.見えないオブジェクトをわざわざ生成して画面外で待機させておくのは無駄でしかないため,どうにかしたいというのがこの課題の趣旨ということになります.

f:id:nozomi_takahashi:20200920130840p:plain

スカウト画面のピックアップ表示

方針の決定

同じような問題の解決方法としてよくあるのは,最初に一度に画面内に見える分だけ画像を表示するオブジェクトを生成しておき,スワイプに従って画像の差し替えと位置の再調整を行うというものです.今回は画像だけでなく画像がタップされた時の処理も差し替える必要がありますが,大まかにこの方針で実装を進めることにしました.

f:id:nozomi_takahashi:20200920105134p:plain

方針の概略図

実装

方針が決まり,それに沿って実装を始めましたが,そこで早速問題にぶつかってしまいました.現状のコードではUnity側が用意しているGridLayoutGroupというオブジェクトの整列を自動で行なってくれるクラスによってピックアップ画像を並べていたのですが,この自動整列機能のおかげで今回の実装の肝である画像位置の再調整をする事ができません.なんとかしようとあの手この手を使って工夫を重ねた結果目的の動作を実現する事ができたものの,非常に複雑で可読性に欠けるプログラムが出来上がってしまいました.これは良くないと思いメンターさんに相談したところ,画像の一覧表示を最小限のオブジェクト数で実現する機能を提供するまさに今回の目的にうってつけのクラスが存在することを教えていただきました.このクラスを仮にクラスAとしておきます.クラスAには一覧表示のスタート地点や画像間の空白を設定する仕組みが無かったため,それらを実装した上でピックアップ画像の表示方法をGridLayoutGroupからクラスAに置き換えることで無事ピックアップ選手の表示数削減に成功する事ができました.GridLayoutGroupを使った実装方法を考えるのに多くの時間を費やしてしまったこともあり,目的を達成するのに適切なアプローチを取れているかを立ち止まって考えてみることの大切さに気づかされた課題だったと思います.

ダイアログ外タップ機能の実装についての検討

概要

私がインターン中最後に取り組んだ課題はダイアログ外タップ機能の実装についての検討でした.ダイアログとはアイテムの受け取りや選手の育成など何らかの確認や意思決定が必要となる場面で選択肢とともに表示されるウィンドウのことです.

f:id:ytfkbc:20200921163844p:plain

ダイアログの例

ハチナイでは,一部の例外を除いてダイアログ内のいずれかのボタンをタップすることによってのみ次の画面に移る事ができるようになっていますが,実質選択肢が1つしかない場合や間違えてダイアログを開いてしまった場合などに簡単にダイアログを閉じる事ができると便利です.その方法としてダイアログ外の領域をタップすることでキャンセル等の処理が行われるようにしよう,というのが本課題の概要です.「実装についての検討」と言ったことからも分かるようにインターン期間中に実装まで漕ぎ着けることはできなかったのですが,以下では実際に私が調査・検討した内容について簡単にまとめようと思います.

仕様の決定

このダイアログ外タップ機能ですが,存在する全てのダイアログに適用すれば良いというわけではありません.というのも,ダイアログによっては意図しない画面外タップによってダイアログが閉じられてしまう事が望ましくない場合もあるからです.そのため,実装の前にプランナさんと相談してどういったタイプのダイアログに対してこの機能を適用するかを決めました.

方針の決定

方針を決めるにあたって,まずダイアログの表示やボタンのコールバックイベントの設定がどのように行われているのかを調べました.その結果,ダイアログの種類毎にクラスが用意されており,その内部でそれぞれのボタンのコールバックが設定されているようでした.また,これらのクラスはそれぞれの背景となるオブジェクトへの参照も持っていたため,この背景に対して他のボタンと同じようにタップ時のコールバックを設定してあげればダイアログ外タップ機能を実現できそうだという事が分かりました.通常であればこの処理をそれぞれのダイアログのクラスに加えて作業終了なのですが,今回の場合ダイアログの種類が全部で200種類近くあったため,手作業で全てのクラスを変更するのは現実的ではありません.幸いなことにこれらのクラスは全て共通のクラスを継承していたため,この基底クラスを編集することでなるべく少ない労力でダイアログ外タップ機能を実現する方法について検討することにしました.色々と考えた結果,基底クラスにボタンの参照を1つ追加し,ダイアログ外がタップされた時にこのボタンに登録されているコールバックを呼び出す方法をとることにしました.このようにすれば,派生クラスに対する変更は要らなくなります.インスペクタからそれぞれのクラスに対してボタンの参照を登録する作業は必要になりますが,これについてはコードの編集とは違ってある程度自動化できると考えました.

問題点

ボタンに登録されているコールバックを呼び出す,という説明をしましたが,どうやってそれを行うかが大きな問題でした.ハチナイでは独自の方法でボタンのコールバックの設定をしているため,例えばButton.onClick.Invoke()などのようにしてコールバックを取り出す事ができません.この問題の解決方法として1つ目に考えたのはExecuteEventsクラスを使ってボタンをプログラムからタップし間接的にコールバックを呼び出す方法です.最初は名案だと思ったのですが,これをやるとボタンタップ時のアニメーション等まで再生されてしまうのと,力技な感じが否めなかったため見送りました.2つ目は独自に実装されているボタンのコールバックを設定する関数の内部にコールバックを取り出す処理を加えてしまう方法です.このようにすればコールバックのみをきれいに取り出す事ができますが,代わりにプロジェクトの至る所で使われている関数をダイアログ周りでしか使わない処理で汚してしまうことになります.どうしようかと悩んでいる内にインターン最終日を迎えてしまい,ダイアログ外タップ機能を実装する事はできませんでした.結論としては,素直に全ダイアログクラスを編集するのが良いということになりました(もっと良い方法があったかもしれないけど私には思いつけなかったです).実装までたどり着かなかったのは残念ですが,変更点の多さが実装うの障害になるという大規模なプロジェクトならではの問題に取り組む事ができ,良い経験になったと感じました.

振り返り

インターン中に取り組んだ課題については大体紹介したと思うので,以下では今回のインターンで感じた「会社の印象」,「良かったこと」,「反省点」について述べていきたいと思います.

会社の印象

雰囲気が良い

一番印象に残ったのは何よりもこれでした.会社と聞くと僕は厳しいとか忙しいという言葉を一番最初に思い浮かべてしまいます.もちろんアカツキの皆さんも真剣に仕事に取り組んでいるのですが,ミーティングの雰囲気や何気ない雑談からも社員の皆さんがリラックスして仕事をしている様子が伝わってきました.私の場合は今回が人生初のインターンで,さらにオンライン開催だったこともありうまくやっていけるか心配しながら初日を迎えたのですが,いざ仕事を初めてみるとそんな心配もすぐに無くなりました.

 やりたいことをやらせてもらえる

若干語弊があるかもしれませんが,やりたいことをやらせてくれる会社だと感じました.例えば今回最初に取り組んだ溢れた経験値の表示機能は元々私がハチナイをプレイした感想をもとにメンターさんに提案したものでした.正直提案をしても取り入れられることはないかと思っていたので,提案をした翌日に「やってみましょう」と言われた時には私の方が驚いていました.インターンの課題として丁度良い内容だったということもあるかと思いますが,熱意を持って提案をすればきちんと評価してくれる会社だと思います.

良かったこと

仕事としてのゲーム開発を体験できた

インターンの動機でもあった仕事としてのゲーム開発をしっかり体験できた点はとても良かったです.新しい機能の仕様についてデザイナさんやプランナさんと相談したり,初めてみる巨大なクラスを解読したり,書いたコードをレビューしてもらったりといった個人開発ではすることのない経験をたくさんする事ができました.

以前よりGitを使えるようになった

恥ずかしい話ですが,私は今までGitをほとんど使った事がありませんでした.チーム開発においては必須のスキルであるため,今回のインターンに参加する事が決まってからの1ヶ月間で急いで勉強しました.それでも分からないことは多くメンターさんに初歩的な質問ばかりしてしまいましたが,3週間の業務を通して以前よりも理解が深まったと思います.

反省点

工夫したコーディングができなかった

うまく一言で言い表せなかったためこのような見出しになりましたが,共通する処理は一箇所にまとめるなどといったプログラミングの原則を意識したコーディングができなかったと感じました.もちろん知識としては持っていましたが,機能をどのようにして実装するかに意識が集中してしまったので今後は機能だけでなく可読性・拡張性なども意識したコーディングを心がけていきたいと思います.

まとめ

反省点などもありましたが,アカツキという会社についてよく知る事ができ,ゲーム開発の楽しさを肌で感じることができた3週間だったと思います.ありがとうございました!

 

 

Akatsukiクライアントサイドインターン振り返り

こんにちは。2020/8/17~9/4の3週間Akatsukiのインターンに参加していました、弘部と申します。この記事では私が3週間何をやっていたのか、そしてその感想を書かせていただきます。

どこか良いインターンが無いかと探している方、Akatsukiのインターンに興味がある方の参考になれば嬉しいです。

目次です。

インターンについて

配属先

 今回私が配属されたのは「八月のシンデレラナイン」というスマートフォンゲームのクライアントサイドでした。

f:id:daichi-hirobe:20200904120117p:plain

八月のシンデレラナインは通称ハチナイと呼ばれ、女子高生達が甲子園を目指し野球に打ち込むという可愛さと熱さを兼ね備えたゲームです。私が最後に野球をしたのは小学校の体育ですが、そんな私でも気付いたらストーリーを最新のところまで進めてしまうほどハマってしまいました。野球が好きな方はもちろん、そうでない方も是非プレイしてみてください!

フルリモートでのインターン

記事を執筆している現在、世界的なCOVID-19の流行のため不要不急の外出が出来なくなっています。ですのでインターンのために地方から東京へ出てくるということも出来ず、自宅からのフルリモートという形で行われました。

実際にオフィスへお邪魔して、社員の方と顔を合わせてお話して、ということが出来なかったのは非常に残念ですが仕方がありません。

それにリモートワークにも良い点はあって、何と言ってもドアtoドア0分です。インターンの始業時刻は10:00なのですが、一度9:40に起床した日がありました。しかし起床した時点で出勤は完了している訳ですから、余裕で朝食を取ることすら出来ました。実際に通勤していたとしたら朝から大慌てだったでしょう。今後も出社するかリモートワークにするかを都合よく選べるようになると良いですね!

 

インターンに参加するまで

インターンに参加するまでには2度の面談がありました(人事の方との面談とエンジニアの方との面談)。参加確定後も再度エンジニアの方との事前面談があり、そこで配属チームなどを伝えられる、という形でした。特別必要な事前知識等は無く、Unityとgitが一通り使えれば問題はないと思います。UniRxを使用しているのでその辺りも少し触っていると役に立つと思います。後は配属先のゲームをしっかり遊んでおくのが大事だと思います。

 

インターンで取り組んだこと

 さて、肝心のインターンで取り組んだことですが、

  • デレスト選手入れ替え時のUIの追加、改修
  • プレゼントボックスのアイテムタブにしおり系のアイテムが表示されるようにする
  • スカウト画面の最適化、ループ対応
  • ピックアップ画面の動作の改善
  • スカウト結果から戻ってくる際の挙動の改善

 の5つの課題に取り組みました。

以下順を追って各課題についてお話していきたいと思います。

デレスト選手入れ替え時のUIの追加、改修

これが私がインターンで最初に取り組んだ課題でした。デレストというのは選手達にスキルを取得させることができるゲームモードのことです。

デレストにはいくつかのストーリーがあり、ストーリー毎に選手が取得できるスキルが異なります。当然プレイしたいストーリーを選んでプレイすることもできるのですが、どの選手にどのスキルを習得させたいかを選んで、そのスキルを取得可能なストーリーをプレイすることもできるようになっています。そしてストーリー毎にオーダーが保存されるようになっているので、選手からストーリーを選ぶと、その選手をオーダーに入れるために入れ替えが発生します。その際の画面がこちらです。

f:id:daichi-hirobe:20200904133704p:plain

 明るく表示されている8人の選手の中から交代したい選手を選ぶ、という画面です。しかしこれは少し不親切で、初見のプレイヤーがこの画面を表示されてもすぐには何をすればいのか分からないのではないでしょうか?

そこで以下のように何をすればいいのかをプレイヤーに促すUIを追加する、というのが本課題の内容です。

f:id:daichi-hirobe:20200904140424p:plain

要はある画面にUIを1つ追加したいということですね!何だか簡単そうじゃないですか...

実際にUIを追加する作業自体はすぐに完了しました。しかしこの表示は既存のUIを使い回していたのですが、デザイナーさんから既存の物よりも表示時間を伸ばして欲しい、という要望が入りました。

このUIの表示時間はアニメーションとして設定されており、エンジニアが触る領域ではありません。ですから表示時間を伸ばすためにはデザイナーさんにアニメーションの作成を依頼する必要があります。

しかし配属されて間もない私はそれをお願いするのに気後れしてしまい、プログラム側で対応します!と安請負いをしてしまったのです。

ですが本来アニメーションで制御すべきものをプログラムから制御しようとすると、どうしても無理な実装になります。結局、やっぱりアニメーションを作ってください、と後から依頼をし、二度手間となってしまいました。

他にもこのUIを追加するにあたって既存のUIの表示タイミングも変更することになったのですが、仕様の確認をする際に私が曖昧な言い方をしたせいで、どのUIの話をしているのか齟齬が生じる、ということがありました。

そしてオンラインでの会話というのは数分や数十分越しになってしまうこともしばしばで、やり取りが増えていった結果、最初の一週間は本タスクに費やされてしまいました。

チーム開発を行う上でコミュニケーションは大切だ、何てことは私も知っていました。しかしコミュニケーションの何たるかが分かっていなかったのです。コミュニケーションとは意思疎通な訳ですから、アニメーションを作って欲しいという意思、自分がどのUIを話題にしているのかという意思を伝えられなかった時点でコミュニケーションに失敗していたのです。

このような失敗は個人で開発をしていては決して味わえるものではありません。チームとして誰か他の人と一緒に同じものを作るからこそ、この失敗ができたのであり、その点でこれはインターンの大きな成果と言えます。

これまで個人開発でやってきたぜ、という方は是非Akatsukiでチーム開発を体験されてみてはいかがでしょうか?きっと新たな気づきがあると思います。

プレゼントボックスのアイテムタブにしおり系のアイテムが表示されるようにする

続いてはプレゼントボックスの改修作業をしました。

私がこれを執筆している現在(2020/09/04)ではプレゼントボックスの「アイテム」タブの中にしおり系のアイテム(URキャラクターの強化に使うやつ)が入っていません。ですが、しおり系のアイテムもアイテムなので「アイテム」タブの中に入っていて欲しいですね。その改修を行いました。

プレゼントボックスの仕様はリスト方式になっており、ナインスターは「スター」タブに、選手は「選手」タブに、というような事が記載されたリストがあり、この件はしおり系のアイテムがリストから漏れていたために「すべて」以外のタブに含まれないようになってしまっていたのです。

ですので、リストの中にしおり系アイテムを含めてやる、という作業でした。

こちらは意図していない挙動なので上の課題よりも先にアプリに入れ込まれることになりました。私のインターン期間中には間に合いませんでしたが何月何日のアップデートに入れます、と聞いた時はとても嬉しく、早速その日の夜にプレゼントボックスにしおりを用意しました。

スカウト画面の最適化、ループ対応

続いてスカウト画面の改修作業です。スカウト画面にはたくさんのスカウト達が並んでいました。これは比喩表現ではなく、文字通りスカウト画面にはスカウト達が並んでいたのです。

f:id:daichi-hirobe:20200904144307p:plain

このようにスカウト画面には、見えないところでスカウトの背景画像がずらっと並んでいました。そしてこのように一列に並んでいるせいで、端のスカウトから端のスカウトへの移動は間のスカウトを高速でめくることで実現していました。見えないところに画像を配置しても無駄ですし、端のスカウト間の移動はもっとスムーズにしたいですね。

そこで以下のように改善を行いました。

f:id:daichi-hirobe:20200904144717p:plain

画面外に配置するのは必要最低限に留め、端のスカウト同士はループするように隣りに配置することでスムーズに移動できるようにしています。

この課題が今回のインターンの中で最大規模のもので、スカウトの表示周りの処理をかなり大幅に変更することになりました。

Akatsukiのインターンではこのような割と規模の大きな課題にも取り組ませてもらえます。メンターの方もサポートをしてくださるので自分の実力を試す良い機会だと思います。

ピックアップ画面の動作の改善

スカウト画面の次はピックアップ画面の改修を行いました。ピックアップ画面とはそのスカウトの注目選手のステータスやスキルを確認できる画面のことです。

f:id:daichi-hirobe:20200904150133p:plain

この画面では下のサムネイルや矢印ボタンを押すと表示する選手を切り替えることができるのですが、その切り替え処理が非常に重たかったのです。

f:id:daichi-hirobe:20200904150308p:plain

でっかいスパイクが立っている部分が切り替え処理をした際の負荷です。見切れていますが15FPSを優に割っていることが分かります。これを解消するというのが本課題の内容です。

さて、重たいと言っても、なぜ、何がそんなに重たいのでしょうか?

ピックアップ画面の下部には注目選手のサムネイルが並んでいますが、これはスカウトと同様に画面外にまで並んでいました。

f:id:daichi-hirobe:20200904150736p:plain

選手の切り替え時にはその選手のサムネイルが画面中央に来るようにサムネイル群を動かしていました。ピックアップ選手は、多いスカウトでは数十人にも及ぶのでこれだけのサムネイルを一斉に動かせば確かに重くなりそうです。

と思っていたのですが処理が重たくなっている部分の負荷の内訳を確認してみると以下のようになっていました。

f:id:daichi-hirobe:20200904150959p:plain

GC.MarkDependenciesという処理が最大の負荷のようです。UIを動かしてGCがどうにかなるというのは少し考えづらいですね。更に言えばスカウトによっては注目選手が2,3人しかいない場合もあるのですが、数十人でも2,3人でも同じぐらいの負荷がかかっていました。UIを動かすことが原因では無いのでしょうか?

調査を進めたところ、原因は「習得可能スキル」や「才能」の表示にあることが分かりました。これらの表示に含まれるUIはキャラクターを切り替えるごとに全て破棄されて生成され直すようになっていたのです。その際のメモリの開放、もしくは確保に起因してGCが働いていた、というのが負荷の原因でした。よって、UIを一々作り直すのではなく既にあるものを再利用するようにした結果、負荷は以下のようになりました。

f:id:daichi-hirobe:20200904153048p:plain

水色のスパイクが立ち上がっている部分が選手切り替え時の負荷です。上の巨大なスパイクに比べれば遥かにマシですね。実際に動作は非常に軽快になっており、無事最適化に成功しました。

他の誰かが作ったものを最適化するというのは意外な所に原因があったりして非常に面白く、これも決して個人開発では味わえない経験でした。

スカウト結果から戻ってくる際の挙動の改善

最後の課題はスカウト結果から戻ってくる際の挙動の改善でした。

挙動の改善とはつまりどういうことかと言うと、スカウト結果から戻ってくる際、OKボタンを押して戻ってくる方法と、左上の戻るボタンを押して戻ってくる方法があります。

f:id:daichi-hirobe:20200904154613p:plain

どちらも押すとスカウト画面に戻ってくるのですが、戻るボタンで戻った場合、最後に引いたスカウトと異なるスカウトが表示されることがある、ということがスカウト画面の改修中にメンターさんによって発見されました。なのでついでにそこも直してしまおうということになったのです。

どこを直せばいいのかはすぐに分かったのですが、問題はどう直せばいいかでした。そもそも戻るボタンとOKボタンの挙動は同じであるべきなのか、OKボタンを押した場合にはレビューのお願いが表示されるが戻るボタンを押した場合には表示されないのは意図しているのか、その辺りの仕様が問題でした。最初の課題と同じ轍は踏むまいと、自分から、そして齟齬の無いよう言葉と表現を選びプランナーの方に質問すると「戻るボタンの挙動をokボタンに合わせるでお願いします!」とあっさり答えが帰ってきました。のでスムーズに作業を進める事ができました。3週間の中で成長できたということだと思います。

まとめ

Akatsukiの3週間のインターンは気づきと学びの連続でした。

大規模なプロジェクトに携わるということ、チームで開発するということは一人でゲームを作っていては決して経験することができません。特にAkatsukiのインターンはメンターの方の指示にただ従う、というような事は無く、基本的には自分で作業をして分からないところは質問する、もしくは結果的に間違っていれば指摘していただく、という形なので実際の業務に比較的近いと思いますし、その分身につく物も多いと思います。

書籍購入制度というのもあり、これはメンターの方の許可が必要ですが、技術書等を経費で購入してもらえるという太っ腹制度です。私も技術書を2冊購入していただきました。技術書って結構高いので非常にありがたいです。こういう風に就職活動の場だけでなく、学生の学びの場としてもインターンを提供しているのはAkatsukiのいい所だと思います。

また、今回はフルリモートでのインターンでしたが、このような状況下でもインターン生を受け入れるという事は、インターンにかなり力を入れている企業であると言えると思います。実際に事前の面談やインターン参加直後の受け入れなどもリモートでありながら非常にスムーズで、困るような事は一切ありませんでした。ですので就業型のインターンが初めて、という方も是非Akatsukiで初挑戦してみてはいかがでしょうか?僕もこのインターンが初めての就業型でした。

最後になりましたが、3週間お世話になったAkatsukiの皆様、大変ありがとうございました。

アカツキでフルリモートインターンをしました

こんにちは!

この度クライアントエンジニアとしてインターンシップで勤務させていただきました、堀越と申します。

本記事では、インターンシップ期間 (2020年9月1日〜9月18日) 中に取り組んだこと、感じたことなどを書いていきます。アカツキのことを知りたい方、これからインターンシップを受けようと考えている方などの手助けになれば幸いです。

インターンシップへ参加した経緯

まずは、インターンへ参加した経緯をお話ししたいと思います。

就活を考え始める季節、春。

ということで、今年の5月に開催された逆求人イベントに参加し、そこで、アカツキさんとお話ししました。

自分としては、就職するのであれば自分が楽しめることを積極的にできる職場がいいということが一番にあったので、そういったようなビジョンを掲げていたアカツキさんに興味を持ちました。

そして、そういったことを自身で感じるために、自身の持っているスキルで参加できるインターンとして、参加させていただくことにしました。

インターンシップで取り組んだこと

さて、上記の理由でインターンに参加したわけですが、次に具体的にインターンで何をしたのかをお話ししたいと思います。

今回インターンとして関わらせていただいたのは、アカツキを代表するスマホゲーム『八月のシンデレラナイン』です。個人的に高校時代の思い出が蘇ってきてなんとも言えない気持ちになるゲームです。

f:id:toshiyuki_horikoshi:20200918184929p:plain

そこでは、自分はクライアントエンジニアとしてインターンに参加しました。

業務内容としては、クライアントサイドの機能改修です。

以下にインターン中に主に取り組んだことを紹介していきます。

次ステージへの自動遷移

まずは、次ステージへの自動遷移を実装しました。

現状、ステージをクリアした際に、ステージがアンロックされる場合はそのステージに遷移するようになっています。しかし、ステージを攻略している際にいちいちステージのアイコンをタップするのは面倒です。

そこで、ステージをクリアした後に、挑戦できるステージがある場合には自動で挑戦する直前の画面まで遷移する機能をつけることで、ユーザーの負担を減らす仕組みを実装しました。

f:id:toshiyuki_horikoshi:20200918191656p:plain

強化時のボイスをプロフィールボイスからシーンボイスへと変更

次に、強化時のボイスをプロフィールボイスからシーンボイスへと変更しました。

ハチナイには、様々な選手がいるのはご存知かと思います。また、それぞれの選手でもシーンごとで再生されるボイスが違うということも知られているでしょう。これまで、選手シーンを強化する際には、再生されるボイスは別々のシーンでも同一の選手であれば同じボイスが再生されていました。

今回は諸々の理由で、製品版にはこの変更を含めないことになりましたが、開発段階ではシーンごとに再生されるボイスを変更することによって、そのシーンの背景だったり、情景だったりがより感じられるようになったのではないかと思っていました。

デレストでデレストのオーダーを参照して音声が再生されるようにする

現在、デレストで練習メニューを実行する際に、デレストオーダーに含まれていない選手のボイスが再生されることがありました。

これを、デレストオーダーに含まれている選手と、一緒に練習する選手のボイスのみが流れるようにすることによって、違和感なくデレストを行えるように変更しました。 

インターンシップで感じたこと

今回のインターンシップはフルリモートということもあって、実際にアカツキという会社の雰囲気を知りたくてインターンシップに参加した自分にとっては少し残念ではありましたが、実際に業務に関わる上で、とても貴重な経験をさせていただきました。

また、他のインターンシップ生や今回の業務では関わることのなかった社員の方とリモートではありますが交流をする機会を数多くいただきました。

リモートで業務に携わることについて、自分自身多少なりとも不安に感じることはあったのですが、メンターの方や同じチームの方と協力をすることによってタスクをこなす際に特にそれらのことが障壁となるようなことありませんでした。

業務を行う面でも、社員の方と関わってアカツキのことを知るという面でも自分にとってはとても有意義なインターンになったかと思います。

最後に

短い期間ではありましたが、アカツキという会社を実際に業務に携わることでより深く知ることができたと感じています。

また、実際にリリースされているアプリケーションの改修をするにあたって、まだまだ自分の至らないことなど、多くを学ばせていただきました。

本当にありがとうございました。

CloudFormationでAuroraのMySQL5.7インプレースアップグレードをする際のハマりポイント&対応方法

Amazon Aurora MySQL のインプレースアップグレード機能

つい先日、Amazon Aurora にて、MySQL 5.6互換のバージョン1.xから、MySQL 5.7互換のバージョン2.xへインプレースアップデートが可能になりました。

Amazon Aurora が MySQL 5.6 から 5.7 へのインプレースアップグレードをサポート

この機能を使うことで、従来のようにスナップショットからの復元やレプリケーション、インスタンスの切替といった作業をしなくても、エンドポイントなどはそのままに、簡単にMySQL5.7互換にアップグレードすることが可能になります。

早速この機能でアップグレードを試みたのですが、CloudFormationで管理されているAuroraクラスターをアップグレードする際にちょっとハマったことがあったので、その内容と対応方法をシェアします。

アップデート前のRDS用CloudFormation stack

更新前のDBクラスタのCloudFormationでの定義はこんな感じでした。(わかりやすいよう最小限の記述のみにしてあります)

DevAuroraParameterGroup というカスタムのインスタンスパラメータグループを使っています。

---
AWSTemplateFormatVersion: '2010-09-09'
Description: RDS for sandbox
Resources:
  DevAuroraParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: Development Aurora parameter group
      Family: aurora5.6
      Parameters:
        max_connections: '1024'
        wait_timeout: '300'
  DevAuroraParameterGroup57:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Description: Development Aurora parameter group for 5.7
      Family: aurora-mysql5.7
      Parameters:
        max_connections: '1024'
        wait_timeout: '300'
  DBCluster:
    Type: AWS::RDS::DBCluster
    Properties:
      DBClusterIdentifier: test-cluster
      DBSubnetGroupName:
        Fn::ImportValue: DBSubnetGroup
      Engine: aurora
      EngineVersion: 5.6.mysql_aurora.1.22.2
      MasterUsername: "{{resolve:ssm:rds.username.default:1}}"
      MasterUserPassword: "{{resolve:ssm-secure:rds.password.default:1}}"
  DBInstance:
    Type: AWS::RDS::DBInstance
    DeletionPolicy: Delete
    Properties:
      DBClusterIdentifier:
        Ref: DBCluster
      DBInstanceClass: db.t2.medium
      DBInstanceIdentifier: test-db
      Engine: aurora
      EngineVersion: 5.6.mysql_aurora.1.22.2
      DBParameterGroupName:
        Ref: DevAuroraParameterGroup
      DBSubnetGroupName:
        Fn::ImportValue: DBSubnetGroup

ハマったこと

これを、以下のように書き換えて適用することで、MySQL5.7互換バージョンへのインプレースアップグレードを試みます。

@@ -82,8 +82,8 @@
       DBClusterIdentifier: test-cluster
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
       MasterUsername: "{{resolve:ssm:rds.username.default:1}}"
       MasterUserPassword: "{{resolve:ssm-secure:rds.password.default:2}}"
   DBInstance:
@@ -94,9 +94,9 @@
         Ref: DBCluster
       DBInstanceClass: db.t2.medium
       DBInstanceIdentifier: test-db
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
       DBParameterGroupName:
-        Ref: DevAuroraParameterGroup
+        Ref: DevAuroraParameterGroup57
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup

しかし、以下のようなエラーで失敗してしまいました。

{
  "LogicalResourceId": "DBCluster",
  "ResourceStatus": "UPDATE_FAILED",
  "ResourceStatusReason": "The current DB instance parameter
     group sandbox-rds-devauroraparametergroup-fxfe7dqcn31p
     is custom. You must explicitly specify a new DB instance
     parameter group, either default or custom, for the engine
     version upgrade. (Service: AmazonRDS; Status Code: 400; Error Code: InvalidParameterCombination; Request ID: ...)"
}

カスタムのインスタンスパラメータグループを使っているため、5.7に対応した新しい DevAuroraParameterGroup57 に切り替えるよう指定しなければなりません。 CLIであれば modify-db-cluster--db-instance-parameter-group-name オプションでこれを指定可能です。 しかし、どうやらCloudFormationではこれを渡すことができない様子です。同時に DBInstance の更新をしても、異なるリソースの変更までは拾ってはくれないようです。。

対応方法その1

こういう時の一つの方法は、いったんCloudFormationの管理下から外してしまい、手動でアップデートしたのち、CloudFormationにインポートし直すという方法です。

  1. DBCluster および DBInstanceDeletionPolicy: Retain を指定して適用することで、CloudFormationによってこれらが削除されないようにします。

  2. DBCluster および DBInstance の定義を削除し、更新を行います。

  3. 残ったクラスターをAWSコンソールで5.7に更新します。

  4. 5.7の定義で再度 DBCluster および DBInstance の定義を追加し、「インポート」 を行います。この時、追加する各リソースに対応するインスタンスの識別子(ここでは test-clustertest-db )を指定することで、CloudFormationスタックに既存リソースを取り込むことが可能です。

  5. ドリフト検知を行い、定義と実態にズレがないことを確認します。

しかし、手動オペレーションはなるべく避けたいということで、次のような方法も考えてみました。

対応方法その2

エラーメッセージを見るに、カスタムのインスタンスパラメータグループを使わなければ良いのだろうということで、いったんデフォルトに戻し、インブレースアップグレード後に再びカスタムのパラメータを適用しなおしてみます。

まず、 DBInstance のパラメータグループをデフォルトである default.aurora5.6 にしてスタックを更新します。

@@ -96,7 +96,6 @@
       DBInstanceIdentifier: test-db
       Engine: aurora
       EngineVersion: 5.6.mysql_aurora.1.22.2
-      DBParameterGroupName:
-        Ref: DevAuroraParameterGroup
+      DBParameterGroupName: default.aurora5.6
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup

次に、 インプレースアップグレードと合わせて、新しいカスタムのパラメータグループも指定して再度更新します。

@@ -82,8 +82,8 @@
       DBClusterIdentifier: test-cluster
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
       MasterUsername: "{{resolve:ssm:rds.username.default:1}}"
       MasterUserPassword: "{{resolve:ssm-secure:rds.password.default:2}}"
   DBInstance:
@@ -94,8 +94,9 @@
         Ref: DBCluster
       DBInstanceClass: db.t2.medium
       DBInstanceIdentifier: test-db
-      Engine: aurora
-      EngineVersion: 5.6.mysql_aurora.1.22.2
-      DBParameterGroupName: default.aurora5.6
+      Engine: aurora-mysql
+      EngineVersion: 5.7.mysql_aurora.2.07.3
+      DBParameterGroupName:
+        Ref: DevAuroraParameterGroup57
       DBSubnetGroupName:
         Fn::ImportValue: DBSubnetGroup

これで、無事にCloudFormationのみでインプレースアップグレードが完了しました。 またMySQL5.7への移行完了後も、DBは問題なく利用できることを確認できました。

後者の方法は途中でパラメータグループの更新が余分に入るという欠点がありますが、対象が多くて自動化したい場合などはこちらの手段の方が良いこともあるかもしれません。

もっとうまく対応できる方法が提供されるとありがたいのですけれどね。

モバイルで動くShaderでの流体表現


この記事は Akatsuki Advent Calendar 2020の25日目の記事です.
前回の記事は脆弱性診断時のAndroidのプロキシ設定を行うコマンドラインツールを作った話+その他内製ツールの紹介でした。

 

 

はじめに


新卒研修で流体を用いたスマホゲームをリリースする機会がありましたので,実装を紹介します.

具体的には,ミラーケーキ(ケーキの一種)を作成するゲーム内で,
ケーキに溶けたチョコをかけてコーティングする作業(グラサージュ)の実装です.

(実際のアプリ: iOS, Android

実際の動画


実際のゲームプレイ動画がこちらになります.この部分の実装方法を以下で説明していきます.

f:id:AxI:20201223125005g:plain
ちなみに実際のミラーケーキはこんな感じです.

実装

概要:ケーキの柄が変わってるだけ

モバイルで三次元流体表現を行うことはスペック上難しいので,二次元で液体挙動の近似計算を行い,影で立体感をつけることで上記の挙動を実現しています.
具体的には,ケーキオブジェクトのテクスチャをリアルタイムで変化させることで,ケーキの表面に液体が流れているかのように見せています.

f:id:AxI:20201224123839p:plain
ぱっと見,ケーキになにか物体が覆いかぶさっていくように見えますが,実はケーキの柄が変わっているだけです.

実装は主に3つのパートに分かれています.以下の処理はUnity×Shaderで実装されています.
1.液体の広がりを表現
2.液体の流れを表現
3.液体の立体感を表現

液体の広がり


液体の広がりでは,ミラーケーキでのグラサージュの特徴である,注いだ点からじわーっと広がる挙動を表現しています.

具体的には二次元上で液量を定義し,”ぼかし”(平滑化)を行うことで液体が多いところから少ないところへ広がる動きを計算しています.毎フレームShader上で周囲のピクセルの液量の平均をそのピクセルの次の値とすることで,下図のように注いだ点から周囲に広がり,付近の液量と影響しあう挙動となります.

f:id:AxI:20201223133432p:plain

上図において,液量2以上など,閾値以上の部分のみ液体が存在すると定義し,液体が存在するところは別のテクスチャを参照するとすることで下図のようになります.

f:id:AxI:20201223133450p:plain

液体の流れ


液体の流れでは,液体が流れていく方向へ色も移動する処理を行います.

先ほどの液体の広がりで用いた図を見ると,液体範囲の縁は閾値に近くなることがわかります.よって,閾値に近い部分に黄色をつけるとするならば,黄色は常に外側,つまり液体が流れていく方向へ移動することになります.
このように液量が似ているピクセルは似た色を参照するという仕組みにすることで,流れていく方向に色が移動しているような挙動になります.

f:id:AxI:20201223133505p:plain
具体的には,液体範囲が液体テクスチャを参照する際,テクスチャの参照座標を液量分ずらすことで,任意のテクスチャにおいて液量に伴い変動するマーブル模様が生成され.流体っぽい挙動を実現しています.(時間が経つと戻っていく など,実際の流体挙動とは大きく異なる部分があります)

f:id:AxI:20201223133516p:plain

液体の立体感


液体の立体感は,液体の広がりで計算された,液体が存在する範囲の周囲に影をつけることで表現されています.
具体的には,テクスチャ上で光の方向を定義し,液体が存在しない かつ 光の逆向きに隣接するピクセルに液体が存在するピクセルを黒くします.

f:id:AxI:20201223133532p:plain

f:id:AxI:20201223133542p:plain

影をつけることで一気に立体感が出たと思います.影と反対側にハイライトをつけることでより立体感,艶感がでます.
上記の三つの要素を合体させることでモバイルで動く流体表現を実装しました.

おわりに


実際のアプリリンクです.楽しんでいただけたら幸いです.

Mirror cakes - Apps on Google Play

Mirror cakes on the App Store

 

限定的な状況下の実装ですがみなさまの発想の助けになれば幸いです.
来年も,おもしろいがたくさん生まれますように,メリークリスマス.