Skip to content

Instantly share code, notes, and snippets.

@umegaya
Last active December 13, 2015 16:58
Show Gist options
  • Select an option

  • Save umegaya/4943761 to your computer and use it in GitHub Desktop.

Select an option

Save umegaya/4943761 to your computer and use it in GitHub Desktop.
mrogue 設計
scene
+-childs (entity)
+- wall (x, y)
+- wall (x1, y1)
+- player (xx, yy)
+- item1
+- item2
+- NPC (xx1, yy1)
+- item1
+- item2
+- ItemN (xxx, yyy)
pop @ x, y => refresh (x, y)
depop @ x, y => refresh (x, y)
move @ x1,y1 - x2,y2 => refresh (x1, y1), refresh (x2, y2)
change @ x, y => refresh (x, y)
sceneは縦x, 横yの配列の配列の配列
scene[x][y]にはx, y座標にあるオブジェクト全体が積まれている
refresh(x, y)はscene[x][y]の配列を総なめしてプライオリティに従って表示する
(ユーザー、モンスター>アイテム モンスター、アイテム内部ではランク的なものでソート)
canvasは画面サイズの(たぶん7x10)ボタンの配列で画像の表示と入力の受付を行う
x, yが画面内の場合のみrefreshは実際の描画を書き換えることになる
そうでない場合、x,yが画面内に入ってきたタイミングでrefresh(x,y)を呼び出して画像をセットする感じ
おそらく通知がくるのはユーザーの周囲、canvas + 2のサイズ相当のみ (12x12かな?)
ほかは可視範囲内に入ったときにとってくる。たぶん12マス分
可視範囲は小さくできてもいい
client {
scene[MAX_X][MAX_Y]
canvas[DISP_X][DISP_Y]
canvas_origin_x, canvas_origin_y
visible_w, visible_h
-- viewportは
canvas_origin_x + (canvas_origin_x - visible_w) / 2,
canvas_origin_y + (canvas_origin_y - visible_h) / 2,
canvas_origin_x - (canvas_origin_x - visible_w) / 2,
canvas_origin_y - (canvas_origin_y - visible_h) / 2,
}
server {
scene[MAX_X][MAX_Y]
}
ユーザーが行動するごとに経過時間がキューに積まれる(そうしないとレスポンスが相当悪くなる)
5,4,4,5秒経過する行動を4回やるとキューには
{5,4,4,5}とつまれ、サーバー内部のfiberによって
tick(5), tick(4), tick(4), tick(5)と処理される。たぶんwaitはなくてもよい
tickごとにオブジェクトのon_tickが実行されそれに応じた行動をとることになる。
単純にtickを実行するとそれしか処理されないのでやっぱりwaitは必要。
一回tickをするたびにsuspendすればよかったりするかも
0.5秒ぐらい?
Object
複雑な継承構造は作らない
移動、AI、攻撃など、機能ごとに応じてモジュールを作り、mixinしてオブジェクトを作る
データからクラスを組み立て、それをインスタンス化するイメージ
ID, name, hp, attack, defense, attack_module, move_module, AI, Skill1, Skill2, Skill3, Skill4
100, dragon, 100000, 1000, 1000, DoubleAttack, FlyMove, StrongAI, FireBreath, None, None, None
=>
class Dragon.extends.NPC.with.DoubleAttack.with.FlyMove.with.StrongAI.with.FireBreath {}
を作成してDragon.newでオブジェクトを作るとこれがドラゴンとして振る舞う、ようなイメージ
現状の課題は、ランダムで有無が決まるtraitsをどうするか、と動的に状態が変わるtraitsをどうするか
例を挙げると
前者は、ときどき強力な武器を持ったコボルトがいる、というのをどうデータで表現するか
後者は、酩酊すると仲間を斬りつける、といったAIの変化をどう表現するか
どちらもベースのtraitsのロジックの中に突っ込んでしまえばいいような気もするが、
前者で例えば、侍というモンスターだけが強力な日本刀を持っている、であるとか
後者でドラゴンだけは酩酊するとそのときだけしか使わないスキルをつかう、
などはそれだとベースのロジックがふくれあがる結果となるのでさけたい。
前者はInventoryTraits的なもので対応する
後者は難しい問題でbuff/debuffをどう管理するかという問題と関係している。
MMO的にEffectのリストをちゃんと処理するべきか。(フラグにしてベースのロジックに持っていくか、動的にAITraitsを差し替えるかはまた別の問題)
Builder, Probability, Template
==============================
Builderはランダムなダンジョンの地形を作り、アイテムやモンスターを配置するロジックを表現する
BaseBuilderやMonsterHouseBuilderがある
Builderは以下のカテゴリー分けでアイテムや門巣をポップさせる
unique(U)
legend(L)
ultra-rare(UR)
super-rare(SR)
rare(R)
uncommon(UC)
common(C)
probabilityは実際にポップさせるidを(templateと連携して)決定する
Builder:pop(category, type) --> category: U,L,UR,SR,R,UC,C, type --> monster, item, terrain
probability:choose(category, type)
end
probability : templates(monster, item, terrain)を受け取ってなかみをランダムにpopさせる。
ポップするもので、何か特定のタイプを増やすとか、そういうのはここを差し替える(ゴールド強化ダンジョン!アイテム強化ダンジョン!みたいな)
templateは
実際にポップするentityの具体的なパラメーターや振る舞いを保持している。また上記のカテゴリー分けも持っている(U,L,UR,SR,R,UC,C)
UI
アイテムリスト:swipeで右から?
ログ:オーバーレイ表示 or 左からswipe
画面上へのアクション:タップ。
何もないところへのタップは自動移動
アイテムが表示されているところは:そこまで移動して拾う?
NPCが表示されているところは:そのNPCをターゲットして攻撃
shootできればshoot
そうでなければ近くまで移動してattack
アイテム、マジック、スキル
1ダンジョンは1スレッドで処理される前提
action queue
============
ユーザーの操作はかならずaction queueというテーブルを生成する。
action queueはfiberによってシーケンシャルに実行される。
通信はしてもしなくてもよい。action queueの実行中は別のアクションは基本的に開始できない
キャンセルはできる。(攻撃を受けたときなど、自動的にキャンセルされる場合もある)
attack, skill, magic, effect
============================
effectは様々なシチュエーションでユーザーに発生する効果を定義するtrait
時間でダメージを受けたり攻撃ごとに体力が回復したりみたいな。
skillはeffectとeffectのパラメータの組み合わせをいくつか集めてまとまった効果にしたもの。エンティティの属性として付与されている
magicはskillと同様だが、魔法書を「使って」いくらかの時間を費やすことで使用回数がスタックされるもの
attackをどう定義するか
attackもskillとして定義されるべきか
entity
- inventory
items
- equipment
weapon
armor
shield
helm
gauntlet
left-ring
right-ring
amulet
- magic_inventory
magics
- attack
attack_skill
- skill_inventory
skills
attackは
basic_attack
weapon_attack
AI
=====
AIは「行動の種類」と「手段」、「ターゲット」を決定するのが役割(手段はないこともある)
(例:「隣のuser」を「武器」で「攻撃」、「自分」に「薬草」を「使う」、「石ころ」を「拾う」)
目的に沿って上記を選択するので、自身の「気分」みたいなものを持っていることが望ましい
attack
rescue
escape
みたいな。
choose_howみたいなやつで、そのユーザーが利用可能な手段の中から適当なものをリストアップする。
リストアップしたものをベースはランダムで選んでもいいし、賢いアルゴならもっとがんばって選んでもいい。
ベースのシステムではリストアップ>ランダムで選ぶところまでにする。
「気分」の遷移も簡単にやっちゃう。
defaultではattack、体力が2割以下でa)回復手段があればrescue、b)なければescape
hate, monsterのgroupなどもより賢くするのであれば必要だが今回は考えない
user:attack(target, user:weapon())
user:use(user, herb)
user:pick(item)
how item is used
=================
- 範囲内に存在しているエンティティに対して使用する
user:use(item, target)
- 装備している武器onlyで範囲内に存在しているエンティティに対して攻撃する
user:attack(item, target)
- 向きを指定して、その方向にいるオブジェクトのうち一番最初or範囲内全て(これはterrain or field_objectを生成してそれを移動させることで可能かもしれない)
:弓をうつ、杖を使う、薬を投げる
user:fire(item, dirx, diry)
- 場所を指定して、その場所および周囲に存在するオブジェクトのうちいくつかor全部
:爆弾
user:throw(item, posx, posy)
- 自分のみ。inventory windowから直接使うだけ。
:薬を飲む、巻物を読むなど。
user:use(item, user)
action
======
タップした先のグリッドに存在するオブジェクトと可能なアクション(見えている場合)
npc : 話す(friendly)、攻撃(enemy)
monster : 話す(friendly)、攻撃(enemy)
field_object : 使う、壊す
item : 拾う、使う
upstair : のぼる(ダンジョンから脱出する)
downstair : おりる(次の階へ)
タップ=>フリックで選択
その場所の1つ手前までは自動で移動し、あとはnpcなどであればその位置で最終的なアクション、itemやterrainであれば同じ位置まで移動して最終アクションをする
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment