作者 godfat (godfat 真常) 看板 GameDesign
標題 Re: [程式] 關於SLG系統的寫法
時間 Wed Apr 9 17:00:20 2008
───────────────────────────────────────
不是很清楚你想作成什麼樣子,根據不同的遊戲系統,
我想寫出來的東西可以大相逕庭。你可以從你希望怎麼操作你的東西開始思索,
像是我會希望能夠這樣做(in Ruby):
> unit_pool = {} # a hash map
> godfat = Unit.new "godfat"
> godfat.hp = godfat.mp = 10
> # active ability
> godfat.obtain_ability Heal.new(:level => 10, :cooldown => 29)
> # passive ability
> godfat.obtain_ability Flying.new(:height => 2)
像這樣就可以任意指定某個單位有哪些能力,事後也能修改單位的屬性和能力。
存起來以便事後 clone 出來:
> unit_pool["godfat"] = godfat
治療自己:
> action = godfat.abilities["heal"].targets(godfat)
> action.apply
反治療:
> action.unapply
這裡有一個重點,就是 unapply 不可能自己生出來,
必須針對每一個 ability 都寫一次。除非不用這種 undo 法,
而是把整個狀態記錄下來,然後重新寫回去,像是:
> before_heal = godfat.dump_state
> action.apply
反治療:
> godfat.restore_state before_heal
不過我是不太建議這種作法,因為這樣你就必須知道被影響的單位有哪些,
像是在這裡只有影響到 godfat, 所以只要這樣做就好了。
要全面回復,可能就會有:
> targets_to_restore = action.target_list
> before_heals = targets_to_restore.map{ |t| t.dump_state }
> action.apply
反治療:
> targets_to_restore.zip( before_heals ).each{ |t, s| t.restore s }
唔,zip 和 map 的用法我就先不說了,總之這樣會有很多要處理的。
或是乾脆全場記下來,可能還簡單些:
> last_step = game.dump_state
> action.apply
反治療:
> game.restore_state last_step
不過我不知道你是不是要做這麼複雜的 undo,
還是只是單純取消之前下達的命令,例如換人之類的,而不是說「悔棋」
如果只是要取消之前下達的命令,那根本不用 undo, 只要不要執行就好了...
等到「回合結算」的時候才真的去執行,那就很單純。
其他程式碼:(我隨手寫的,所以其實很粗糙)
class Unit
attr_reader :name, :abilities
attr_accessor :cooldown, :hp, :mp
def initialize name
@name = name
@abilities = {}
@cooldown = @hp = @mp = 0
end
def obtain_ability ability
ability.owner = self
@abilities[ability.name] = ability
end
end
class Ability
attr_accessor :owner
attr_reader :name, :target_list
def targets *list # 這表示引數可以無限多
@target_list = list
self
end
def apply
end
def unapply
end
protected
def initialize name
@name = name
end
end
class Heal < Ability
def initialize opts
super "heal"
@opts = opts
end
def apply
self.owner.mp -= (opts[:level] * 1.5).round
self.target_list.each{ |t| t.hp += opts[:level] * 2 }
self.owner.cooldown += opts[:cooldown]
end
def unapply
self.owner.cooldown -= opts[:cooldown]
self.target_list.each{ |t| t.hp -= opts[:level] * 2 }
self.owner.mp += (opts[:level] * 1.5).round
end
private
attr_reader :opts
end
class Flying < Ability
# 略...
end
上面那個 unapply, 其實可以寫得更抽象化一點,像是:
> apply_steps << subtract 'self.owner.mp', '(opts[:level] * 1.5).round'
> << lambda{ self.target_list.each{ |t| ....略 } }
> << addition 'self.owner.cooldown', 'opts[:cooldown]'
然後 apply / unapply 就能這樣寫:
> def apply
> apply_steps.each &:apply
> end
> def unapply
> apply_steps.reverse_each &:unapply
> end
然後 subtract 的 unapply 當然就是 addition,
addition 的 unapply 當然就是 subtract.
中間的 lambda 會複雜許多,所以我就不寫了...
當然這樣是有點走火入魔啦,只是要大量使用 undo 的話就得做徹底一點。
補充:
這邊每 apply 一次,就會洗掉上一個 target_list,
所以如果需要直接放入 stack 做 undo list 的話,
Ability#targets 可能要這樣寫:
class Ability
def targets *list
@target_list = list
self.clone
end
end
這樣就可以直接放到 stack 去不怕影響到別人了
(當然,那個 clone 在 Heal/Flying 那些 class 裡要定義)
--
#!/usr/bin/env ruby [露比] /Programming (Kn|N)ight/ 看板《Ruby》
# if a dog nailed extra legs that http://www.ptt.cc/bbs/Ruby/index.html
# walks like an octopus, and Welcome ~Ruby@ptt~
# talks like an octopus, then ◢█◣ http://www.ruby-lang.org/
# we are happy to treat it as █ http://www.ruby-doc.org/
# if it were an octopus. ◥ ◤ http://www.rubyforge.org/
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 220.135.28.18
0 retries:
Post a Comment
Note: Only a member of this blog may post a comment.