mori

専門学校HAL×Aiming 産学連携プロジェクト(後編)


こんにちは、人事の森です。

前編に続き、「HAL×Aiming産学連携プロジェクト」後編をお送りします。

今回は、栄えある優秀賞を受賞した2作品を紹介させて下さい。優秀賞は当初、1作品のみを選出する予定でした。ところが、どちらの作品も系統が異なりとても面白い!吟味した結果、2作品共に優秀賞を授与する形となりました。

優秀賞受賞作品は、Aiming名義で、App StoreとGoogle Playでリリースします。

それでは、2つの作品を紹介させて頂きます。

 

まずは1つ目、こちらはHAL大阪チームの作品です。

優秀賞:クレイジーヘッドボーイズ(HAL大阪:it OKASHI!チーム)

 

キュートでポップな二人のキャラクターが頭をぶつけながら疾走する爽快感あふれるラン&ジャンプアクションゲームです。

  • タップでジャンプというシンプルな操作だが、画面の上下にプレイヤーを置くことで、良い意味での複雑なゲームデザインが構築されている
  • ゲーム開始までのタップ数が少なく、迷うことなくプレイ開始に誘導している
  • チュートリアルから体感型レベルデザインが組み込まれていて、失敗を通じて正解を模索させるような作りになっている
  • 骨太なアクションゲームに仕上がっていて、しっかりと遊べる
  • ビジュアルにも力入れている

 

カメラアングルも独自性があり、この効果によりスピード感が倍増しているように感じます。こちらの操作方法で、上手くいった時、墜落しちゃった時を実感できるので、「もう1回!」と何度もプレイしたくなりました。キャラクターが可愛いのも良い感じ。Sランクを取るのは非常に難しく、テクニックが必要です。私は未だそこに到達していません。どなたか、タイムアタックで勝負しませんか?

ダウンロードはこちらから。

App Store からダウンロードGoogle Play で手に入れよう

 

 

 

 

続いてHAL東京チームの作品

 

優秀賞:挟撃のインターポーザー(HAL東京:雨霧工房チーム)

個性的なキャラクターが多数登場し、敵を挟んで倒すというやりごたえのある戦略性がおすすめポイントです。

  • はさみ将棋に、独自の世界観とキャラクター性を上手に融合させている
  • ターンベースの詰め将棋といったプレイフィール
  • 見た目とは裏腹に、手応えのある難易度に調整してあり、しっかりと考えないと攻略できないというのが秀逸
  • リプレイ性が高い
  • ステージボリュームが豊富で倍速機能もついている(気遣いが良い感じ!)

 

アプリ内課金の要素はないものの、商用ゲームさながらのまとまりがあり、とても完成度の高いゲームです。クラシカルな内容に、演出とイラストが見事に彩りを与えています。ステージごとに満点をとるのは難しく、満点をとるために熱中してプレイしてしまいました。「挟撃のインターポーザー」というネーミングも素敵です。ゲーム内に漂うラノベ的な雰囲気も、このタイトルに上手く表現されていると思います。

ダウンロードはこちらから。

App Store からダウンロードGoogle Play で手に入れよう

 

 

 

いかがでしょうか・・・?2作品共に短期間の開発ながら非常に完成度が高く、楽しく遊べるゲームに仕上がっています。それぞれ配信期間は、2018年3月31日までを予定していますが、落し切りのゲームなので、DLしてしまえば配信期間後もプレイすることが出来ます。皆さま、是非手に取って、遊んで見て下さい!

(まとめ)

さて、今回の産学連携プロジェクト。4月のオリエンテーションから始まり、中間企画発表、総合作品審査、受賞式、リリースと経て幕を閉じました。とても濃密な内容でした。優秀賞受賞チームの皆さんには、リリース準備の際に、+αの対応事を様々依頼しましたが、そのレスポンスの速さと的確な内容から、非常にスムーズに進めることが出来、感謝しております。

また、普段開発側の人間でない私にとっては、開発したゲームをリリースまで持っていくこと、そのために必要なもの、時間、やるべきこと、注意点、落とし穴、等々・・・通して体感することが出来たことはとても貴重な体験でした。こんな作業、手間をかけてゲームはリリースされお客様に届くのだと改めて認識したことと、ゲームを作り、世に生み出す開発者の方のお仕事を少しでも体験できたことも良かったです。

 

最後に・・・

このプロジェクトは、HAL学生さんの「ゲーム制作」や「チーム開発」への熱意、工夫、技術、拘り、愛、頑張りなしには成立しないプロジェクトです。あわせて、これらの企画~実施、運営までのサポートを下さったHALの先生方のお力添えやお気遣い・・・こちらも学びが多く、このような機会を頂けたことに感謝しています。関わって頂いた皆様、ありがとうございました。

 

