いろいろ見せますlord of knightsのクライアント開発事例紹介
DESCRIPTION
パソナテックエンジニアカフェで話すスライドです。 http://atnd.org/events/26591 Unityで作ったオンラインゲームの開発事例とC#を使った通信設計周りの話です。TRANSCRIPT
いろいろ見せます❤
Lord of Knights のクライアント開発事例紹介
株式会社 Aimingリードソフトウェアエンジニア
細田幸治2012/04/10
こんばんは
ゲーム開発超楽しいで
す。
そのなかでも
オンラインゲーム開発
めっちゃ楽しい❤
私は
細田幸治といいます。
http://www.facebook.com/kouji.hosoda Lord of Knights のクライアント開発のチーフをしています。 以後お見知りおきを。
というわけで
Lord of Knights開発事例紹介
話すこと
● ゲーム紹介 ● 開発あるあると改善の話 ● Unity+HTML で作るハイブリッドアプリ
● C#を活用した非同期通信アプリ
時間があれば
● AppleStoreの審査あれこれ
この発表のターゲット
● ゲーム開発ってどうやってるのか興味がある人
● ある程度 Unity & C# を触ってる人
● これからオンラインゲーム作りたい人
はじめに
ゲーム紹介
どんなゲーム?
カードを強化して戦うストラテジー RPG
● メインプレイは内政、カード強化、バトルのサイクル
● 多人数で1つのマップを共有する戦略ゲーム
○同盟を組んで協力プレイ
○他の同盟と競争して目標となる拠点を奪い合
う
どんなゲーム?
おかげさまでApp Storeの
→トップ25
→トップ無料
で5位になりました ※2012/04/07現在
開発あるあると改善の話
まず
開発の前提
大事なことは
● チームみんなで楽しく開発すること
● そのための工夫や改善をひたすら頑張る
○言いだしっぺが主導して頑張る
● 何があっても楽しく、あわてない
具体的事例紹介
開発規模
● クライアント開発 3-8人
● サーバー開発約 5人
● 企画 3人
● デザイン 3人
の約 20人でリリースまで 8ヶ月半
現在はリリースされたので運営とマーケティングも加わりもっと増えてる
問題1
● 企画とエンジニアのすれ違いが多くて仲が悪い
● 部署ごとに部屋を区切られていてコミュニケー
ションが取りづらい
あるある
これは最初から対策
チームの席は一緒
● 企画、エンジニア、デザイン、運営など必要なメンバー全員で1チーム
● メンバーの席は近くする
すごい
リーダー
チームの席は一緒
● すごいリーダー(総責任者、仕様判断、運営判断、なんでも判断)が中心
チームの席は一緒
● 企画リーダーとエンジニアリーダーがその近く
すごい
リーダー エンジニ
ア
リーダー
企画リー
ダー
チームの席は一緒
● UIデザイナーが企画リーダーの近く
すごい
リーダー
UIデザ
イナー
エンジニ
ア
リーダー
企画リー
ダー
チームの席は一緒
● テクニカルアーティストはUIデザイナーとエンジニアの近く
すごい
リーダー
UIデザ
イナー
エンジニ
ア
リーダー
企画リー
ダー
TA
チームの席は一緒
● 運営が企画とリーダーの近く
すごい
リーダー
運営
UIデザ
イナー
エンジニ
ア
リーダー
企画リー
ダー
TA
すごい
リーダー
運営
UIデザ
イナー
エンジニ
ア
リーダー
企画リー
ダー
チームの席は一緒
● エンジニアや企画のメンバーは各リーダーの近く
エンジ
ニア
エンジ
ニア
企画
企画
TA
すごい
リーダー
運営
UIデザ
イナー
● 新人は各リーダーの近く
エンジニ
ア
リーダー
企画リー
ダー
チームの席は一緒
エンジ
ニア
エンジ
ニア
企画
企画
TA
新人
新人
チームの席は一緒
結果 ● 必要な人にすぐ判断を仰げる
● 関連する会話が自然と耳に入る
● 新人が放置されにくい
結果
次
問題2
● 他のメンバーが何をやっているか分からない
● 問題があったときに誰に相談したらいいか分か
らない
?
あるある
ありました
朝会
朝会
● チーム全員で朝一で集まって立ったまま10-15分で
● 当日やること、分かってる懸念点を報告
● 難しい話はしない
○長くなるなら後で個別に話し合う
朝会
結果
● 全員の動きが把握できた
● 問題はチームで共有
● 短時間に出来れば特にデメリットは無い
結果
次
問題3
● 朝会の時に昨日やったことを忘れている
● 問題報告が遅れる
● 残業が多い
あるある
ありました
夕会
夕会
● チーム全員で終業時間前に集まって立ったまま10-15分で
● 忘れないうちに報告
○当日達成できたこと
○出た問題点
●残業の必要性を報告
○その日のうちにやらなくていいと判断したら帰る
夕会
結果 ● 夕会で報告が済むので次の日から朝会が短く
なった ● 問題共有の漏れが減り、共有も早くなった
● 残業が減った!
結果
次
問題4
リモート会社との仕事をしている時 ● チャットやメールだけだとお互い仕事の進みが
見えず足並みがそろわない ● 問題発見が遅れる
??
ある(ry
週例ビデオチャット会議
● お互い顔を見ながら30分以内で簡潔に
● 進捗報告と問題共有、改善共有
● 雑談も交えつつ
週例ビデオチャット会議
結果 ● 合意が作りやすい
○すれ違いが減る
● 見えていなかった問題がぽろっとでてくる
● 仲良くなれる
結果
次
問題5
● どの実装を優先すべきか分からない
● 実装中に仕様抜け(必要なのに決まってない仕
様があること)がぽろぽろでる ?
ある(ry
ユーザー体験をリスト化
ユーザー体験をリスト化
● ユーザーの体験(ストーリー)ベースで出来ることをリストアップ
● 上記をマイルストーンごとにまとめ、いつどんな
体験が出来るかが一覧できる ● すごいリーダーが優先順位をつけてどれが大事
か決定する
ユーザー体験をリスト化
結果 ● 次にやることが明確になった
● ストーリーを書く段階で仕様抜けにあるていど
気づける ● これをマスターストーリーリストって言うらしい
結果
マスターストーリーリスト
こんなの
(ユーザーが)何をどうできるというように具体的に書く
マスターストーリーリスト
こんなの
フローを工夫しないと管理が大変
次
問題6
● スケジュール通りに終わらない
● デスマーチになる
ある(ry
タスクの増加・消化を可視化
タスクの増加・消化を可視化
● マイルストーン終了までに必要な総タスク数をカウント
● 毎週タスク数をカウントしてグラフ化
○総タスクの増減
○消化タスク数
○週当たりの平均値
● 総タスクが増えたら、その理由を記録
タスクの増加・消化を可視化
結果● 遅れはじめたらすぐ分かるようになった
● いつごろ終わるか予測が立つようになった
● 何で遅れたか把握でき、不安が減った
● リリースバーンダウンチャートって言うらしい
結果
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート)
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート)
スケジュールが延びた実例
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート) タスク25個からスタート
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート) 線形的に増えて
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート)
最終的に約70個に
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート)
約3倍のずれヒャッハー!!
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート)
でも週の消化数は平均して7出てる
リリースバーンダウンチャートこんなの(OBTリリースまでの実際のチャート)
平均速度からリリースを予測可能
ここまでのまとめ
結果
アジャイル開発に
なりました
現在の問題
いまはリリース直後で作業の割り込みが多く、優先度がころころ変わってる↓中長期のスケジュールが立っていない↓どうしたらいいか試行錯誤中
大事なことは?
● リスクの早期発見と改善が基本セット
● チームみんなで作るという意識(自発的である)
● 何があっても楽しく、あわてない
● 何でも言えるチームの空気
上記が実現できれば細かい手法は問わない
開発プロセスの話はここ
まで
続いて技術の話
Unity! Unity!
Unity + HTMLで作る
ハイブリッドアプリ
Unity×HTMLな理由
● Unity で UI 作るの大変!
● 内政、マップ、レポート、メール、ショップ、合成、
カード・・・・・・など 40画面以上! ● リスト系など動きが少ない画面はHTMLの方が
作りやすい!
HTMLを使うメリット
ぱっと見区別できないぐらい自然
HTML画面Unity画面
HTMLを使うメリットその2
リリース後のアップデートがしやすい● 審査なしでアップデート可能
○ キャンペーンページなどの自由が利きやすい
HTML画面
HTMLを使うメリットその3
自由文字入力ができる● iPhone 上でフォントに使えるテクスチャサイズ
に制限がある(EZ GUI)○ 1つのフォントごとに 2048*2048 ピクセルのテクスチャに
収める必要がある(iPhone4以降) ● HTML だと上記のような制限がない
○ チャットなど自由入力出来る画面は HTML で作成
HTMLを使うデメリット
● ローディングが長い
● 反応が遅い
○ どうしてもユーザー体験が落ちる
● メモリーを喰う
○ ゲーム内メールなどのリストを追加読み込みし続けると
突然落ちたりする
● エディターで確認できないところがある
○ 後で説明する Unity と HTML との連携部分
HTMLとUnityの連携仕様
● 連携とは
○ HTML 側から Unity の関数を呼び出す仕組みの事
● なにに使うか?
○ クエストの達成判定
○ サーバーと Unity 内モデルのデータ同期
○ Unity の画面遷移やUIの操作
HTML×Unity 実装
● 実装方法
○ Native Plugin として実装
○ Objective-C の UIWebView を利用
UIWindow *window =[[UIApplication sharedApplication] keyWindow]; // 基本クラスのインスタンス作るだけでOK
UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectMake(0,0,width,height)];
[window addSubview:webView];
HTML×Unity 実装
shouldStartLoadWithRequest を使ってクエリスト
リングをパース クエリストリングとは
URL の後ろにつく ?aho=foo&hoge=bar みたいなやつ UIWebViewNavigationType が以下の場合に処理
UIWebViewNavigationTypeFormSubmittedUIWebViewNavigationTypeLinkClickedUIWebViewNavigationTypeOther
HTML×Unity 実装
shouldStartLoadWithRequest を使ってクエリスト
リングをパース パース処理部分 NSString *query = [[request URL] query];if(query == nil) return YES;NSArray *parsedStrings = [query componentsSeparatedByString:@"&"]; for (NSString *q in parsedStrings){
char* key = [[[q componentsSeparatedByString:@"="]objectAtIndex:0]
}
HTML×Unity 実装
UnitySendMessage でパースしたデータを送信
Objective-C側でメッセージ送信
Unity側でメッセージ受信
if(strcmp(key,"change_scene") == 0){
UnitySendMessage(gameObjectName, "ChangeScene", value);}
void ChangeScene(string targetScneneName){
Appllication.LoadLevel(targetScneneName);}
HTML×Unity 実装
● フォルダ構成
○ Plugins/iOS 以下に Objective-C のコードを配置
○ ビルド時に Unity が自動的に Xcode のプロジェクトにコ
ピーしてくれる
HTML×Unity 実装
● ブラウザが操作不能になる問題が出た
○ Unity 側が自動生成する AppCotroller.mm の描画フラ
グを変更(@Unity3.4) ○ #define USE_DISPLAY_LINK_IF_AVAILABLE 0
C# を活用した
非同期通信アプリ
非同期通信って何?
サーバーと通信する時に結果を待っている間フリーズしてプログラムが止まっているのが同期通信。サーバーと通信する時に、結果を待たずにプログラムは続行し、結果が返ってきたら通信処理の続きが実行されるようにするのが非同期通信。 ゲームなどではフリーズを防ぐために通信処理は非同期通信で実装する必要がある。
非同期通信って何?
ようするに
めんどくさい
非同期通信アプリの設計指針
● 通信の実装を気にしたくない
● 処理を直感的に書きたい
● エラーもあまり気にしたくない
● サーバー実装に依存したくない
● 簡単に View に反映させたい
なぜそうするか
1つ1つ解説します
通信の実装を気にしたくない
よくあること ● 仕様が変わる
● 仕様変わったら通信実装も色々変わる
○ APIのインターフェイスの修正
○ データのシリアライズ
○ バリデーション
良くあること
通信の実装を気にしたくない
結果 ● 表示部分の実装、確認がなかなかできない
● バグりやすい
↓仕様変更、追加コストが高い ってなってしまう。
結果
通信の実装を気にしたくない
そこで
通信の実装を気にしたくない
通信実装コードの自動生成
通信の実装を気にしたくない
通信実装コードの自動生成● https://github.com/ppcuni/rpcoder
※ 動かすには LitJSON の微修正必要なので参考程度に ● 定義ファイルから実装コードを自動生成する
ツール ● アプリケーション層で通信実装を気にする必要
はないようになってる
通信の実装を気にしたくない
定義ファイル# ユーザ登録しログインする
RPCoder.function "registerUser" do |f| f.path = "/startup/regist.php" # エンドポイント URL
f.method = "POST" # 通信メソッド
f.add_param :invitation_code, "String",{:require => false} #招待コード
f.add_param :user_name, "String" # 登録ユーザ名
f.add_param :card_number, "int" # 初期カード番号
f.add_param :direction_id, "int" # 方角ID
f.add_return_type :login_user_info, "LoginUserInfo" # ユーザーの全情報
f.description = "ユーザ登録する"
end
通信の実装を気にしたくない
定義ファイル# ユーザ登録しログインする
RPCoder.function "registerUser" do |f| f.path = "/startup/regist.php" # エンドポイント URL
f.method = "POST" # 通信メソッド
f.add_param :invitation_code, "String",{:require => false} #招待コード
f.add_param :user_name, "String" # 登録ユーザ名
f.add_param :card_number, "int" # 初期カード番号
f.add_param :direction_id, "int" # 方角ID
f.add_return_type :login_user_info, "LoginUserInfo" # ユーザーの全情報
f.description = "ユーザ登録する"
end
APIを定義
通信の実装を気にしたくない
定義ファイル# ユーザ登録しログインする
RPCoder.function "registerUser" do |f| f.path = "/startup/regist.php" # エンドポイント URL
f.method = "POST" # 通信メソッド
f.add_param :invitation_code, "String",{:require => false} #招待コード
f.add_param :user_name, "String" # 登録ユーザ名
f.add_param :card_number, "int" # 初期カード番号
f.add_param :direction_id, "int" # 方角ID
f.add_return_type :login_user_info, "LoginUserInfo" # ユーザーの全情報
f.description = "ユーザ登録する"
end
エンドポイントURL
通信の実装を気にしたくない
定義ファイル# ユーザ登録しログインする
RPCoder.function "registerUser" do |f| f.path = "/startup/regist.php" # エンドポイント URL
f.method = "POST" # 通信メソッド
f.add_param :invitation_code, "String",{:require => false} #招待コード
f.add_param :user_name, "String" # 登録ユーザ名
f.add_param :card_number, "int" # 初期カード番号
f.add_param :direction_id, "int" # 方角ID
f.add_return_type :login_user_info, "LoginUserInfo" # ユーザーの全情報
f.description = "ユーザ登録する"
end
Method
通信の実装を気にしたくない
定義ファイル# ユーザ登録しログインする
RPCoder.function "registerUser" do |f| f.path = "/startup/regist.php" # エンドポイント URL
f.method = "POST" # 通信メソッド
f.add_param :invitation_code, "String",{:require => false} #招待コード
f.add_param :user_name, "String" # 登録ユーザ名
f.add_param :card_number, "int" # 初期カード番号
f.add_param :direction_id, "int" # 方角ID
f.add_return_type :login_user_info, "LoginUserInfo" # ユーザーの全情報
f.description = "ユーザ登録する"
end
引数いろいろ
通信の実装を気にしたくない
定義ファイル# ユーザ登録しログインする
RPCoder.function "registerUser" do |f| f.path = "/startup/regist.php" # エンドポイント URL
f.method = "POST" # 通信メソッド
f.add_param :invitation_code, "String",{:require => false} #招待コード
f.add_param :user_name, "String" # 登録ユーザ名
f.add_param :card_number, "int" # 初期カード番号
f.add_param :direction_id, "int" # 方角ID
f.add_return_type :login_user_info, "LoginUserInfo" # ユーザーの全情報
f.description = "ユーザ登録する"
end
戻り値
通信の実装を気にしたくない
自動生成されるもの ● API のインターフェイスクラス
● API の実装クラス
● API の Mock クラス
● 型の実装クラス
● 型のシリアライザ、デシリアライザ
C#
通信の実装を気にしたくない
色々めんどくさいところ作ってくれるバグがあってもテンプレート直せばOK
次
処理を直感的に書きたい
よくあること ● リクエストとレスポンスの処理が分離している
● 非同期処理を連続して行うときにカオスになる
良くあること
処理を直感的に書きたい
結果 ● コードの見通しが悪い
● 通信時に何処で何が起きてるか分からない
● バグりやすい
↓仕様変更、追加コストが高い ってなってしまう。
結果
処理を直感的に書きたい
そこで
処理を直感的に書きたい
メソッドチェインで書けるように
処理を直感的に書きたい
記述例
var task = IncrementAsync(1)// タスク完了時に呼ばれる完了処理(2を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result))// ↑のタスク成功時に別のタスクを繋げる
.ContinueWithTask<int>(IncrementAsync)// ↑のタスク完了時に呼ばれる完了処理(3を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result));
処理を直感的に書きたい
記述例
var task = IncrementAsync(1)// タスク完了時に呼ばれる完了処理(2を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result))// ↑のタスク成功時に別のタスクを繋げる
.ContinueWithTask<int>(IncrementAsync)// ↑のタスク完了時に呼ばれる完了処理(3を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result));
非同期呼び出し
処理を直感的に書きたい
記述例
var task = IncrementAsync(1)// タスク完了時に呼ばれる完了処理(2を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result))// ↑のタスク成功時に別のタスクを繋げる
.ContinueWithTask<int>(IncrementAsync)// ↑のタスク完了時に呼ばれる完了処理(3を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result));
非同期結果受け取り
処理を直感的に書きたい
記述例
var task = IncrementAsync(1)// タスク完了時に呼ばれる完了処理(2を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result))// ↑のタスク成功時に別のタスクを繋げる
.ContinueWithTask<int>(IncrementAsync)// ↑のタスク完了時に呼ばれる完了処理(3を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result));
続けて行う非同期処理
処理を直感的に書きたい
記述例
var task = IncrementAsync(1)// タスク完了時に呼ばれる完了処理(2を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result))// ↑のタスク成功時に別のタスクを繋げる
.ContinueWithTask<int>(IncrementAsync)// ↑のタスク完了時に呼ばれる完了処理(3を出力)
.OnComplete(t => UnityEngine.Debug.Log(t.Result));
非同期結果受け取り
処理を直感的に書きたい
すっきり
処理を直感的に書きたい
実装的には 非同期処理用のクラスを作成● 内部処理は yield を利用したコルーチン
● コルーチンの完了をメソッドチェインで書ける
● 次のコルーチンをメソッドチェインで繋げる
次
エラーもあまり気にしたくない
よくある ● API ごとにエラー処理が分散している
● 連続してエラーが起きたときに最後のエラーし
か分からない
良くあること
エラーもあまり気にしたくない
結果 ● エラー実装がめんどくさい
● バグ調べにくい
↓仕様変更、追加コストが高い ってなってしまう。
結果
エラーもあまり気にしたくない
そこで
エラーもあまり気にしたくない
● すべての非同期処理を共通化
○ 根っこ部分で try/catch してエラーハンドリング
○ エラーダイアログを出したりする処理も共通化
● 個別エラー処理も可能に
○ エラーが複数発生したらキューにして全エラーを保持
○ エラーはタスクをまたいで次のタスクに伝播、後でチェッ
クできる
エラーもあまり気にしたくない
View はだいたい正常系だけ書けば OK
次
サーバー実装に依存したくない
よくあること ● サーバーの実装が完了しないと画面確認できな
い ● 通信エラーが起きたときの再現が取れない
良くあること
結果 ● 実装のFixが延び延びになる
● バグ調べにくい
↓仕様変更、追加コストが高い ってなってしまう。
結果
サーバー実装に依存したくない
そこで
サーバー実装に依存したくない
Mock
サーバー実装に依存したくない
サーバー実装に依存したくない
Mock とは
● 擬似サーバー
● クライアントだけで完結
● ソースの変更無しで
サーバーと切り替えられる
クライアント
Mock
Server
サーバー実装に依存したくない
Mock を使うと
● サーバー実装スケジュールとの依存が少ない
● 異常系の確認も手軽にできる
サーバー実装に依存したくない
Mock 実装の例
しばらくサーバーいらず
サーバー実装に依存したくない
次
簡単に View に反映させたい
よくあること ● View で Polling してデータをチェック→反映
○ GameObject の Update の中でチェックする感じ
○ Unity3.5 のプッシュ通知の初期化周りとかがそんな感じ
良くあること
結果 ● チェック頻度が高いと負荷が高い
● チェック頻度が低いと画面反映が遅れる
● チェックコード自体書きたくない
↓余計な負荷、ユーザー・エンジニア体験の悪化 ってなってしまう。
結果
簡単に View に反映させたい
簡単に View に反映させたい
そこで
簡単に View に反映させたい
イベントドリブンで View を更新
簡単に View に反映させたい実装例
public class CityModel{
// 資源の増減通知
public event Action<ResourceStatus> Updated;} public class CityView : Aiming.TSS.Infrastructure.EventDrivenBehavior{
void Start(){
// 資源の増減通知を購読、解除設定
_cityModel.Updated += OnResourceUpdated;base.AddDisposable(_cityModel, x => x.Updated -= OnResourceUpdated);
}}
簡単に View に反映させたい実装例
public class CityModel{
// 資源の増減通知
public event Action<ResourceStatus> Updated;} public class CityView : Aiming.TSS.Infrastructure.EventDrivenBehavior{
void Start(){
// 資源の増減通知を購読、解除設定
_cityModel.Updated += OnResourceUpdated;base.AddDisposable(_cityModel, x => x.Updated -= OnResourceUpdated);
}}
イベントを定義
簡単に View に反映させたい実装例
public class CityModel{
// 資源の増減通知
public event Action<ResourceStatus> Updated;} public class CityView : Aiming.TSS.Infrastructure.EventDrivenBehavior{
void Start(){
// 資源の増減通知を購読、解除設定
_cityModel.Updated += OnResourceUpdated;base.AddDisposable(_cityModel, x => x.Updated -= OnResourceUpdated);
}}
+= でイベント購読開始
簡単に View に反映させたい実装例
public class CityModel{
// 資源の増減通知
public event Action<ResourceStatus> Updated;} public class CityView : Aiming.TSS.Infrastructure.EventDrivenBehavior{
void Start(){
// 資源の増減通知を購読、解除設定
_cityModel.Updated += OnResourceUpdated;base.AddDisposable(_cityModel, x => x.Updated -= OnResourceUpdated);
}}
イベント購読解除を予約
簡単に View に反映させたいイベントを受け取った時の処理
public class CityView : Aiming.TSS.Infrastructure.EventDrivenBehavior{
void OnResourceUpdated(ResourceStatus resource){
// テキストフィールド更新
_currentManaText.Text = resource.CurrentMana.ToString();}
}
簡単に View に反映させたいイベントを受け取った時の処理
public class CityView : Aiming.TSS.Infrastructure.EventDrivenBehavior{
void OnResourceUpdated(ResourceStatus resource){
// テキストフィールド更新
_currentManaText.Text = resource.CurrentMana.ToString();}
}
表示処理だけ書けばOK
簡単に View に反映させたい
● View の作成時に Model の変更イベントを購読
● View の破棄、非表示時にイベント購読を解除
● 購読と解除は近くに記述できるようにする
簡単に View に反映させたい
すっきり
ちなみに通信実装は
通信実装で使ったもの
● 通信処理は Unity の WWW クラスを利用
● データフォーマットは JSON
● JSON のパースに LitJSON を改良して利用
○ http://sourceforge.jp/projects/sfnet_litjson/○ ライセンスがゆるい
○ ソースコードがフルオープン
まとめると
まとめ
● 自動生成いいね
● 直感的に書けるのいいね
● エラーは簡単に処理できるのいいね
● Mock いいね
● イベントいいね
以上技術の話でした
最後に
とにかく楽しむ
どんなトラブルも懸念事項も前向きに取り組めば楽しいクエストになります
ゲーム開発超楽しい❤
ご清聴ありがとうございました
あそびにきてね!
株式会社 Aiming はオフィス見学を
いつでも受け付けています。 興味がある方はお気軽にご連絡ください。
おまけ
AppleStoreの審査あれこれ
初めての iPhone アプリリリースだった ノウハウがなかったので試行錯誤
審査について
リリースまでにリジェクト3回されました リジェクト理由その1● キャッシュファイルの保存場所が悪くてアウト!
○永続化用と一時用があるので気をつける
○保存場所を直して解決
審査について
リジェクト理由その2● レビュアーが想定通りに行動しなくてアウト!
○審査専用アカウントかどうかで、審査用サーバーか本番
サーバーかをスイッチしていたが、レビュアーが専用アカウントを使ってくれなかった
○クライアントのバージョンでサーバーをスイッチするようにして解決
審査について
リジェクト理由その3● 審査中にメンテをしたらレビュアーがログインで
きなくなってアウト○In Reviewになったらメンテを予定していたとしてもリスケ
ジュールする
○次からワークフローに落とし込んで解決
審査について
どのくらいで通るの?● だいたい審査出してから約5営業日で審査開始
(In Review)、だいたいその数時間後に結果出る ● 場合によってはIn Reviewのまま1日過ぎることも
あるので油断しない
審査について
どういう判断基準?● 審査のたびに判断基準がまちまち
● 深く見られる時もあれば一瞬でOKでる時も
審査について
とにかく地雷が多いので● なるべく早く最初の審査をだす
● 早くたくさん地雷を踏む
● 審査提出時は2人以上でダブルチェック
おわり