マルチプレイ Flashゲームのつくりかた - be

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 ゲームのつくりかた
ご清聴ありがとうございました!