BMVC for RGSS 1.00
1. BMVC是什么?
BMVC是RGSS中实现多个窗口或者精灵,或者他们的混合架构的一个脚本,可以用来简化代码。
相对于单个的窗体Window/精灵Sprite而言,BMVC可以同时有多个显示对象被控制。比如应用物品时,物品描述窗口,物品选择窗口和对象选择窗口是三个窗口,但有关联。可以用BMVC实现。
而相对于场景Scene而言,BMVC比Scene要轻量,也可以嵌入Scene中。
所以也可以放在事件中,比如一个物品选择窗口,没必要创建一个类。
BMVC是RGSS系列上对MVC模式(http://zh.wikipedia.org/wiki/MVC)的一个特化实现,因为RGSS默认脚本本身已经实现一系列与模型有关的东西比如$game_…,这里只需要和他们建立各种关系即可,这种关系模型在本脚本叫做BindingModel,故本脚本命名为BindingModel-View-Controller
2. 如何使用?
有两个重要的方法,一个是K,一个是B,K创建视图和有关的控制器,B创建和模型的绑定。
写在K里面的self.xxx,如果他是一个window或者sprite的话,会自动update和dispose
第一个例子,显示一个有Hello world的窗口,按回车(Input::C)时退出,因为不含任何可变的数据,所以没有用到B。
1 2 3 4 5 6 7 | K{ a = self.window = Window.new a.width = 132 a.height = 132 self.bitmap = a.contents = Bitmap.new(100, 100) self.bitmap.draw_text(a.contents.rect, "Hello world") }.run :C => :exit |
下面这个例子的窗口将要显示一个全局变量$a,并且当你按下回车键时,$a会加上1,并且显示也对应变化,注意变化的部分用B{}括起来。相对于上面那个例子,实际上就是把不变的”Hello world”换成了变化的$a.to_s,这里我们用B{$a.to_s}括起来。(同时加上了contents.clear清除内容这样的行为,不然前后写的文字会重叠在一起)
1 2 3 4 5 6 7 8 9 10 11 | $a = 0 K{ a = self.mywindow = Window.new self.mywindow.width = 132 self.mywindow.height = 132 self.bitmap = self.mywindow.contents = Bitmap.new(100, 100) B{ self.bitmap.clear self.bitmap.draw_text(0, 0, 100, 100, B{$a.to_s}) } }.run :B => :exit, :C => proc{$a += 1} |
因为按下回车键时,$a加上了1,所以$a.to_s会变化,B{$a.to_s}会把这个变化反馈给外面那个B{},
因此重新进行了绘制.
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | module Kittiko end module Kittiko::BindingModel attr_accessor :block def self.stack @stack ||= [] end def changed? @changed end def check_block @check_block ||= [] end def add_block(&b) check_block << Kittiko::Binding.new(&b) end def B(&b) if Kittiko::BindingModel.stack[-1] && !Kittiko::BindingModel.stack[-1].sealed Kittiko::BindingModel.stack[-1].add_block &b b.call else b.call end end def calc @cache = block.call end def update_binding if check_block.empty? @cache ||= calc else if @model_cache != (a = check_block.map{|x| x.calc}) @model_cache = a @cache ||= calc else @cache end end end end class Kittiko::Binding include Kittiko::BindingModel attr_accessor :sealed def initialize(&b) self.sealed = false Kittiko::BindingModel.stack.push self self.block = b b.call if b Kittiko::BindingModel.stack.pop self.sealed = true end end class Kittiko::Container include Kittiko::BindingModel attr_accessor :sealed def initialize(str, &b) @__symbols__ = [] self.sealed = false Kittiko::BindingModel.stack.push self instance_eval str instance_eval &b if b self.block = proc{} Kittiko::BindingModel.stack.pop self.sealed = true end def method_missing(sym, *args) @__symbols__.push(('@'+sym.to_s.chomp("=")).to_sym) (class << self; self; end).send :attr_accessor, sym.to_s.chomp("=") send sym, *args end def each @__symbols__.each do |x| yield instance_variable_get(x) end end def reverse_each @__symbols__.reverse.each do |x| yield instance_variable_get(x) end end def update each{|x| x.update if x.respond_to?(:update)} update_binding end def dispose reverse_each{|x| x.dispose if x.respond_to?(:dispose)} end def run_proc(v) case v when Symbol send v when Kittiko::Container v.run when Proc instance_eval &v else instance_eval v end end def run_loop(opt = {}) @exit = false until @exit run_once(opt) end end def run_once(opt = {}) Graphics.update Input.update update opt.each{|k, v| run_proc(v) if case k when Symbol Input.trigger?(Input.const_get(k)) when Proc instance_eval &k end } end def run(opt = {}) run_loop opt dispose end def exit @exit = true end def self.uniform_define_setter(*symbols) symbols.each do |sym| class_eval " def #{sym}(value) each{|x| x.#{sym} = value } end " end end uniform_define_setter :ox, :oy, :x, :y, :zoom_x, :zoom_y, :angle, :opacity, :content_opacity, :back_opacity, :z, :width, :height, :active, :mirror, :bush_depth, :blend_type, :color, :tone, :visible end def K(a = "", &b) return Kittiko::Container if a == "" && !b Kittiko::Container.new(a, &b) end class Kittiko::EventBase def self.keypress?(k) proc{Input.press?(Input.const_get(k))} end def self.keytrigger?(k) proc{Input.trigger?(Input.const_get(k))} end def self.keyrepeat?(k) proc{Input.repeat?(Input.const_get(k))} end end class Kittiko::Scope def self.[](name) BindObject.new(name) end class BindObject def initialize(name) @name = name end [:+, :-, :*, :/, :<, :>, :==, :>=, :<=].each{|x| class_eval %{ def #{x}(rhs) u = @name lambda{ instance_variable_get(u) #{x} rhs} end } } end end E = Kittiko::EventBase S = Kittiko::Scope |
没看懂咋用呢咋办?==