(おまけ)

クレイジーヘッドボーイズ、どうしてもRANK Sがとれませんでした。28秒の分厚い壁、私はいつ越えられるのでしょうか。

 

私の中の最高記録のRANK Aで、「産学連携プロジェクト」(前編/後編)を締めたいと思います。(完)


mori

専門学校HAL×Aiming 産学連携プロジェクト(前編)


こんにちは。人事の森です。

今日は、学校法人・専門学校HALとAimingが産学連携の1つとして行った「産学連携プロジェクト」について紹介したいと思います。(前編)
「産学連携」とは、教育機関である学校法人・専門学校HALと、民間企業である株式会社Aimingが連携し、学生がスマートフォン用のゲーム開発に挑戦するというプロジェクトです。

このプロジェクトは、「今日は皆さんに、ちょっとゲームを作ってもらおうと思います」という映画バトルロワイヤル風に始まりました。(古いですか)

内容はこうです。

  1. Aimingが出したテーマに沿ってHALの学生がゲームを制作する
  2. 提出されたゲームを「企画段階」と「完成品」の2段階で審査する
  3. 優秀なゲームには、Aimingが用意した幾つかの賞を授与する

特に優秀なゲームは、Aiming名義で、App StoreとGoogle Playからリリースします。

 

制作は、企画期間1ヵ月/開発期間1ヵ月という、とても限られたスケジュールです。この内容に対し、HALの400名を超える学生が、チームを組んで挑戦してくれました。

Aimingがお題としたテーマは以下の3つです。

  1. 最初の3分のおもしろさ
  2. 新規性
  3. 遊びやすさ

この3つを軸に、作品審査を行いました。

iOSの開発は初めてという方が多い中、たくさんのチャレンジがあり、工夫があり、熱意があり、審査であるにも関わらず、ついつい楽しくプレイさせて頂きました。

企画段階のものから内容を大きく変更し、素晴らしくブラッシュアップされた作品もありました。ネットワークに挑戦し、オンライン要素を取入れた作品もありました。チームワークや頑張りの跡が見られる作品は、審査にも熱が入ります。

選びきることに苦悩はありましたが、Aimingが用意した賞は全部で4つ。
「優秀賞」、「ゲームデザイン賞」、「技術賞」、「審査員特別賞」です。

前編では、優秀賞を除く5つの受賞作品について紹介したいと思います。

 

 

まずは、ゲームデザイン賞:「Pechantet」(HAL大阪)

指でなぞった地面が切り取られ折り曲がり、そこに敵を挟んで倒すという、操作感と見た目も面白いタワーディフェンスです。ゲームデザインに優れているポイントは、リソース管理と操作が上手に融合している点です。大きくなぞると簡単に敵を挟めますが、次の敵を攻撃することが出来なくなってしまう。敵の動きを予想して、最小範囲で切り取り挟む。更に角度も考え遊ぶというテクニカルな要素がとても面白い作品です。

 

 

続いて、技術賞:「双璧のマジカライズ」(HAL名古屋)

画面いっぱいの大量のスライムを魔法の壁でプチプチ挟んで倒していく、小気味良く簡単な操作で楽しめるゲームです。
ゲームとしては荒削りであるものの、コアメカニクスである指でなぞったルートのスライムを巻き込んでいくというのが、”わかりやすいゲームデザイン + 面白いビジュアル + 簡単操作のユーザビリティ” として、バランス良くまとまっていました。
ベースとしてテクニカルなアプローチがあり、この美点を技術賞として評しました。

 

 

そして、審査員特別賞は個性豊かな3作品がノミネート。

「ヤンキーキャット」(HAL名古屋)

ヤンキーを操作して相手のヤンキーを倒す「喧嘩上等」のシミューレーションに、ネコの要素が加わることで癒やしの効果が得られるネコゲーです。
ベースは挟み将棋で、相手ヤンキーを挟んで倒していくというものです。そしてそこにネコ登場!
通常は倒すしかないヤンキーも、ネコを間に入れる(相手とネコを挟む)ことで場が和み、和解すれば相手を仲間にすることができます。
ネコ好きに悪い奴ぁいねぇ理論ですね。(私は犬派です。)
ヤンキーというクラシカルな題材ではあるものの、細かな動きや演出面など細部までこだわりが見え、ゲーム全体を通してクオリティの高さがうかがえるゲームです。
センスが光るテキストに、にやにやしながら審査しました。

 

 

「ぽより~」(HAL名古屋)

