beinteractive-lightningtalks-#02 マルチプレイ Flash ゲームのつくりかた 2008.09.30 Yoshihiro Shindo (BeInteractive!) マルチプレイ Flash ゲームってなに? マルチプレイ Flash ゲームってなに? ネットを介して同時多人数でプレイするゲーム 本日のサンプル アットゲームズ 対戦ゲーム「大富豪」 www.atgames.jp 大富豪概要 大富豪概要 • 大富豪 大富豪概要 • 大富豪 • 3人∼4人対戦 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 • ルール選択 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 • ルール選択 • 一戦勝負 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 • ルール選択 • 一戦勝負 • ポイント戦 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 • ルール選択 • 一戦勝負 • ポイント戦 • メダルのベット 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 • ルール選択 • 一戦勝負 • ポイント戦 • メダルのベット • アバター表示 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 • ルール選択 • 一戦勝負 • ポイント戦 • メダルのベット • アバター表示 • チャット 大富豪概要 • 大富豪 • 3人∼4人対戦 • ルーム作成 • ルール選択 • 一戦勝負 • ポイント戦 • メダルのベット • アバター表示 • チャット • フレンドリスト • ライバルリスト • エモーション • ウィスパー • 招待 • プロフィール • 成績 • ランキング 大富豪開発概要 大富豪開発概要 • Server 担当: gawgaw さん 大富豪開発概要 • Server 担当: gawgaw さん • Flash 担当: yossy (+デザイナーさん) 大富豪開発概要 • Server 担当: gawgaw さん • Flash 担当: yossy (+デザイナーさん) • 二ヶ月 (実装実質一ヶ月) 大富豪役割分担 Server Side Client (Flash) Side 大富豪役割分担 Server Side • ユーザー管理 Client (Flash) Side 大富豪役割分担 Server Side • ユーザー管理 • ロビー管理 Client (Flash) Side 大富豪役割分担 Server Side • ユーザー管理 • ロビー管理 • ルーム管理 Client (Flash) Side 大富豪役割分担 Server Side • ユーザー管理 • ロビー管理 • ルーム管理 • ゲーム進行 Client (Flash) Side 大富豪役割分担 Server Side • ユーザー管理 • ロビー管理 • ルーム管理 • ゲーム進行 • ゲームロジック Client (Flash) Side 大富豪役割分担 Server Side • ユーザー管理 • ロビー管理 • ルーム管理 • ゲーム進行 • ゲームロジック Client (Flash) Side • 表示 大富豪役割分担 Server Side • ユーザー管理 • ロビー管理 • ルーム管理 • ゲーム進行 • ゲームロジック Client (Flash) Side • 表示 • 演出 大富豪役割分担 Server Side • ユーザー管理 • ロビー管理 • ルーム管理 • ゲーム進行 • ゲームロジック Client (Flash) Side • 表示 • 演出 • 入力 大富豪役割分担 Server Side Client (Flash) Side ロジック ビュー 大富豪で使われているライブラリ Server Side Ruby on Rails dango Framework (Ruby) dango Framework (AS3; Socket) dango Integration ActionScript Thread Library 1.0 Client (Flash) Side 大富豪で使われているライブラリ dango http://dango-net.org/ ActionScript Thread Library 1.0 (そうめん) http://www.libspark.org/wiki/Thread 大富豪 Flash 概要 大富豪 Flash 概要 • 言語 ActionScript 3.0 大富豪 Flash 概要 • 言語 • 行数 ActionScript 3.0 約 15700 行 大富豪 Flash 概要 • 言語 • 行数 • クラス ActionScript 3.0 約 15700 行 171 個 大富豪 Flash 概要 • 言語 • 行数 • クラス • インターフェイス ActionScript 3.0 約 15700 行 171 個 43 個 大富豪 Flash 概要 • 言語 • 行数 • クラス • インターフェイス • 行数ランキング ActionScript 3.0 約 15700 行 171 個 43 個 1619行, 904行, 387行 大富豪 Flash 設計 大富豪 Flash 設計 DangoThread 大富豪 Flash 設計 SceneControlThread DangoThread 大富豪 Flash 設計 SceneControlThread DangoThread SceneThread 大富豪 Flash 設計 SceneControlThread DangoThread Model SceneThread 大富豪 Flash 設計 SceneControlThread DangoThread SceneThread Model View 大富豪 Flash 設計 SceneControlThread DangoThread SceneThread Model View Model ってなんだ Model ってなんだ • 大富豪内で扱うデータをクラス化したもの Model ってなんだ • 大富豪内で扱うデータをクラス化したもの • ユーザー, ルーム, カード, チャットログ Model ってなんだ • 大富豪内で扱うデータをクラス化したもの • ユーザー, ルーム, カード, チャットログ • データと、その操作メソッドを定義 Model の例 public class User { public var id:uint; public var name:String; public function isEquals(u:User):Boolean { return u != null && this.id == u.id; } } Model の例 public class UserList { private var _list:Array = []; public function addUser(user:User):void { _list.push(user); } public function contains(user:User):Boolean { for each (var u:User in _list) { if (u.isEquals(user)) { return true; } } return false; } } Model を用意するメリット Model を用意するメリット • 型が厳格になる Model を用意するメリット • 型が厳格になる • コード補完が効く Model を用意するメリット • 型が厳格になる • コード補完が効く • 操作が統一される Model を用意するメリット • 型が厳格になる • コード補完が効く • 操作が統一される • 細工がし易い Model のファクトリ public class User { public static function fromObject(obj:Object):User { var user:User = new User(); if ( id in obj) { user.id = uint(obj.id); } if ( name in obj) { user.name = String(obj.name); } return user; } ... View ってなんだ View ってなんだ • 表示に関する操作を行うためのクラス View ってなんだ • 表示に関する操作を行うためのクラス • DisplayObject を操作するためのクラス View ってなんだ • 表示に関する操作を行うためのクラス • DisplayObject を操作するためのクラス • サウンドを鳴らしたりもする View の例 public interface IChatView { function addChatLog(log:ChatLog):void; } View の例 public class ChatView implements IChatView { public function addChatLog(log:ChatLog):void { _seManager.play( chatlog ); _logField.appendText(log.text + \n ); } } View と Scene を分ける意味 View と Scene を分ける意味 • 構造がすっきりする View と Scene を分ける意味 • 構造がすっきりする • 依存性と影響範囲が狭くなる View と Scene を分ける意味 • 構造がすっきりする • 依存性と影響範囲が狭くなる • 変更に強くなる View と Scene を分ける意味 • 構造がすっきりする • 依存性と影響範囲が狭くなる • 変更に強くなる • 使い回しがきく Scene ってなんだ Scene ってなんだ • シーンのまとめ役となるクラス Scene ってなんだ • シーンのまとめ役となるクラス • ロビー画面, ゲーム画面,... Scene ってなんだ • シーンのまとめ役となるクラス • ロビー画面, ゲーム画面,... • サーバーとの通信 Scene ってなんだ • シーンのまとめ役となるクラス • ロビー画面, ゲーム画面,... • サーバーとの通信 • Model の生成, 操作 Scene ってなんだ • シーンのまとめ役となるクラス • ロビー画面, ゲーム画面,... • サーバーとの通信 • Model の生成, 操作 • View の生成, 操作, 入力処理 Scene におけるサーバーとの通信 Scene におけるサーバーとの通信 • dango を使う Scene におけるサーバーとの通信 • dango を使う • データが来たら Message オブジェクトに 変換してキューに溜める Scene におけるサーバーとの通信 • dango を使う • データが来たら Message オブジェクトに 変換してキューに溜める • キューの Message を逐次処理 Scene におけるサーバーとの通信 • dango を使う • データが来たら Message オブジェクトに 変換してキューに溜める • キューの Message を逐次処理 • データを投げるときは普通に投げる キューってなんだ キューってなんだ • オブジェクトを 溜めておける入れ物 Obj2 Obj1 キューってなんだ • オブジェクトを Obj3 Obj2 Obj1 溜めておける入れ物 • offer(obj) で入れる キューってなんだ • オブジェクトを Obj3 Obj2 Obj1 溜めておける入れ物 • offer(obj) で入れる キューってなんだ • オブジェクトを 溜めておける入れ物 Obj3 Obj2 Obj1 • offer(obj) で入れる • poll() で取り出す キューってなんだ • オブジェクトを 溜めておける入れ物 Obj3 Obj2 • offer(obj) で入れる • poll() で取り出す キューを介したデータの受信 public function messageHandler(e:DangoRecieveEvent):void { _queue.offer(new Message(e.type, e.recieve_data)); } キューを介した Scene の処理 override protected function run():void { next(run); if (_queue.checkPoll()) { return; } var message:Message = _queue.poll(); if (message.type == chatlog ) { var log:ChatLog = ChatLog.fromObject(message.params); _chatView.addChatLog(log); } } キューを介した Scene の処理 override protected function run():void { next(run); if (_queue.checkPoll()) { return; } var message:Message = _queue.poll(); if (message.type == chatlog ) { var log:ChatLog = ChatLog.fromObject(message.params); _chatView.addChatLog(log); } } イベント駆動からメッセージ駆動へ メッセージ駆動の疑問 メッセージ駆動の疑問 • なにそれ面倒くさくない? メッセージ駆動の疑問 • なにそれ面倒くさくない? • キューに溜める必要なくない? メッセージ駆動の疑問 • なにそれ面倒くさくない? • キューに溜める必要なくない? • すぐ処理すればよくね? メッセージ駆動でなければならない理由 Server Side ゲーム開始通知 ↓ カードの配布通知 ↓ カードの交換 ↓ ターンの通知 ↓ 最初の人が出した カードの通知 Client (Flash) Side メッセージ駆動でなければならない理由 Server Side ゲーム開始通知 ↓ カードの配布通知 一瞬 ↓ カードの交換 ↓ ターンの通知 ↓ 最初の人が出した カードの通知 Client (Flash) Side メッセージ駆動でなければならない理由 Server Side 一瞬 ゲーム開始通知 Client (Flash) Side ↓ カードの配布通知 アニメ ↓ カードの交換 アニメ ↓ ターンの通知 アニメ ↓ 最初の人が出した アニメ カードの通知 メッセージ駆動でなければならない理由 Server Side Client (Flash) Side メッセージ駆動でなければならない理由 Server Side ゲーム開始通知 カードの配布通知 カードの交換 ターンの通知 最初の人が出した ↓ ↓ ↓ カードの通知 Client (Flash) Side アニメ アニメ アニメ アニメ メッセージ駆動でなければならない理由 メッセージ駆動でなければならない理由 サーバーから複数の通知が一瞬で届いても 順番にひとつずつ処理する必要がある メッセージ駆動でなければならない理由 サーバーから複数の通知が一瞬で届いても 順番にひとつずつ処理する必要がある ↓ メッセージ駆動 メッセージ駆動でなければならない理由 サーバーから複数の通知が一瞬で届いても 順番にひとつずつ処理する必要がある ↓ メッセージ駆動 ↓ Message + キュー + Thread アニメーションが入る Scene の処理 if (message.type == start ) { var startAnim:Thraed = _view.getStartAnimation(); startAnim.start(); startAnim.join(); return; } if (message.type == deal ) { var cards:CardList = CardList.fromObject(message.params); var dealAnim:Thread = _view.getDealAnimation(cards); dealAnim.start(); dealAnim.join(); return; } ... Scene の分割 Scene の分割 • 全てのメッセージ処理をひとつの スレッドで行うと応答性が下がる Scene の分割 • 全てのメッセージ処理をひとつの スレッドで行うと応答性が下がる • 種類に応じてスレッドを分割 Scene の分割 • 全てのメッセージ処理をひとつの スレッドで行うと応答性が下がる • 種類に応じてスレッドを分割 • 例: ゲーム進行とチャット メッセージ駆動 + Thread のススメ メッセージ駆動 + Thread のススメ • 何も考えずにマルチプレイものを作ると ハマる問題のほとんどはタイミングが原因 メッセージ駆動 + Thread のススメ • 何も考えずにマルチプレイものを作ると ハマる問題のほとんどはタイミングが原因 • 意図しないタイミングで意図しない動作... メッセージ駆動 + Thread のススメ • 何も考えずにマルチプレイものを作ると ハマる問題のほとんどはタイミングが原因 • 意図しないタイミングで意図しない動作... • しかもデバッグ大変 メッセージ駆動 + Thread のススメ • 何も考えずにマルチプレイものを作ると ハマる問題のほとんどはタイミングが原因 • 意図しないタイミングで意図しない動作... • しかもデバッグ大変 • メッセージ駆動 + Thread でそこの堅陣性は 保証される まとめ まとめ • ロジックはサーバー, Flash はビュー まとめ • ロジックはサーバー, Flash はビュー • Model + View + Scene まとめ • ロジックはサーバー, Flash はビュー • Model + View + Scene • Scene はメッセージ駆動 まとめ • ロジックはサーバー, Flash はビュー • Model + View + Scene • Scene はメッセージ駆動 • 団子と素麺を美味しく頂く まとめ • ロジックはサーバー, Flash はビュー • Model + View + Scene • Scene はメッセージ駆動 • 団子と素麺を美味しく頂く • ぜひみなさんも作ってみて下さい QA 質問があるなら手を挙げればいいじゃない マルチプレイ Flash ゲームのつくりかた ご清聴ありがとうございました!
© Copyright 2024 Paperzz