cyross-ruby-miyako-mswin32 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. data/README +929 -0
  2. data/img/cursor.png +0 -0
  3. data/img/cursors.png +0 -0
  4. data/img/dice.png +0 -0
  5. data/img/wait_cursor.png +0 -0
  6. data/img/win_base.png +0 -0
  7. data/img/window.png +0 -0
  8. data/install_miyako.rb +61 -0
  9. data/lib/Miyako/API/audio.rb +198 -0
  10. data/lib/Miyako/API/basic_data.rb +573 -0
  11. data/lib/Miyako/API/bitmap.rb +507 -0
  12. data/lib/Miyako/API/choices.rb +475 -0
  13. data/lib/Miyako/API/collision.rb +460 -0
  14. data/lib/Miyako/API/diagram.rb +561 -0
  15. data/lib/Miyako/API/drawing.rb +151 -0
  16. data/lib/Miyako/API/fixedmap.rb +428 -0
  17. data/lib/Miyako/API/font.rb +403 -0
  18. data/lib/Miyako/API/input.rb +447 -0
  19. data/lib/Miyako/API/layout.rb +433 -0
  20. data/lib/Miyako/API/map.rb +529 -0
  21. data/lib/Miyako/API/map_event.rb +198 -0
  22. data/lib/Miyako/API/modules.rb +109 -0
  23. data/lib/Miyako/API/movie.rb +154 -0
  24. data/lib/Miyako/API/parts.rb +189 -0
  25. data/lib/Miyako/API/plane.rb +166 -0
  26. data/lib/Miyako/API/screen.rb +325 -0
  27. data/lib/Miyako/API/shape.rb +443 -0
  28. data/lib/Miyako/API/sprite.rb +752 -0
  29. data/lib/Miyako/API/sprite_animation.rb +481 -0
  30. data/lib/Miyako/API/spriteunit.rb +147 -0
  31. data/lib/Miyako/API/story.rb +300 -0
  32. data/lib/Miyako/API/textbox.rb +725 -0
  33. data/lib/Miyako/API/utility.rb +388 -0
  34. data/lib/Miyako/API/viewport.rb +140 -0
  35. data/lib/Miyako/API/yuki.rb +996 -0
  36. data/lib/Miyako/EXT/miyako_cairo.rb +62 -0
  37. data/lib/Miyako/EXT/raster_scroll.rb +138 -0
  38. data/lib/Miyako/EXT/slides.rb +157 -0
  39. data/lib/Miyako/miyako.rb +171 -0
  40. data/lib/Miyako/miyako_no_katana.so +0 -0
  41. data/logo/EGSR_logo.png +0 -0
  42. data/logo/EGSR_logo_bg.png +0 -0
  43. data/logo/EGSR_logo_fg.png +0 -0
  44. data/logo/EGSR_title_banner.png +0 -0
  45. data/logo/EGSR_title_logo.png +0 -0
  46. data/logo/miyako.png +0 -0
  47. data/logo/miyako_banner.png +0 -0
  48. data/logo/space.png +0 -0
  49. data/sample/Animation1/m1ku.rb +68 -0
  50. data/sample/Animation1/m1ku_arm_0.png +0 -0
  51. data/sample/Animation1/m1ku_arm_1.png +0 -0
  52. data/sample/Animation1/m1ku_arm_2.png +0 -0
  53. data/sample/Animation1/m1ku_arm_3.png +0 -0
  54. data/sample/Animation1/m1ku_back.jpg +0 -0
  55. data/sample/Animation1/m1ku_body.png +0 -0
  56. data/sample/Animation1/m1ku_eye_0.png +0 -0
  57. data/sample/Animation1/m1ku_eye_1.png +0 -0
  58. data/sample/Animation1/m1ku_eye_2.png +0 -0
  59. data/sample/Animation1/m1ku_eye_3.png +0 -0
  60. data/sample/Animation1/m1ku_hair_front.png +0 -0
  61. data/sample/Animation1/m1ku_hair_rear.png +0 -0
  62. data/sample/Animation1/readme.txt +72 -0
  63. data/sample/Animation2/lex.rb +96 -0
  64. data/sample/Animation2/lex_back.png +0 -0
  65. data/sample/Animation2/lex_body.png +0 -0
  66. data/sample/Animation2/lex_roadroller.png +0 -0
  67. data/sample/Animation2/lex_wheel_0.png +0 -0
  68. data/sample/Animation2/lex_wheel_1.png +0 -0
  69. data/sample/Animation2/lex_wheel_2.png +0 -0
  70. data/sample/Animation2/readme.txt +72 -0
  71. data/sample/Animation2/song_title.png +0 -0
  72. data/sample/Diagram_sample/back.png +0 -0
  73. data/sample/Diagram_sample/chr01.png +0 -0
  74. data/sample/Diagram_sample/chr02.png +0 -0
  75. data/sample/Diagram_sample/cursor.png +0 -0
  76. data/sample/Diagram_sample/diagram_sample_yuki2.rb +387 -0
  77. data/sample/Diagram_sample/readme.txt +90 -0
  78. data/sample/Diagram_sample/wait_cursor.png +0 -0
  79. data/sample/Room3/blue.rb +297 -0
  80. data/sample/Room3/ending.rb +180 -0
  81. data/sample/Room3/green.rb +220 -0
  82. data/sample/Room3/image/akamatsu.png +0 -0
  83. data/sample/Room3/image/aoyama.png +0 -0
  84. data/sample/Room3/image/congra.png +0 -0
  85. data/sample/Room3/image/congratulation.png +0 -0
  86. data/sample/Room3/image/congratulation_bg.png +0 -0
  87. data/sample/Room3/image/cursor.png +0 -0
  88. data/sample/Room3/image/midori.png +0 -0
  89. data/sample/Room3/image/mittsu_no_oheya.png +0 -0
  90. data/sample/Room3/image/mittsu_no_oheya_logo.png +0 -0
  91. data/sample/Room3/image/room_blue.png +0 -0
  92. data/sample/Room3/image/room_green.png +0 -0
  93. data/sample/Room3/image/room_red.png +0 -0
  94. data/sample/Room3/image/start.png +0 -0
  95. data/sample/Room3/image/three_doors.png +0 -0
  96. data/sample/Room3/image/wait_cursor.png +0 -0
  97. data/sample/Room3/main.rb +120 -0
  98. data/sample/Room3/main_component.rb +59 -0
  99. data/sample/Room3/readme.txt +76 -0
  100. data/sample/Room3/red.rb +227 -0
  101. data/sample/Room3/room3.rb +27 -0
  102. data/sample/Room3/title.rb +184 -0
  103. data/sample/ball_action_sample.rb +204 -0
  104. data/sample/blit_rop.rb +70 -0
  105. data/sample/cairo_sample.rb +25 -0
  106. data/sample/circle_collision_test.rb +62 -0
  107. data/sample/collision_test.rb +33 -0
  108. data/sample/collision_test2.rb +104 -0
  109. data/sample/fixed_map_test/cursor.png +0 -0
  110. data/sample/fixed_map_test/fixed_map_sample.rb +140 -0
  111. data/sample/fixed_map_test/map.csv +19 -0
  112. data/sample/fixed_map_test/map_01.png +0 -0
  113. data/sample/fixed_map_test/mapchip.csv +23 -0
  114. data/sample/fixed_map_test/monster.png +0 -0
  115. data/sample/fixed_map_test/readme.txt +72 -0
  116. data/sample/map_test/chara.rb +58 -0
  117. data/sample/map_test/chr1.png +0 -0
  118. data/sample/map_test/cursor.png +0 -0
  119. data/sample/map_test/main_parts.rb +69 -0
  120. data/sample/map_test/main_scene.rb +153 -0
  121. data/sample/map_test/map.png +0 -0
  122. data/sample/map_test/map2.png +0 -0
  123. data/sample/map_test/map_layer.csv +127 -0
  124. data/sample/map_test/map_manager.rb +75 -0
  125. data/sample/map_test/map_test.rb +23 -0
  126. data/sample/map_test/mapchip.csv +21 -0
  127. data/sample/map_test/oasis.rb +71 -0
  128. data/sample/map_test/readme.txt +89 -0
  129. data/sample/map_test/route.rb +157 -0
  130. data/sample/map_test/sea.png +0 -0
  131. data/sample/map_test/town.rb +74 -0
  132. data/sample/map_test/wait_cursor.png +0 -0
  133. data/sample/map_test/window.png +0 -0
  134. data/sample/polygon_test.rb +35 -0
  135. data/sample/rasterscroll.rb +25 -0
  136. data/sample/takahashi.rb +42 -0
  137. data/sample/text.png +0 -0
  138. data/sample/textbox_sample.rb +190 -0
  139. data/sample/transform.rb +54 -0
  140. data/sample/utility_test.rb +73 -0
  141. data/sample/utility_test2.rb +61 -0
  142. data/sample/utility_test3.rb +64 -0
  143. data/sample/utility_test4.rb +73 -0
  144. data/uninstall_miyako.rb +19 -0
  145. metadata +196 -0