風船を思わせる妖精”ポヨリー”を、上手く操作し上昇させて故郷に帰してあげる、とても可愛いビジュアルのゲーム。
ポヨリーを指で挟んで空気を押し出し、その反動でどんどん上昇させてゴールに導いてあげます。
直感的な操作と、瞬時にルールを理解できるゲームデザインが秀逸です。
操作は簡単ですが、挟み方によってはポヨリーが右に左に飛んでいき、ゆっくり操作すれば落下していくので、慎重かつ大胆なプレイが求められます。
キュートな世界観も魅力のゲームです。

 

 

「日狭茶飯事」(HAL東京)

ふりそそぐ食品をトングで挟んで食べまくる。シンプルながら瞬間的に熱くなれるゲームです。
本能に訴えかける説明不要のゲームルールとポップなビジュアルが上手く組み合わさり、高い中毒性と、1人プレイながらも場を盛り上げることのできるパーティーゲームに仕上がっています。
ゲーム開始までのタイトルやイントロのカットシーンなどもポップな演出で彩られ、細部まで抜かりがありません。
丁寧な作りを感じます。プレイ動画は、YouTube投稿にも向いてるかもしれません。

 

さて、栄えある優秀賞は・・・!?(後編に続く)

 

(おまけ)HAL大阪での授賞式の1コマ

素晴らしいゲームを作ったチームメンバーの皆様と、素敵な先生で記念撮影★

 


ログの収集基盤をサーバレス化した話


初めまして、エンジニアの鴛海太一です。
主にデータ分析や、その基盤ツールを作るチームに所属しています。

今回は、アプリトラッキングツールから送られてくるログをBigQueryに入れるための機構をサーバレス化した話になります。

サーバレス化の目的と以前の構成

以前の構成は以下のようなものでした。

この構成は、安定して1年ほど稼動していましたが、kubernetesの知識が必要で、メンテナンスがしにくいことが欠点でした。

サーバレス化

そこで、以下の図の様なマネージドサービスを使ったサーバレスアーキテクチャを構築しました。

概要

まず、Google Cloud Functionsはコールバックを受け取り、Google Pub/Subにpublishします。
その際に、標準出力でログを出しておき、それをGoogle Stackdriverで拾い、1時間おきにGoogle Cloud Storage(GCS)に保存します。
GCSに保存する理由は、何かしらの理由でログが欠損した場合に復元するためです。
Google Pub/SubにpublishされたログデータをDataflowでsubscribeし、不要なカラムの除去を行い、Google BigQueryの指定のテーブルにデータを挿入します。

メリット