@@ -0,0 +1,147 @@
1
+ # -*- encoding: utf-8 -*-
2
+ =begin
3
+ --
4
+ Miyako v2.0
5
+ Copyright (C) 2007-2009 Cyross Makoto
6
+
7
+ This library is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU Lesser General Public
9
+ License as published by the Free Software Foundation; either
10
+ version 2.1 of the License, or (at your option) any later version.
11
+
12
+ This library is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General Public
18
+ License along with this library; if not, write to the Free Software
19
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
+ ++
21
+ =end
22
+
23
+ # スプライト関連クラス群
24
+ module Miyako
25
+ #==SpriteUnitを生成するための構造体クラス
26
+ #Structクラスからの継承
27
+ #--
28
+ #SpriteUnit = Struct.new(:bitmap, :ox, :oy, :ow, :oh, :x, :y, :cx, :cy)
29
+ #++
30
+ class SpriteUnitBase < Struct
31
+ #===位置を変更する(変化量を指定)
32
+ #位置を右方向へdxピクセル、下方向へdyピクセル移動する
33
+ #ブロックを渡すと、ブロック評価中の位置を変更する
34
+ #_dx_:: 移動量(x方向)。単位はピクセル
35
+ #_dy_:: 移動量(y方向)。単位はピクセル
36
+ #返却値:: 自分自身を返す
37
+ def move(dx, dy)
38
+ o = [self.x, self.y]
39
+ self.x+=dx
40
+ self.y+=dy
41
+ if block_given?
42
+ yield
43
+ self.x, self.y = o
44
+ end
45
+ return self
46
+ end
47
+
48
+ #===位置を変更する(位置指定)
49
+ #左上を(0.0)として、位置を右xピクセル、下yピクセルの位置移動する
50
+ #ブロックを渡すと、ブロック評価中の位置を変更する
51
+ #_x_:: 移動先位置(x方向)。単位はピクセル
52
+ #_y_:: 移動先位置(y方向)。単位はピクセル
53
+ #返却値:: 自分自身を返す
54
+ def move_to(x, y)
55
+ o = [self.x, self.y]
56
+ self.x=x
57
+ self.y=y
58
+ if block_given?
59
+ yield
60
+ self.x, self.y = o
61
+ end
62
+ return self
63
+ end
64
+ #また、ブロックを渡せば、複製したインスタンスに補正を欠けることが出来る(画像変換も可能)
65
+
66
+ #===自分自身を返す
67
+ #SpriteUnit対応
68
+ #ダックタイピング用のメソッド
69
+ #得られるインスタンスは複写していないので、インスタンスの値を調整するには、dupメソッドで複製する必要がある
70
+ #返却値:: 自分自身
71
+ def to_unit
72
+ return self
73
+ end
74
+
75
+ #===スプライトを生成して返す
76
+ #ダックタイピング用のメソッド
77
+ #所持しているSpriteUnitから、Spriteクラスのインスタンスを生成する
78
+ #但し、bitmapの設定は:type=>:alpha_channelのみ
79
+ #引数1個のブロックを渡せば、スプライトに補正をかけることが出来る
80
+ #返却値:: 生成したスプライト
81
+ def to_sprite
82
+ sprite = Sprite.new(:unit=>self, :type=>:ac)
83
+ yield sprite if block_given?
84
+ return sprite
85
+ end
86
+
87
+ #===画像の表示矩形を取得する
88
+ #画像が表示されているときの矩形を取得する。矩形は、[x,y,ow,oh]で取得する。
89
+ #返却値:: 生成された矩形
90
+ def rect
91
+ return Rect.new(self.x, self.y, self.ow, self.oh)
92
+ end
93
+
94
+ #===現在の画面の最大の大きさを矩形で取得する
95
+ #但し、SpriteUnitの場合は最大の大きさ=画像の大きさなので、rectと同じ値が得られる
96
+ #返却値:: 画像の大きさ(Rect構造体のインスタンス)
97
+ def broad_rect
98
+ return self.rect
99
+ end
100
+ end
101
+
102
+ #==スプライト出力情報構造体
103
+ #基本的なことは、Sprite.renderで行うことが出来るが、凝った処理を行う場合は、SpriteUnitを使う
104
+ #--
105
+ #SpriteUnit = Struct.new([:dp], :bitmap, :ox, :oy, :ow, :oh, :x, :y, :cx, :cy)
106
+ #++
107
+ #([数字])は、配列として認識したときのインデックス番号に対応(Struct#[]メソッドを呼び出した時のインデックス)
108
+ #:bitmap([0]) -> 画像データ(SDL::Surfaceクラスのインスタンス)
109
+ #:ox([1]) -> 描画開始位置(x方向)
110
+ #:oy([2]) -> 描画開始位置(y方向)
111
+ #:ow([3]) -> 描画幅
112
+ #:oh([4]) -> 描画高さ
113
+ #:x([5]) -> 描画幅
114
+ #:y([6]) -> 描画高さ
115
+ #:cx([7]) -> 回転・拡大・縮小・鏡像の中心座標(x方向)
116
+ #:cy([8]) -> 回転・拡大・縮小・鏡像の中心座標(y方向)
117
+ SpriteUnit = SpriteUnitBase.new(:bitmap, :ox, :oy, :ow, :oh, :x, :y, :cx, :cy)
118
+
119
+ #==SpriteUnit生成ファクトリクラス
120
+ #SpriteUnit構造体のインスタンスを生成するためのクラス
121
+ class SpriteUnitFactory
122
+ PARAMS = [:bitmap, :ox, :oy, :ow, :oh, :x, :y, :cx, :cy]
123
+ #==SpriteUnitのインスタンスを生成する
124
+ #params: 初期化するSpriteUnit構造体の値。ハッシュ引数。引数のキーは、SpriteUnitのアクセサ名と同一。省略可能
125
+ def SpriteUnitFactory.create(params = nil)
126
+ unit = SpriteUnit.new(nil, 0, 0, 0, 0, 0, 0, 0, 0)
127
+ return SpriteUnitFactory.apply(unit, params)
128
+ end
129
+
130
+ #==SpriteUnitの各アクセサに対応した値を設定する
131
+ #(注)bitmapアクセサに値を設定する場合、ox,oy,ow,ohの値が自動的に、
132
+ #bitmapに対応する値(ox=0,oy=0,ow=bitmap.w,oh=bitmap.h)が設定される
133
+ #unit: 設定対象のSpriteUnit構造体
134
+ #params: 設定するSpriteUnit構造体の値。ハッシュ引数。引数のキーは、SpriteUnitのアクセサ名と同一
135
+ def SpriteUnitFactory.apply(unit, params)
136
+ if params && params.has_key?(:bitmap)
137
+ unit.bitmap = params[:bitmap]
138
+ unit.ox = 0
139
+ unit.oy = 0
140
+ unit.ow = unit.bitmap.w
141
+ unit.oh = unit.bitmap.h
142
+ end
143
+ PARAMS.each{|prm| unit[prm] = params[prm] if params.has_key?(prm) } if params
144
+ return unit
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,300 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ =begin
4
+ --
5
+ Miyako v2.0
6
+ Copyright (C) 2007-2009 Cyross Makoto
7
+
8
+ This library is free software; you can redistribute it and/or
9
+ modify it under the terms of the GNU Lesser General Public
10
+ License as published by the Free Software Foundation; either
11
+ version 2.1 of the License, or (at your option) any later version.
12
+
13
+ This library is distributed in the hope that it will be useful,
14
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ Lesser General Public License for more details.
17
+
18
+ You should have received a copy of the GNU Lesser General Public
19
+ License along with this library; if not, write to the Free Software
20
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
+ ++
22
+ =end
23
+
24
+ module Miyako
25
+
26
+ #==シーン実行クラス
27
+ #用意したシーンインスタンスを実行
28
+ class Story
29
+ @@sub_scenes = [:sub_scene, :sub_routine]
30
+ @@over_scenes = [:over_scene]
31
+
32
+ def prev_label #:nodoc:
33
+ return @prev_label
34
+ end
35
+
36
+ def next_label #:nodoc:
37
+ return @next_label
38
+ end
39
+
40
+ def upper_label #:nodoc:
41
+ return @stack.empty? ? nil : @stack.last[0]
42
+ end
43
+
44
+ #===インスタンスの作成
45
+ #ストーリー情報の初期か
46
+ #返却値:: 生成したインスタンス
47
+ def initialize
48
+ @prev_label = nil
49
+ @next_label = nil
50
+
51
+ @stack = []
52
+ @fibers = [nil]
53
+
54
+ @scene_cache = Hash.new
55
+ @scene_cache_list = Array.new
56
+ @scene_cache_max = 20
57
+
58
+ @fiber = Proc.new{|sc, num|
59
+ raise MiyakoError, "Illegal Script-label name! : #{sc}" unless Scene.has_scene?(sc.to_s)
60
+ fnum = nil
61
+ bk_nn = sc
62
+ uu = sc.new(self)
63
+ uu.init_inner(@prev_label, self.upper_label)
64
+ uu.setup
65
+ ret = true
66
+ while ret do
67
+ nn = uu.update
68
+ uu.render
69
+ if fnum && @fibers[fnum]
70
+ @fibers[fnum].resume(true)
71
+ elsif nn && !(nn.eql?(uu.class)) && @@over_scenes.include?(nn.scene_type)
72
+ @fibers << Fiber.new(&@fiber)
73
+ fnum = @fibers.length-1
74
+ @fibers[fnum].resume(nn, fnum)
75
+ n = bk_nn
76
+ end
77
+ break unless nn
78
+ ret = Fiber.yield
79
+ end
80
+ uu.final
81
+ uu.dispose
82
+ if (fnum && @fibers[fnum])
83
+ @fibers[fnum].resume(nil)
84
+ @fibers[fnum] = nil
85
+ fnum = nil
86
+ end
87
+ @fibers[num] = nil
88
+ }
89
+ end
90
+
91
+ def get_scene(n, s) #:nodoc:
92
+ class_symbol = n.to_s
93
+ if @scene_cache_list.length == @scene_cache_max
94
+ del_symbol = @scene_cache_list.shift
95
+ @scene_cache[del_symbol].dispose
96
+ @scene_cache.delete(del_symbol)
97
+ end
98
+ @scene_cache_list.delete(class_symbol)
99
+ @scene_cache_list.push(class_symbol)
100
+ @scene_cache[class_symbol] ||= n.new(self)
101
+ return @scene_cache[class_symbol]
102
+ end
103
+
104
+ #===Storyの実行を始める
105
+ #"obj.run(MainScene)"と記述すると、SceneモジュールをmixinしたMainSceneクラスのインスタンスを作成し、評価を始める
106
+ #_n_:: 最初に実行するシーン名(クラス名を定数で)
107
+ def run(n)
108
+ return nil if n == nil
109
+ u = nil
110
+ on = nil
111
+ @stack = Array.new # reset
112
+ while n != nil
113
+ @prev_label = on
114
+ on = n
115
+
116
+ raise MiyakoError, "Illegal Script-label name! : #{n}" unless Scene.has_scene?(n.to_s)
117
+ raise MiyakoError, "This scene cannot use for Standard Scene! : #{n}" if n.scene_type != :scene
118
+ u = get_scene(n, @stack.size) if u == nil
119
+ u.init_inner(@prev_label, self.upper_label)
120
+ u.setup
121
+
122
+ loop do
123
+ Input.update
124
+ Screen.clear
125
+ bk_n = on
126
+ n = u.update
127
+ u.render
128
+ if @fibers.first
129
+ raise MiyakoError, "Double over scene from root!" if n && @@over_scenes.include?(n.scene_type)
130
+ @fibers.first.resume(true, 0)
131
+ elsif n && @@over_scenes.include?(n.scene_type)
132
+ @fibers.clear
133
+ @fibers << Fiber.new(&@fiber)
134
+ @fibers.first.resume(n, 0)
135
+ n = bk_n
136
+ end
137
+ Screen.render
138
+ break unless n && on.eql?(n)
139
+ end
140
+ u.next = n
141
+ @next_label = n
142
+ u.final
143
+ if n == nil
144
+ if @@sub_scenes.include?(u.class.scene_type) && @stack.empty? == false
145
+ n, u = @stack.pop
146
+ next
147
+ end
148
+ break
149
+ elsif @@sub_scenes.include?(n.scene_type)
150
+ @stack.push([on, u])
151
+ u = nil
152
+ else
153
+ u = nil
154
+ end
155
+ end
156
+ if @fibers.length > 0
157
+ @fibers.each{|fiber| fiber.resume(nil) if fiber }
158
+ end
159
+ @scene_cache_list.each{|sy| @scene_cache[sy].dispose }
160
+ @scene_cache.clear
161
+ @scene_cache_list.clear
162
+ end
163
+
164
+ #==="over_scene"形式のシーンが実行中かどうか判別する
165
+ #返却値:: "over_scene"形式のシーンが実行中の時はtrueを返す
166
+ def over_scene_execute?
167
+ return @now_fiber != nil
168
+ end
169
+
170
+ #===内部の情報を解放する
171
+ def dispose
172
+ @scene_cache.keys.each{|k| @scene_cache[del_symbol].dispose }
173
+ end
174
+
175
+ #==シーンモジュール
176
+ #本モジュールをmixinすることにより、シーンを示すインスタンスを作成することができる
177
+ #mixinするときに気をつけなければいけないのは、本モジュールでは以下のインスタンス変数・モジュール変数を
178
+ #予約しているため、これらの変数の値を勝手に変えてはいけない
179
+ #@@scenesモジュール変数(シーンクラス一覧が入っている配列)、@storyインスタンス変数(シーンを呼び出したStoryクラスインスタンス)
180
+ #@nowインスタンス変数(現在評価しているシーンクラス)、@preインスタンス変数(一つ前に評価していたシーンクラス)
181
+ #@upperインスタンス変数(sub_routineの呼び元シーンクラス)、@nextインスタンス変数(移動先のシーンクラス)
182
+ #また、シーンには「シーン形式」がある。
183
+ #種類は、シーケンスな移動が出来る「通常シーン」、終了したときに移動元に戻る「サブシーン」、
184
+ #現在実行中のシーン上で並行に実行する「オーバーシーン」の3種類。
185
+ #デフォルトは「通常シーン」となっている。
186
+ #判別は、scene_typeクラスメソッドを呼び出すことで可能。デフォルトは、通常シーンを示すシンボル":scene"が返る。
187
+ #形式を変えるには、scene_typeクラスメソッドをオーバーライドし、返却値を変える。
188
+ #サブシーンの時はシンボル":sub_scene"、オーバーシーンのときはシンボル":over_scene"を返すように実装する
189
+ #(注1)同じクラス名のシーンを繰り返し実行したいときは、いったん別のダミーシーンを介してから元のシーンへ移動する必要がある
190
+ #(注2)オーバーシーン内では、シーンの移動が出来ないが、入れ子形式で別のオーバーシーンを積み上げる形なら移動可能。
191
+ module Scene
192
+ @@scenes = {}
193
+
194
+ def Scene.included(c) #:nodoc:
195
+ unless c.singleton_methods.include?(:scene_type)
196
+ def c.scene_type
197
+ return :scene
198
+ end
199
+ end
200
+ @@scenes[c.to_s] = c
201
+ end
202
+
203
+ def Scene.scenes #:nodoc:
204
+ return @@scenes
205
+ end
206
+
207
+ def Scene.has_scene?(s) #:nodoc:
208
+ return @@scenes.has_key?(s)
209
+ end
210
+
211
+ def initialize(story, check_only=false) #:nodoc:
212
+ return if check_only
213
+ @story = story
214
+ @now = self.class
215
+ @prev = nil
216
+ @upper = nil
217
+ @next = nil
218
+ self.init
219
+ end
220
+
221
+ def init_inner(p, u) #:nodoc:
222
+ @prev = p
223
+ @upper = u
224
+ end
225
+
226
+ #===シーン内で使用するオブジェクトの初期化テンプレートメソッド
227
+ #シーン内で使用するインスタンスを生成するときなどにこのメソッドを実装する
228
+ def init
229
+ end
230
+
231
+ #===シーン内で使用するオブジェクトの初期設定テンプレートメソッド
232
+ #シーン内で使用するインスタンスの設定を行うときにこのメソッドを実装する
233
+ #(シーン生成時に生成したインスタンスはキャッシュされ、再利用することができることに注意)
234
+ def setup
235
+ end
236
+
237
+ #===シーンの情報を更新するテンプレートメソッド
238
+ #
239
+ #現在実行しているシーンを繰り返し実行する場合はインスタンス変数@nowを返すように実装する
240
+ #nilを返すとシーンの処理を終了する(元のStory#runメソッド呼び出しの次に処理が移る)
241
+ #但し、scene_typeメソッドの結果が:sub_routneのとき、移動元シーンに戻る
242
+ #返却値:: 移動先シーンクラス
243
+ def update
244
+ return @now
245
+ end
246
+
247
+ #===シーンで指定しているインスタンスを画面に描画するテンプレートメソッド
248
+ def render
249
+ end
250
+
251
+ #===シーン内で使用したオブジェクトの後始末を行うテンプレートメソッド
252
+ #ここでは、解放処理(dispose)ではなく、終了処理(値を変更するなど)に実装する
253
+ #setupメソッドと対になっているというイメージ
254
+ def final
255
+ end
256
+
257
+ #===シーンに使用したデータの解放を記述するテンプレートメソッド
258
+ #initメソッドと対になっているというイメージ
259
+ def dispose
260
+ end
261
+
262
+ def next=(label) #:nodoc:
263
+ @next = label
264
+ end
265
+
266
+ #==="over_scene"形式のシーンが実行中かどうか判別する
267
+ #返却値:: "over_scene"形式のシーンが実行中の時はtrueを返す
268
+ def over_scene_execute?
269
+ return @story.over_scene_execute?
270
+ end
271
+
272
+ #===シーンの解説を返す(テンプレートメソッド)
273
+ #Sceneモジュールをmixinしたとき、解説文を返す実装をしておくと、
274
+ #Scene.#lisutupメソッドを呼び出したときに、noticeメソッドの結果を取得できる
275
+ #返却値:: シーンの解説(文字列)
276
+ def notice
277
+ return ""
278
+ end
279
+
280
+ #===登録しているシーン一覧をリストアップする
281
+ #リストの内容は、"シーンクラス名(文字列),シーンクラス(ポインタ),解説(noticeメソッドの内容)"という書式で取得できる
282
+ #返却値:: リストアップしたシーンの配列
283
+ def Scene.listup
284
+ list = Array.new
285
+ sns = @@scenes
286
+ sns.keys.sort.each{|k| list.push("#{k}, #{sns[k]}, \"#{sns[k].notice}\"\n") }
287
+ return list
288
+ end
289
+
290
+ #===Scene.#listupメソッドの内容をCSVファイルに保存する
291
+ #_csvname_:: 保存するCSVファイルパス
292
+ def Scene.listup2csv(csvfname)
293
+ csvfname += ".csv" if csvfname !~ /\.csv$/
294
+ list = self.listup
295
+ File.open(csvfname, "w"){|f| list.each{|l| f.print l } }
296
+ end
297
+
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,725 @@
1
+ # -*- encoding: utf-8 -*-
2
+ =begin
3
+ --
4
+ Miyako v2.0
5
+ Copyright (C) 2007-2008 Cyross Makoto
6
+
7
+ This library is free software; you can redistribute it and/or
8
+ modify it under the terms of the GNU Lesser General Public
9
+ License as published by the Free Software Foundation; either
10
+ version 2.1 of the License, or (at your option) any later version.
11
+
12
+ This library is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General Public
18
+ License along with this library; if not, write to the Free Software
19
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
+ ++
21
+ =end
22
+
23
+ module Miyako
24
+ #==テキストボックスを構成するクラス
25
+ #テキスト表示部、ウェイトカーソル、選択カーソルで構成される
26
+ class TextBox
27
+ include SpriteBase
28
+ include Animation
29
+ include Layout
30
+ extend Forwardable
31
+
32
+ attr_accessor :textarea
33
+ attr_accessor :select_type, :waiting, :selecting
34
+ attr_accessor :font, :margin
35
+ attr_reader :wait_cursor, :select_cursor, :choices
36
+ attr_reader :locate, :size, :max_height
37
+
38
+ #===インスタンスの作成
39
+ #テキストボックスを生成する。パラメータは以下の通り。
40
+ #(括弧内は省略形)
41
+ #_:font_:: 描画フォント(Fontクラスのインスタンス) デフォルトはFont.sans_serif
42
+ #_:size_:: 描画文字数(2要素の配列またはSize構造体のインスタンス) デフォルトはSize(20,8)
43
+ #_:wait_cursor(:wc)_:: ボタン入力待ちを示すカーソル(SpriteもしくはSpriteAnimationクラスのインスタンス)
44
+ #_:select_cursor(:sc)_:: 選択カーソル(SpriteもしくはSpriteAnimationクラスのインスタンス)
45
+ #_:page_size_:: 一度にテキストボックスに表示させる選択肢の数(縦方向、デフォルトは8)
46
+ #
47
+ #_params_:: 生成時のパラメータ(ハッシュ引数)
48
+ #返却値:: TextBoxクラスのインスタンス
49
+ def initialize(params = {})
50
+ init_layout
51
+ @visible = true
52
+ @font = params[:font] || Font.sans_serif
53
+ @max_height = @font.line_height
54
+ @locate = Point.new(0, 0)
55
+
56
+ @base = params[:size] || Size.new(20, 8)
57
+ @size = Size.new((@font.size + @font.hspace) * @base[0] - @font.hspace +
58
+ (@font.use_shadow ? @font.shadow_margin[0] : 0),
59
+ @font.line_height *
60
+ @base[1] - @font.vspace)
61
+ @pos = Point.new(0, 0)
62
+ set_layout_size(*@size)
63
+
64
+ @margin = 0
65
+
66
+ @textarea = Sprite.new({:size => @size, :type => :ac, :is_fill => true})
67
+
68
+ @default_wait_cursor_position = lambda{|wcursor, tbox| wcursor.center.outside_bottom}
69
+ @default_select_cursor_position = lambda{|scursor, tbox| scursor.outside_left.middle}
70
+
71
+ @wait_cursor = params[:wait_cursor] || params[:wc] || nil
72
+ @wait_cursor_position = @default_wait_cursor_position
73
+ @select_cursor = params[:select_cursor] || params[:sc] || nil
74
+ @select_cursor_position = @default_select_cursor_position
75
+
76
+ @on_pause = lambda{}
77
+
78
+ @on_release = lambda{}
79
+
80
+ @on_draw = lambda{}
81
+
82
+ @command_page_size = params[:page_size] || @base[1]
83
+
84
+ @choices = Choices.new
85
+ @choices.snap(self)
86
+ @choices.left.top
87
+
88
+ @now_choice = nil
89
+ @pre_attach = false
90
+
91
+ @waiting = false
92
+ @select_type = :left
93
+ @selecting = false
94
+
95
+ @textarea.snap(self)
96
+ @textarea.centering
97
+
98
+ @fiber = nil
99
+
100
+ if @wait_cursor
101
+ @wait_cursor.snap(self)
102
+ @default_wait_cursor_position.call(@wait_cursor, self)
103
+ end
104
+ @select_cursor.snap(self) if @select_cursor
105
+
106
+ @move_list = [
107
+ [lambda{ },
108
+ lambda{ @choices.right_choice },
109
+ lambda{ @choices.left_choice }],
110
+ [lambda{ @choices.down_choice },
111
+ lambda{ },
112
+ lambda{ }],
113
+ [lambda{ @choices.up_choice },
114
+ lambda{ },
115
+ lambda{ }]
116
+ ]
117
+
118
+ end
119
+
120
+ #===表示可能な文字行数を取得する
121
+ #返却値:: 表示可能な行数
122
+ def rows
123
+ return @base.h
124
+ end
125
+
126
+ #===一列に表示可能な文字数を取得する
127
+ # 返却される値は全角文字の数だが、半角文字も全角文字1文字と計算されるので注意
128
+ #返却値:: 表示可能な文字数
129
+ def columns
130
+ return @base.w
131
+ end
132
+
133
+ #===一列に表示可能な文字数と行数を取得する
134
+ # 文字数はcolumns、行数はrowsの値と同一
135
+ # Size構造体のインスタンスとして取得
136
+ #返却値:: 表示可能な文字数と行数
137
+ def text_size
138
+ return Size.new(@base.w, @base.h)
139
+ end
140
+
141
+ #===並行なブロック処理を開始する
142
+ # ブロックをFiberに渡して、並行実行できるようにして、Fiberを開始する
143
+ # ブロックには引数を必ず一つ付けること。引数には自分自身と、
144
+ #executeメソッドの引数リスト(配列化されて渡ってくる)が渡ってくる。
145
+ # 渡したブロックは、現在の処理と切り替えて実行することになる
146
+ # 現在の処理からブロック処理へ切り替えるときは、TextBox#updateメソッドを呼び出す
147
+ # ブロック処理から現在の処理に戻るには、ブロックから抜け出すか、
148
+ #draw_text・command・pause・clear・cr・spaceのどれかのメソッドを呼び出す。
149
+ #_params_:: Fiberに渡す引数リスト。Fiberへは配列として渡される
150
+ def execute(*params, &block)
151
+ raise MiyakoError, "This method needs a block!" unless block
152
+ raise MiyakoError, "This method needs a block with one parameter!" unless block.arity == 2
153
+ @fiber = Fiber.new(&block)
154
+ @fiber.resume(self, params)
155
+ end
156
+
157
+ #===並行ブロック処理が実行中かどうかを問い合わせる
158
+ #返却値:: Fiberが評価中ならば、trueを返す
159
+ def execute?
160
+ return @fiber != nil
161
+ end
162
+
163
+ #===並行ブロック処理を更新する
164
+ # 内部でFiberが評価中ならば、Fiberに処理を移す
165
+ #返却値:: 自分自身を返す
166
+ def update
167
+ begin
168
+ @fiber.resume if @fiber
169
+ rescue FiberError
170
+ @fiber = nil
171
+ end
172
+ return self
173
+ end
174
+
175
+ #===テキストボックスのアニメーションを開始する
176
+ #返却値:: 自分自身を返す
177
+ def start
178
+ @textarea.start
179
+ @wait_cursor.start if @wait_cursor
180
+ @choices.start
181
+ @select_cursor.start if @select_cursor
182
+ return self
183
+ end
184
+
185
+ #===テキストボックスのアニメーションを停止する
186
+ #返却値:: 自分自身を返す
187
+ def stop
188
+ @textarea.stop
189
+ @wait_cursor.stop if @wait_cursor
190
+ @choices.stop
191
+ @select_cursor.stop if @select_cursor
192
+ return self
193
+ end
194
+
195
+ #===テキストボックスのアニメーションを先頭に戻す
196
+ #返却値:: 自分自身を返す
197
+ def reset
198
+ @textarea.reset
199
+ @wait_cursor.reset if @wait_cursor
200
+ @choices.reset
201
+ @select_cursor.reset if @select_cursor
202
+ return self
203
+ end
204
+
205
+ #===テキストボックスの表示を更新する
206
+ #テキストボックス・選択カーソル・選択肢・ウェイトカーソルのアニメーションを更新する
207
+ #返却値:: 常にfalseを返す
208
+ def update_animation
209
+ @textarea.update_animation
210
+ @wait_cursor.update_animation if (@wait_cursor && @waiting)
211
+ if @selecting
212
+ @choices.update_animation
213
+ @select_cursor.update_animation if @select_cursor
214
+ end
215
+ return false
216
+ end
217
+
218
+ #===スプライトに変換した画像を表示する
219
+ #すべてのパーツを貼り付けた、1枚のスプライトを返す
220
+ #引数1個のブロックを渡せば、スプライトに補正をかけることが出来る
221
+ #返却値:: 描画したスプライト
222
+ def to_sprite
223
+ rect = self.broad_rect
224
+ sprite = Sprite.new(:size=>rect.to_a[2,2], :type=>:ac)
225
+ Drawing.fill(sprite, [0,0,0])
226
+ Bitmap.ck_to_ac!(sprite, [0,0,0])
227
+ self.render_to(sprite){|sunit, dunit| sunit.x -= rect.x; sunit.y -= rect.y }
228
+ yield sprite if block_given?
229
+ return sprite
230
+ end
231
+
232
+ #===SpriteUnit構造体を生成する
233
+ #いったんSpriteインスタンスを作成し、それをもとにSpriteUnit構造体を生成する。
234
+ #返却値:: 生成したSpriteUnit構造体
235
+ def to_unit
236
+ return self.to_sprite.to_unit
237
+ end
238
+
239
+ #===現在の画面の最大の大きさを矩形で取得する
240
+ #テキストボックスの状態により、取得できる矩形の大きさが変わる
241
+ #返却値:: 生成された矩形(Rect構造体のインスタンス)
242
+ def broad_rect
243
+ rect = self.rect.to_a
244
+ rect_list = []
245
+ rect_list << @wait_cursor.broad_rect if (@wait_cursor && @waiting)
246
+ if @selecting
247
+ rect_list << @choices.broad_rect
248
+ rect_list << @select_cursor.broad_rect if @select_cursor
249
+ end
250
+ return self.rect if rect_list.length == 0
251
+ rect_list = rect.zip(*rect_list)
252
+ # width -> right
253
+ rect_list[2] = rect_list[2].zip(rect_list[0]).map{|xw| xw[0] + xw[1]}
254
+ # height -> bottom
255
+ rect_list[3] = rect_list[3].zip(rect_list[1]).map{|xw| xw[0] + xw[1]}
256
+ x, y = rect_list[0].min, rect_list[1].min
257
+ return Rect.new(x, y, rect_list[2].max - x, rect_list[3].max - y)
258
+ end
259
+
260
+ #===画面に描画する
261
+ #現在のテキストエリア・カーソルを、現在の状態で描画する
262
+ #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
263
+ #ブロックの引数は、|インスタンスのSpriteUnit, 画面のSpriteUnit|となる。
264
+ #visibleメソッドの値がfalseのときは描画されない。
265
+ #返却値:: 自分自身を返す
266
+ def render(&block)
267
+ return unless @visible
268
+ @textarea.render(&block)
269
+ @wait_cursor.render(&block) if (@wait_cursor && @waiting)
270
+ if @selecting
271
+ @choices.render(&block)
272
+ @select_cursor.render(&block) if @select_cursor
273
+ end
274
+ return self
275
+ end
276
+
277
+ #===画面に描画する
278
+ #現在のテキストエリア・カーソルを、現在の状態で描画する
279
+ #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
280
+ #ブロックの引数は、|インスタンスのSpriteUnit, 転送先のSpriteUnit|となる。
281
+ #visibleメソッドの値がfalseのときは描画されない。
282
+ #返却値:: 自分自身を返す
283
+ def render_to(dst, &block)
284
+ return unless @visible
285
+ @textarea.render_to(dst, &block)
286
+ @wait_cursor.render(dst, &block) if (@wait_cursor && @waiting)
287
+ if @selecting
288
+ @choices.render(dst, &block)
289
+ @select_cursor.render(dst, &block) if @select_cursor
290
+ end
291
+ return self
292
+ end
293
+
294
+ #===文字の描画位置にマージンを設定する
295
+ #marginで指定したピクセルぶん、下に描画する
296
+ #ブロックを渡すと、ブロックを評価している間だけマージンが有効になる
297
+ #_margin_:: 設定するマージン
298
+ #返却値:: 自分自身を返す
299
+ def margin_during(margin)
300
+ raise MiyakoError, "not given block!" unless block_given?
301
+ omargin, @margin = @margin, margin
302
+ yield
303
+ @margin = omargin
304
+ return self
305
+ end
306
+
307
+ #===指定した高さで描画する際のマージンを求める
308
+ #現在のフォントの設定で指定の文字列を描画したとき、予想される描画サイズを返す。実際に描画は行われない。
309
+ #第1引数に渡す"align"は、以下の3種類のシンボルのどれかを渡す
310
+ #_:top_:: 上側に描画(マージンはゼロ)
311
+ #_:middle_:: 中間に描画
312
+ #_:bottom_:: 下部に描画
313
+ #
314
+ #_align_:: 描画位置
315
+ #_height_:: 描画する高さ(デフォルトは、描画した最大の高さ)
316
+ #返却値:: マージンの値
317
+ def margin_height(align, height = @max_height)
318
+ return @font.margin_height(align, height)
319
+ end
320
+
321
+ #===ブロックを評価している間、文字色を変更する
322
+ #_color_:: 変更する文字色([r,g,b]の3要素の配列(値:0~255))
323
+ #返却値:: 自分自身を返す
324
+ def color_during(color)
325
+ raise MiyakoError, "not given block!" unless block_given?
326
+ @font.color_during(Color.to_rgb(color)){ yield }
327
+ return self
328
+ end
329
+
330
+ #===フォントサイズを変更する
331
+ #行中の最大フォントサイズが更新されるので、見栄えの良い表示のためにこちらを使用することをお薦めします
332
+ #_size_:: 変更するフォントサイズ
333
+ #返却値:: 自分自身を返す
334
+ def font_size=(size)
335
+ @font.size = size
336
+ @max_height = @font.line_height if @max_height < @font.line_height
337
+ return self
338
+ end
339
+
340
+ #===ブロックを評価している間、フォントサイズを変更する
341
+ #_size_:: 変更するフォントサイズ
342
+ #返却値:: 自分自身を返す
343
+ def font_size_during(size)
344
+ raise MiyakoError, "not given block!" unless block_given?
345
+ @font.size_during(size){
346
+ @max_height = @font.line_height if @max_height < @font.line_height
347
+ yield
348
+ }
349
+ return self
350
+ end
351
+
352
+ #===ブロックを評価している間、太字に変更する
353
+ #文字が領域外にはみ出る場合があるので注意!
354
+ #返却値:: 自分自身を返す
355
+ def font_bold
356
+ raise MiyakoError, "not given block!" unless block_given?
357
+ @font.bold{ yield }
358
+ return self
359
+ end
360
+
361
+ #===ブロックを評価している間、斜体文字に変更する
362
+ #文字が領域外にはみ出る場合があるので注意!
363
+ #返却値:: 自分自身を返す
364
+ def font_italic
365
+ raise MiyakoError, "not given block!" unless block_given?
366
+ @font.italic{ yield }
367
+ return self
368
+ end
369
+
370
+ #===ブロックを評価している間、下線付き文字に変更する
371
+ #返却値:: 自分自身を返す
372
+ def font_under_line
373
+ raise MiyakoError, "not given block!" unless block_given?
374
+ @font.under_line{ yield }
375
+ return self
376
+ end
377
+
378
+ #===テキストエリアに文字を描画する
379
+ #_text_:: 描画する文字列
380
+ #返却値:: 自分自身を返す
381
+ def draw_text(text)
382
+ @locate.x = @font.draw_text(@textarea, text, @locate.x, @locate.y + @margin)
383
+ @max_height = [@max_height, @font.line_height].max
384
+ @on_draw.call
385
+ Fiber.yield if @fiber
386
+ return self
387
+ end
388
+
389
+ #===文字描画時に行う処理を記述したブロックを登録する
390
+ #処理を行うブロックはオブジェクトとして渡す。
391
+ #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
392
+ #_event_:: 文字描画時処理するブロック
393
+ #返却値:: 自分自身を返す
394
+ def on_draw=(event)
395
+ tdraw = @on_draw
396
+ @on_draw = event
397
+ if block_given?
398
+ yield
399
+ @on_draw = tdraw
400
+ end
401
+ return self
402
+ end
403
+
404
+ #===選択肢の集合をTextBoxインスタンスに見合う形のChoicesクラスインスタンスの配列に変換する
405
+ #ブロック(引数一つのブロックのみ有効)を渡したときは、ブロックを評価して変換したChoicesクラスの配列を作成する。
406
+ #引数は、以下の構成を持つ配列のリスト。
407
+ #[非選択時スプライト(文字列可),選択時スプライト(文字列・nil可),選択結果インスタンス]
408
+ # 非選択時スプライト:自身が選択されていない時に表示するスプライト。文字列の時は、Shapeクラスなどでスプライトに変更する
409
+ # 選択時スプライト:自身が選択されている時に表示するスプライト。文字列の時は、Shapeクラスなどでスプライトに変更する
410
+ # (そのとき、文字色が赤色になる)。
411
+ # nilを渡すと、非選択時スプライトが使われる
412
+ # 注:スプライトは、画面にスナップしておくこと
413
+ # 選択結果インスタンス:コマンドが決定したときに、resultメソッドの値として渡すインスタンス。
414
+ # デフォルト処理の選択肢の位置は、画面左上から下へ順番に設定される
415
+ # 注:ブロックを渡すとき、選択肢の位置計算が、全選択肢の左上位置が[0,0]とする相対座標になっていること
416
+ #_choices_:: 選択肢の集合(上記参照)
417
+ #返却値:: Choicesクラスのインスタンスの配列
418
+ def create_choices_chain(choices)
419
+ if block_given?
420
+ return yield(choices)
421
+ end
422
+ choices = choices.map{|v|
423
+ org_font_color = @font.color
424
+ @font.color = Color[:white]
425
+ body = v[0].method(:to_sprite).arity == 0 ? v[0].to_sprite : v[0].to_sprite(@font)
426
+ @font.color = Color[:red]
427
+ body_selected = v[1] ? (v[1].method(:to_sprite).arity == 0 ? v[1].to_sprite : v[1].to_sprite(@font)) : body
428
+ @font.color = org_font_color
429
+ choice = Choices.create_choice(body, body_selected)
430
+ choice.result = v[2]
431
+ choice.end_select_proc = v[3]
432
+ next choice
433
+ }
434
+ choices2 = choices.each_slice(@command_page_size).to_a
435
+ choices2.each_with_index{|cc, x|
436
+ len = cc.length
437
+ right = choices2[x + 1] || choices2[0]
438
+ left = choices2[x - 1]
439
+ yp = 0
440
+ cc.each_with_index{|v, y|
441
+ v.down = cc[y + 1] || cc[0]
442
+ v.up = cc[y - 1]
443
+ v.right = right[y] || right.last
444
+ v.left = left[y] || left.last
445
+ v.body.move_to(0, yp)
446
+ v.body_selected.move_to(0, yp)
447
+ yp += [v.body.broad_rect.h, v.body_selected.broad_rect.h].max
448
+ }
449
+ }
450
+ return choices2
451
+ end
452
+
453
+ #===コマンド選択を設定する
454
+ #コマンド選択処理に移る(self#selecting?メソッドがtrueになる)
455
+ #
456
+ # 引数choicesに配列を渡すとき、各要素の構成は以下のようになる
457
+ # [コマンド文字列・画像,選択時コマンド文字列・画像,選択した結果(オブジェクト)]
458
+ #
459
+ # 引数choicesにChoicesクラスインスタンスを渡したとき、内部で、インスタンスを複写したものに置き換える
460
+ #
461
+ # このメソッドが呼び出された時、選択肢はlocateメソッドの値となる位置に移動する
462
+ # 引数dx,dyともにnil以外の数値を渡すと、上記の位置から更に移動する(位置が補正される)
463
+ # body_selectedをnilにした場合は、bodyと同一となる
464
+ # body_selectedを文字列を指定した場合は、文字色が赤色になることに注意
465
+ #_choices_:: 選択肢の配列、もしくはChoicesクラスのインスタンス
466
+ #_dx_:: 選択肢を表示するx座標の移動量。デフォルトはnil(移動しない)
467
+ #_dy_:: 選択肢を表示するy座標の移動量。デフォルトはnil(移動しない)
468
+ #返却値:: 自分自身を返す
469
+ def command(choices, dx = nil, dy = nil)
470
+ if choices.methods.include?(:start_choice)
471
+ @choices = choices.dup
472
+ @choices.snap(self)
473
+ else
474
+ @choices.clear
475
+ choices.each{|cc| @choices.create_choices(cc) }
476
+ end
477
+ @choices.left{|b| @locate.x}.top{|b| @locate.y}
478
+ @choices.move(dx, dy) if (dx != nil && dy != nil)
479
+ start_command
480
+ Fiber.yield if @fiber
481
+ return self
482
+ end
483
+
484
+ #===コマンド選択を開始する
485
+ #但し、commandメソッドを呼び出したときは自動的に呼ばれる
486
+ #返却値:: 自分自身を返す
487
+ def start_command
488
+ raise MiyakoError, "don't set Choice!" if @choices.length == 0
489
+ @choices.start_choice
490
+ if @select_cursor
491
+ @select_cursor.snap(@choices.body)
492
+ @select_cursor_position.call(@select_cursor, @choices.body)
493
+ end
494
+ @selecting = true
495
+ return self
496
+ end
497
+
498
+ #===コマンド選択を終了する
499
+ # 選択した選択肢(Choice構造体)にend_select_procブロックが設定されていれば自動的に評価される
500
+ #返却値:: 自分自身を返す
501
+ def finish_command
502
+ @choices.end_choice(self)
503
+ @choices.left.top
504
+ @selecting = false
505
+ return self
506
+ end
507
+
508
+ #===選択肢・選択カーソルを移動させる
509
+ #但し、非選択状態だったときは、選択状態に戻るだけ
510
+ #(そのときの選択肢は、最後に選択した選択肢を指定する)
511
+ #_dx_:: 移動量(x軸方向)。-1,0,1の3種類
512
+ #_dy_:: 移動量(y軸方向)。-1,0,1の3種類
513
+ #返却値:: 自分自身を返す
514
+ def move_cursor(dx, dy)
515
+ unless @choices.any_select?
516
+ @choices.start_choice(nil) # 選択状態を元に戻す
517
+ return self
518
+ end
519
+ @move_list[dy][dx].call
520
+ if @select_cursor
521
+ @select_cursor.snap(@choices.body)
522
+ @select_cursor_position.call(@select_cursor, @choices.body)
523
+ end
524
+ return self
525
+ end
526
+
527
+ #===マウスカーソルの位置とコマンドを照合する
528
+ #選択肢・選択カーソルを、マウスカーソルが当たっているコマンドに移動させる
529
+ #どのコマンドにも当たっていない場合は、すべてのコマンドは非選択状態になる
530
+ #_x_:: マウスカーソルの位置(x軸方向)
531
+ #_y_:: マウスカーソルの位置(y軸方向)
532
+ #返却値:: 自分自身を返す
533
+ def attach_cursor(x, y)
534
+ attach = @choices.attach(x, y)
535
+ if attach
536
+ if @select_cursor
537
+ @select_cursor.snap(@choices.body)
538
+ @select_cursor_position.call(@select_cursor, @choices.body)
539
+ end
540
+ else
541
+ @choices.non_select if @pre_attach
542
+ end
543
+ @pre_attach = attach
544
+ return self
545
+ end
546
+
547
+ #===マウスカーソルの位置にコマンドがあるかどうかを問い合わせる
548
+ #マウスカーソルがどれかのコマンドの上にあるときはtrue、どれにも当たっていないときはfalseを返す
549
+ #_x_:: マウスカーソルの位置(x軸方向)
550
+ #_y_:: マウスカーソルの位置(y軸方向)
551
+ #返却値:: マウスカーソルがどれかのコマンドにあるときはtrueを返す
552
+ def attach_any_command?(x, y)
553
+ return @choices.attach(x, y)
554
+ end
555
+
556
+ def update_layout_position #:nodoc:
557
+ @pos.move_to(*@layout.pos)
558
+ end
559
+
560
+ #===入力待ち状態(ポーズ)に表示するカーソルの位置を設定する
561
+ #ポーズカーソルの位置を、パラメータ二つ(カーソル本体・テキストボックス)を引数に取るブロックで実装する
562
+ #位置は、テキストエリアをsnapしていると想定して実装する
563
+ #デフォルトは、テキストエリアの中下に置かれる(center.bottom)
564
+ # (例)テキストボックスの中下(テキストエリアの外) -> {|wc, tbox| wc.center.outside_bottom }
565
+ #   テキストボックスの右下(テキストエリアの中) -> {|wc, tbox| wc.right.bottom }
566
+ #   テキストの最後尾 -> {|wc, tbox| wc.left{|b| tbox.locate.x }.top{|b| tbox.locate.y} }
567
+ # (テキストエリアの左上から右下へ現在の描画開始位置(tbox.locateメソッドで示した値)の距離移動した箇所)
568
+ #ブロックを渡していなかったり、ブロックの引数が2個でなければエラーを返す
569
+ #返却値:: 自分自身を返す
570
+ def set_wait_cursor_position(&proc)
571
+ raise MiyakoError, "Can't find block!" unless proc
572
+ raise MiyakoError, "This method must have two parameters!" unless proc.arity == 2
573
+ @wait_cursor_position = proc
574
+ @wait_cursor_position.call(@wait_cursor, self) if @wait_cursor
575
+ return self
576
+ end
577
+
578
+ #===入力待ち状態(ポーズ)に表示するカーソルの位置をデフォルトに戻す
579
+ #デフォルトの位置は、テキストエリアの中下(center.bottom)に設定されている
580
+ #返却値:: 自分自身を返す
581
+ def reset_wait_cursor_position
582
+ @wait_cursor_position = @default_wait_cursor_position
583
+ @wait_cursor_position.call(@wait_cursor, self) if @wait_cursor
584
+ return self
585
+ end
586
+
587
+ #===コマンド選択時に表示するカーソルの位置を設定する
588
+ #カーソルの位置を、パラメータ二つ(カーソル本体・選択肢)を引数に取るブロックで実装する
589
+ #位置は、テキストエリアをsnapしていると想定して実装する
590
+ #デフォルトは、選択肢の左側に置かれる(outside_left.middle)
591
+ # (例)選択肢の右側 -> {|wc, choice| wc.outside_right.middle }
592
+ #   選択肢の真上 -> {|wc, choice| wc.centering }
593
+ #ブロックを渡していなかったり、ブロックの引数が2個でなければエラーを返す
594
+ #返却値:: 自分自身を返す
595
+ def set_select_cursor_position(&proc)
596
+ raise MiyakoError, "Can't find block!" unless proc
597
+ raise MiyakoError, "This method must have two parameters!" unless proc.arity == 2
598
+ @select_cursor_position = proc
599
+ @select_cursor_position.call(@select_cursor, @choices.body) if (@select_cursor && @choices.body)
600
+ return self
601
+ end
602
+
603
+ #===入力待ち状態(ポーズ)に表示するカーソルの位置をデフォルトに戻す
604
+ #デフォルトの位置は、テキストエリアの中下(center.bottom)に設定されている
605
+ #返却値:: 自分自身を返す
606
+ def reset_select_cursor_position
607
+ @select_cursor_position = @default_select_cursor_position
608
+ @select_cursor_position.call(@select_cursor, @choices.body) if (@select_cursor && @choices.body)
609
+ return self
610
+ end
611
+
612
+ #===入力待ち状態(ポーズ)にする
613
+ #ポーズカーソルを表示する。pause?メソッドの結果がtrueになる
614
+ #ポーズカーソルの位置は、set_wait_cursor_positionで設定したブロックが評価されて決定される
615
+ #(デフォルトはテキストエリアの中下
616
+ #返却値:: 自分自身を返す
617
+ def pause
618
+ @waiting = true
619
+ return self unless @wait_cursor
620
+ @wait_cursor_position.call(@wait_cursor, self)
621
+ @on_pause.call
622
+ Fiber.yield if @fiber
623
+ return self
624
+ end
625
+
626
+ #===ポーズ時に行う処理を記述したブロックを登録する
627
+ #処理を行うブロックはオブジェクトとして渡す。
628
+ #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
629
+ #_event_:: ポーズ時処理するブロック
630
+ #返却値:: 自分自身を返す
631
+ def on_pause=(event)
632
+ tpause = @on_pause
633
+ @on_pause = event
634
+ if block_given?
635
+ yield
636
+ @on_pause = tpause
637
+ end
638
+ return self
639
+ end
640
+
641
+ #===入力待ち状態を解除する
642
+ #同時に、ポーズカーソルを隠蔽する。pause?メソッドの結果がfalseになる
643
+ #返却値:: 自分自身を返す
644
+ def release
645
+ @waiting = false
646
+ @on_release.call
647
+ return self
648
+ end
649
+
650
+ #===ポーズ解除時に行う処理を記述したブロックを登録する
651
+ #処理を行うブロックはオブジェクトとして渡す。
652
+ #ブロック引数の時は、そのブロックを処理している間のみ、そのオブジェクトを呼び出して処理させる
653
+ #_event_:: ポーズ解除時処理するブロック
654
+ #返却値:: 自分自身を返す
655
+ def on_release=(event)
656
+ trelease = @on_release
657
+ @on_release = event
658
+ if block_given?
659
+ yield
660
+ @on_release = trelease
661
+ end
662
+ return self
663
+ end
664
+
665
+ #===入力待ち状態かを確認する
666
+ #返却値:: 入力待ち状態の時はtrueを返す
667
+ def pause?
668
+ return @waiting
669
+ end
670
+
671
+ #===コマンド選択中かどうかを確認する
672
+ #返却値:: 選択中の時はtrueを返す
673
+ def selecting?
674
+ return @selecting
675
+ end
676
+
677
+ #===選択結果を取得する
678
+ #返却値:: コマンドの選択結果(選択中のnilを返す)
679
+ def result
680
+ return @choices.result
681
+ end
682
+
683
+ #===テキストエリアに描画している文字を消去する
684
+ #透明色で消去したあと、描画開始位置を左上(0,0)に移動する
685
+ #返却値:: 自分自身を返す
686
+ def clear
687
+ @textarea.bitmap.fillRect(0, 0, @size[0], @size[1], [0, 0, 0, 0])
688
+ @locate = Point.new(0, 0)
689
+ @max_height = @font.line_height
690
+ Fiber.yield if @fiber
691
+ return self
692
+ end
693
+
694
+ #===縦方向のスペースを空ける
695
+ #現在描画可能な位置から、指定したピクセルで下方向に移動する
696
+ #但し、文字の大きさもピクセル数に含むことに注意すること
697
+ #_height_:: スペースを空けるピクセル数
698
+ #返却値:: 自分自身を返す
699
+ def cr(height = @max_height)
700
+ @locate.x = 0
701
+ @locate.y += height
702
+ @max_height = @font.line_height
703
+ Fiber.yield if @fiber
704
+ return self
705
+ end
706
+
707
+ #===横方向のスペースを空ける
708
+ #現在描画可能な位置から、指定したピクセルで右方向に移動する
709
+ #_length_:: スペースを空けるピクセル数
710
+ #返却値:: 自分自身を返す
711
+ def space(length)
712
+ @locate.x += length
713
+ Fiber.yield if @fiber
714
+ return self
715
+ end
716
+
717
+ #===情報を解放する
718
+ def dispose
719
+ @textarea.dispose
720
+ @textarea = nil
721
+ end
722
+
723
+ def_delegators(:@pos, :x, :y)
724
+ end
725
+ end