この構成にする利点は、無停止更新が行なえること、スケールが簡単なことです。
Cloud Functionsがダウンしている場合、広告SDK側はステータスコード200が返されるまでデータを保持するので、問題がありません。
Pub/Subがダウンしている場合も、同様にCloud Functionsでpublishが成功しなかった場合に、ステータスコード200を返さないようにすることで、広告SDK側でストアしてくれます。
Dataflowがダウンしている場合は、subscribeされないため、Pub/Subがデータを7日間まで保持してくれます(https://cloud.google.com/pubsub/quotas)。
この様に一部が停止しても問題なく動作するため、Cloud Functions、Pub/Sub、Dataflowの無停止更新が可能になります。
また、Pub/Subを間に挟むことによってデータ量が増大した場合にも対応できます。

デメリット

逆にデメリットとしては、ベンダーロックインが発生すること、Dataflowの扱いが難しいことです。
Dataflowは、Pipelineという考え方を取り入れており、関数型のような考え方が要求されます。
他の部分でのコード量は少なく単純でしたが、Dataflowは少し複雑なものを書く必要がありました。

おわりに

ログ収集の機構をサーバレス化した実例をお話ししました。
マネージドサービスを使うことによって、管理コストを減らすことが可能です。
また、Pub/SubやCloud Functionsは、料金的にも安くおさえられるのでオススメです。


新人研修の一環で社内ツールを制作しました


はじめまして!17年度新卒エンジニアの島です。

今回は私が参加した「新人研修プロジェクト」について紹介したいと思います。
内容は、「新人だけでプロジェクトを立ち上げ、社内ツールを制作する」というものです。
その制作過程や成果物、研修の振り返りまでをまとめました。

研修の概要

研修の概要は以下の通りです。

  • 研修は短期間(勤務時間の一部を利用して2か月程度)かつ小規模人数で新卒だけのチームを組み、ツール制作を行う。
  • 東京本社、大阪スタジオの2チームが同じテーマで開発する。
  • 最終的に社長に向けて成果物のプレゼンテーションを行う。
  • 2チームでコンペを行い、選ばれた成果物は実際に社内で実用される可能性がある。

新卒だけで短期間でチーム開発を行いプレゼンをすることは貴重な経験だと思います。
私たちのチームはエンジニア2名、デザイナー1名、プランナー1名の構成でした。
制作する社内ツールとは、「タレント検索ツール」です。
弊社では規模拡大に伴って社員の顔と名前が一致しないことが増えて参りました。
この問題を解決するという目的のもと、2ヶ月ほど業務の合間に開発を行いました。

研修中について

私たちはRuby on railsを中心に開発しました。
制作物の全体像を決めるまではチーム全員で会議を重ねました。
実際に制作する段階に入ってからは

  • エンジニア:コーディング
  • デザイナー:UI、ロゴデザイン
  • プランナー:コンテンツ内容の企画、報告の資料作成と発表

のように、作業を分担して行いました。

また、研修中はプロダクトオーナーや技術監修をしてくださる先輩方のサポートがありました。
開発環境やデプロイ環境のことはもちろん、基本的な開発の相談を気軽に出来たので良かったです!

私たちのチームでは週に1度、監督やサポートの先輩方を交えて報告会を行っていました。
報告会では、進捗報告を中心に問題点の洗い出し、要件確認等を行いました。
この場は開発している私たちにとっても非常に重要で、特に作業スケジュールを全体で共有すること、そして次の週までに消化するタスクを見積もることに繋がりました。

私がやったこと

実際に私がこの研修で行った作業について紹介します。
私はエンジニアとしてユーザー認証やトップページ全体、プロフィール周りを作成しました。
デザイナーさんの成果物をページに組み込んだり、ページレイアウトの調整も行いました。
フロントエンドの開発は特に経験はありませんでしたが、いい経験になったと思っています。

また今回の研修では、単純にタレント(社員)を検索できるツールとしてではなく、コミュニケーションが活性する要素を含めることも目標としていました。
そこで、タレントにタグを登録できる仕組みを導入し、そのタグによって検索するようにしました。
たとえば「エンジニア ゲーム」でゲームが好きなエンジニアを検索することが出来ます。
他にも何気ない瞬間に社員の顔が目に入るようトップページに表示される社員を日替わりで切り替えたり、プロフィールを覚えやすいよう自己紹介のひとことを社員それぞれが設定できるようにしたりと、コミュニケーションにつながるよう工夫しました。

成果物の紹介

実際に制作したツールを簡単に画像で紹介したいと思います。
ツールの名前はMikkeにしました。オシャレなロゴがお気に入りです!

研修の振り返り

振り返りはKPTで行いました。
KPTはそれぞれの感じていることや何が良くて何が悪かったのかを可視化することが出来るので振り返りには非常に有効です。

私たちのチームでは、

Keep

  • 完成させることができた。
  • スキルやタスク管理、コミュニケーション能力が向上した。

Problem

  • タスクの偏りが生じた。
  • 情報共有が甘いときがあった。

Try

これらのProblemを解決するためのTryとして

  • タスクの全体図を可視化する。
  • タスクの優先度を明確にする。
  • 口頭でのコミュニケーションをログとして残す。
  • 会議の議事録を残す。

以上のような振り返りが出来ました。

最後に

新人が実際に小さなプロジェクトを経験し、その経験を実務に活かして欲しいという研修の狙いを強く感じました。
個人的な感想ですが、ただ作るだけでなく実際にプレゼンを行い、レビューをいただけたのは非常にありがたい経験でした。
また、工夫した点を評価されることは素直に嬉しいのだと再認識できました。
今後はこの経験を実務に活かして幅広く活躍していきたいと思います。

以上、弊社における新人研修の紹介とその感想でした。


神﨑 拓人

RubyKaigi 2017 に Gold Sponsor として協賛します&広島のおみやげの話


Source by RubyKaigi 2017

こんにちは! Aiming ソフトウェアエンジニアの神﨑です。

Aiming は来る9月18日(月)から9月20日(水)に行われる RubyKaigi 2017 に Gold Sponsor として協賛します。 Aiming では開発基盤として Ruby on Rails を多く採用しており、 Ruby コミュニティのさらなる発展に貢献したいと考えています。

昨年は国立京都国際会館で行われましたが(昨年の報告記事)、今年の会場は広島国際会議場とのことで、おそらく参加者のほとんどの方が広島へ遠征することになるのではないでしょうか。そうなるとやっぱり調べておきたいのは広島のお土産。おすすめの広島土産がないかを広島出身の友人に聞くと、定番ものから今まで知らなかったようなものまで紹介されたので、まとめてご紹介します!

続きを読む


カテゴリー: Ruby
vivid_muimui

サーバーサイド勉強会(2017年5月)


東京スタジオのエンジニアの小山です。

この記事では、5月中に行われたサーバーサイド勉強会の内容を紹介したいと思います。
サーバーサイド勉強会の紹介や4月分の内容は前回の記事を見てください。
https://developer.aiming-inc.com/study/server_side_study_201704/

5/11 LT

月初のLTです。

今回は全体的に真面目な勉強ネタという感じではなく、ゆったりとしたものが多かったです。(公開できるスライドが少なくてすみません><)

記号でRuby

社内である日突然出された以下の問題の解説でした。

Ruby (2.3.x あるいは 2.4.x) で以下の条件の下に Hello という文字列を標準出力に出力するプログラム、
あるいはそのようなプログラムを出力するプログラムを書きなさい。

アルファベット、数字、スペース、\u007f 以上のコードポイントの文字を利用してはならない
つまり↓の文字のみを使ってよい
解答時に、レイアウトの都合でプログラムの意味が変わらない程度の改行の挿入は許可

!"#$%&'()*+,-./:;<=>?@[]^_`{|}~

(回答の例はこちらです。)

解説されている間はなんとか理解できている気がするのですが、魔術を説明されているようでとても難しかったです><
解説のスライドは公開できませんでしたが、ぜひ皆さん挑戦してみてください。ちなみに僕は解けませんでした!

5/18 code smellを検出するreekのチェック項目を読む

reekというコードスメルを検出するgemのチェック項目を読む回でした。

Reek is a tool that examines Ruby classes, modules and methods and reports any code smells it finds.

https://github.com/troessner/reek/blob/master/docs/Code-Smells.md
このページにチェック項目一覧があるので、上から順番に眺めていきました。

どれもチェック項目として納得いくものばかりですが、実際運用することを想定したときに、

  • 全部デフォルトだと厳しい
  • ケースバイケースなのでどこに基準を設定するのか難しい
  • 養成ギプスとしては良さそう

というのが全体的な感想でした。
あまりプログラムを書くことに慣れていない・Rubyに慣れていないという場合には設定するとメリットが大きそうです。そうでない場合には、Reekの設定のメンテコストや指摘箇所の対応コストが発生し、メリットよりもデメリットのほうが大きくなりそうという印象です。
ただ、こういうコードスメルがある事自体はちゃんと認識しておく必要があるので、たまに思い出したときに初心に返る気持ちで見直したいなと思いました。

5/25 react-rails の入門ハンズオン

@yhirano55によるreact-railsの入門ハンズオンでした。
@yhirano55がこのハンズオンのために用意した資料を見ながら進めました。react-rails gemに特化した内容ではなく、Reactに触れてみよう、ReactをRailsで使ってみよう、という内容のチュートリアルでした。
資料がとても良くできていて、1時間という短い時間でしたがとりあえず動かすことができて基礎も理解できました。恐る恐るレビューしていたReactのコードも今はちょっと読めるようになりました!
資料は口頭での解説がなくても十分できるようになっていると思いますので、興味ある方はぜひやってみてください。

おわりに

5月はGWがあったので3回分だけでした。
今月はReactのハンズオンが個人的にとても良かったです。Reactに関する情報は色んな所で見聞きしてはいましたが、実際に触ったことがなく、なんとなく怖いという印象を持っていました。ですが、今回実際触ってみると全然怖くないなって思いました!
情報を見聞きして満足するだけでなく、実際触ってみることが大事だなと改めて痛感した回でした。


syoshino

AssetBundleGraphTool を触ってみました


エンジニアの吉野です。

先日アップデートされたばかりの AssetBundleGraphTool v1.3 をこれまた先日リリースされた Unity 2017.1 に入れてみました。

AssetBundleGraphTool の bitbucket ページ
日本語マニュアル

今回はゲームで使用する Asset がどの AssetBundle に入っているかのテーブルデータをカスタムノードで作成したのでかいつまんで紹介しようと思います。

概要

ゲームで Asset を読むときに、開発中はローカルから、実機では AssetBundle を使いたいということが良くあります。
(Unite 2017 で紹介されていた Addressable Assets が入ればいらなくなるはずなので、それまでのつなぎで…)
これを満たすための仕様としては、おおむね以下の図のようになると思います。

asset load flow

この図の AssetBundleTable で使う AssetPath → AssetName 変換用のデータをカスタムノードで作ります。

完成したGraph図はこのようになります。

graph sample

カスタムノードの作り方は日本語のマニュアルの「カスタムノードを追加する」を見てください。
以下、作成したノードの要点を解説していこうと思います。

入力/出力するノードのタイプを指定する

今回は、「AssetBundle 名と AssetPath が設定されたノード」(Grouping)と 「AssetBundle をビルドするノード」(BundleBuilder)の間に入れたいので、以下のようにします。


    public override Model.NodeOutputSemantics NodeInputType
    {
        get
        {
            return Model.NodeOutputSemantics.AssetBundleConfigurations;
        }
    }

    public override Model.NodeOutputSemantics NodeOutputType
    {
        get
        {
            return Model.NodeOutputSemantics.AssetBundleConfigurations;
        }
    }

インスペクター上から AssetBundleTable を指定できるようにする

Inputされた情報を書き込む AssetBundleTable を渡せるようにします。
指定はエディタ拡張でおなじみの OnInspectorGUI(…) 部分に追加します。


public override void OnInspectorGUI(
    NodeGUI node,
    AssetReferenceStreamManager streamManager,
    NodeGUIEditor editor,
    Action onValueChanged)
{
...
    tableAsset = EditorGUILayout.ObjectField("AssetBundleTable Object", tableAsset, typeof(AssetBundleTable), false) as AssetBundleTable;
...
}

ビルド時に AssetBundleTable を更新する

Graph をビルドすると、カスタムノードの Build(…) が呼ばれます。この時に受け取った情報をTableに設定します。


public override void Build(
    BuildTarget target,
    Model.NodeData node,
    IEnumerable<PerformGraph.AssetGroups> incoming,
    IEnumerable<Model.ConnectionData> connectionsToOutput,
    PerformGraph.Output Output,
    Action<Model.NodeData, string, float> progressFunc)
{
...
    tableAsset.Clear();
    foreach (var ag in incoming)
     {
         foreach (var assetGroup in ag.assetGroups)
         {
             foreach (var inputAsset in assetGroup.Value)
             {
                 tableAsset.Add(new AssetBundleLoadPath(assetGroup.Key, inputAsset));
             }
         }
     }
     EditorUtility.SetDirty(tableAsset);
     AssetDatabase.SaveAssets();
...
}

AssetBundleTable 自身も AssetBundle にする

実機で使うので、AssetBundleTable も忘れずに AssetBundle にします。
幸いこの後に AssetBundle をビルドするノードがあるので、Output に追加して流します。


public override void Build(
    BuildTarget target,
    Model.NodeData node,
    IEnumerable<PerformGraph.AssetGroups> incoming,
    IEnumerable<Model.ConnectionData> connectionsToOutput,
    PerformGraph.Output Output,
    Action<Model.NodeData, string, float> progressFunc)
{
...
    EditorUtility.SetDirty(tableAsset);
    AssetDatabase.SaveAssets();

    if (Output != null)
    {
        var dst = (connectionsToOutput == null || !connectionsToOutput.Any()) ?
            null : connectionsToOutput.First();

        // 上流のノードから流れてきたものをそのまま渡します。
        foreach (var ag in incoming)
        {
            Output(dst, ag.assetGroups);
        }

        // AssetBundleTableを追加して渡します。
        var additionalOutput = new Dictionary<string, List<AssetReference>>();
        additionalOutput.Add(settings.tableAssetBundleName,
            new List<AssetReference> { 
                AssetReference.CreateReference(AssetDatabase.GetAssetPath(tableAsset), typeof(AssetBundleTableListData))
            }
        );
        Output(dst, additionalOutput);
    }
}

これで、作成した Graph がビルドされるたびに AssetBundleTable が更新されて、AssetBundle にまでなってくれます。
日本語のわかりやすいマニュアルがあるおかげで、すんなりと実装できてしまいました。

使ってみた感想

ノードの拡張機能があるおかげで Asset を読んで加工してなにかする、という機能をグラフィカルかつ低コストで作成できる素晴らしいツールだと思います。
カスタムノード以外にもいろいろな機能があるのでぜひマニュアルを見てみてください。
いろいろ応用できそうなので今後も活用していこうと思います!


水島 克

スマホゲームのUI仕様書


ゲームデザイナの水島です。

Aimingでは定期的に社内勉強会をやってます。

自分は若いプランナー向けにゲーム開発の基礎的な話をすることが多いのですが、新しいメンバーが増えてくると、何年か置いて同じ話を繰り返しすることもあります。手抜きといえばそのとおりなんですが、自分の中でも定期的に見直す良い機会だと思ってまして、今回もそんなお話です。

5年前に行った勉強会のスライド「企画が考えるスマホUIデザイン」は、現在27万viewと多くの方にみていただきました。

でもいま見返すと古いと感じるところも結構あります。当時はブラウザのソーシャルゲームからの移行期で、スマホネイティブのゲームも今ほど多く無かったため、いろいろ手探りの状態だったな~と思い出します。弊社の話でいうと、制作のパイプラインなんかは、その後だいぶ改善されたと感じてます。

そこで今回はもうちょっとテーマを絞って、UI仕様書について話してみることにしました。

スライドの中でも触れてますが、プランナーが書く仕様書の位置づけはチームによってバラバラ。しかも人によってはこだわりを持つ部分でもあるため、時に議論のたねになります。例えば、エクセル方眼紙のメソッドは宗教論争みたいになることもあって、傍から見てると面白い。

今回はもうちょっとマイルドに、「チーム毎に仕様書の項目の優先度をつけて書いてみてはどうか」という提案を盛り込んでみました。これが正解!というつもりもなく、選択肢の一つになるとよいかなと思います。

スマホゲームのUI仕様書

ちなみに5年前のスライドはこちらです。

企画が考えるスマホUIデザイン


Unity 2017.1.0 BetaでInspectorの入力ができなくなる問題を回避する方法


こんにちは。大阪スタジオ エンジニアの西村です。

現在開発中のプロジェクトではUnity 2017.1 Beta版を使用しています。

Unity 2017.1.0b3~Unity 2017.1.0f1のWindows版でInspectorの入力ができなくなるという不具合が発生していて作業に支障が出ていました。

人によっては不具合が発生しておらず、調査の結果Microsoft IMEを使っている場合のみ発生する事がわかりました。

回避方法

Unity使用時、キーボード設定をMicrosoft IME以外に設定する。

Google 日本語入力やUSキーボードを使用している人は不具合が発生していませんでした。

うっかり入力できなくなった時の対処方法

Componentメニューを開いて閉じるだけでInspectorに入力できる状態に戻ります。

不具合はUnityに報告済みで、いずれ修正されるでしょう。


吉田 正広

ルームの機能をモジュール化して、もうこれ以上コピペしなくて済むようにした話


はじめまして!

東京スタジオでエンジニアをしている、吉田と申します。

リリース後も、アップデートを繰り返していくオンラインゲーム。
安定したサービスを提供しつつ、常に新しい遊びを創造していくというのは、なかなか難儀なものです。

アップデートで機能追加をする度に、プログラマを悩ませるのが、

  • 安全のために、動作実績のある既存のプログラムはできるだけ変更したくない。
  • でも、コードの保守性や可読性のために、共通機能を関数化/クラス化するなどのリファクタもしたい。

こんなジレンマ。エンジニアのあなたも、身に覚えがありませんか?
それとも、「動いているコードは触ってはいけない」というルールを頑なに守って、リファクタを避けてはいないでしょうか?

でもそれだと、既存の仕組みに縛られて、新しい機能の実装が難しくなるし、アップデートと共に少しずつ大きくなって、今やなんの機能なのかわからないクラスなどがあると、バグの対応にも一苦労ですよね。

その上担当者も変わったりして、もう誰も中身を把握していない・・・、なんて状態になる前に、上手にリファクタしつつ、安全性も保ちながら、コードを保守していきたいものです。

先日4周年を迎えた「幻塔戦記グリフォン」(以下グリフォン)では、C++で書かれた、リアルタイム通信機能を担うサーバーがあります。
やはり4年もたつと、古いソースも多々あり、上記のような問題に常に直面しています。
今回は、新しい機能を実装するにあたって、私が行った取り組みについて紹介します。

現状のソース

グリフォンでは、いろんなタイプのクエストやバトルがあり、それぞれがクラスで表現されています。

CRoomBase          -共通で使う基本的な処理
  +- CQuestRoom         -シナリオなどのクエスト
  +- CPvPRoom           -定期的に開催されるPVP対戦
  +- CMockBattleRoom    -いつでもバトルが試せる、模擬戦
  +- CBattleRoyalRoom   -バトルロイヤル
  +- CColosseumRoom     -コロシアム

+- は継承を意味します。

CRoomBaseには、共通機能(主にゲーム内のオブジェクトの管理)が入っています。

それぞれの子クラスには、大まかに

  1. 入室までの処理
  2. ゲーム開始までの処理
  3. ゲームのルール処理
  4. ゲーム戦績の保存
  5. ゲーム終了後の処理

こんな機能が実装されています。

現状のソースコードを眺めてみると、こんな状態になっていました。

  • CPvPRoomCMockBattleRoomは、入室してゲーム開始するまでの流れが違うが、ゲームルールは一緒
  • CBattleRoyalRoomは、CMockBattleRoomをコピペし、一部機能を修正して作ったっぽい
  • その後、CMockBattleRoomにも独自の機能が追加されてるっぽい
  • その他、同じ様でちょっと違う処理が随所にみられる

だんだんつらくなってきた・・・もう既存のソースは見たくない・・ってなりました。
エンジニアの方なら、こんな気持ちをわかってくれるはず!!

そして今回

新しいゲームを提供するため、新たにルームクラスを作ることになりました。(仮にCNewBattleRoomとします)
その要件は、

  • 入室&ゲームスタートまでの流れはCBattleRoyalRoomとだいたい一緒
  • ゲームルール、戦績保存は、CQuestRoomとだいたい一緒
  • 加えて、今回初めて実装する機能

さてどうしたものか・・・
まず簡単に思いつく方法は、

  1. CBattleRoyalRoomをコピーして、CNewBattleRoomを作る。
  2. できたCNewBattleRoomのうち、いるものだけ残していらない物は削除する(もしくは使わないなら放置)
  3. CQuestRoomの一部機能をコピーしてCNewBattleRoomに入れる
  4. あと、足りない機能を入れる

こんな感じでしょうか。またコピペが増える・・・・
このアップデートをもって、サービス終了! ならこれでいいのですが、グリフォンはまだまだ続くのです・・!!

じゃあ、共通の機能を1つにまとめる? でも、共通化できそうな機能も、それぞれのルームで微妙に違ってたりするし(どうしてこうなったのか、もう分からないし)
これもつらいのです。

—-そして悩んだ結果、
よし、今回だけは、コピペを許そう。ただし、今後はコピペしないで済むようにする。

と決めました。

そのために、各機能をモジュール化して、そのモジュールたちを付け替える事で、ルームを表現できるようにします。

新しいクラス構成は

CRoomBase               -共通で使う基本的な処理
  +- CModularRoomBase        -各モジュールを乗せるためのベースクラス
      +- CNewBattleModule    -新しいルーム特有の機能を実装したモジュール
      +- CPvPCommonModule    -対戦共通モジュール
      +- CCommonModule       -共通モジュール

今回だけは、既存ソースからコピペして、各モジュールを作ります。

そして、モジュールを組み合わせたルームを生成するためのテンプレートクラスを

template <typename... Modules>
class CModularRoom : public virtual CModularRoomBase, public Modules...
{
...
};

こんな風に定義します。

例えば、Common,PvPCommon,NewBattleの3つの機能を実装した CNewBattleRoom を作成するには、

typedef CModularRoom<
    CCommonModule,           //テンプレート引数に、入れたいモジュールを羅列する
    CPvPCommonModule,
    CNewBattleModule>
        CNewBattleRoom;

こんな感じです。

こうしておけば、例えば今後、新しいルームクラス CHogeBattleRoom を作るときには、CHogeBattleModuleを作り、CNewBattleModuleと差し替えて、

typedef CModularRoom<
    CCommonModule,
    CPvPCommonModule,
    CHogeBattleModule>       //←ここだけ差し替える
        CHogeBattleRoom;

とすればいい訳ですね。

もし、CHogeBattleRoomを作るなかで、「CNewBattleRoomのこの部分は共通化したい」となった場合は、新しい CFugaCommonModule を作って、機能を分離すれば良いのです。

typedef CModularRoom<
    CCommonModule,
    CPvPCommonModule,
    CFugaCommonModule,     //←CNewBattleModuleから一部機能を分離
    CNewBattleModule>
        CNewBattleRoom;

typedef CModularRoom<
    CCommonModule,
    CPvPCommonModule,
    CFugaCommonModule,     //←分離して作ったモジュールをこっちにも入れる
    CHogeBattleModule>
        CHogeBattleRoom;

こうなります。

ところで、class CModularRoom がいろんなモジュールを多重継承してるけど、ひし型継承問題が起こるんじゃ?と思いましたか?

そんな時のために、C++には仮想継承という機能があります。

各モジュールに

class CHogeModule : public virtual CModularRoomBase
{
};

こんな感じで virtual 指定で継承すれば、ひし形問題は起こらずに済むんですね。

終わりに

今回の記事では、アップデートを繰り返していると必ず直面する、安全性 vs 保守性 のジレンマに対する弊社での取り組みについて紹介させて頂きました。
予測不能?なプランナーさんの考える企画を、リスクを回避しつつ、最大限の効果が得られるように、どうやって実現するか? エンジニアの腕のみせどころです。
Happy Programming!