cyross-ruby-miyako 2.0.0 → 2.0.5.1.0

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 (102) hide show
  1. data/README +106 -154
  2. data/defines.h +144 -0
  3. data/{miyako_no_katana/extconf.rb → extconf.rb} +10 -0
  4. data/extern.h +29 -0
  5. data/install_miyako.rb +26 -14
  6. data/lib/Miyako/API/audio.rb +2 -2
  7. data/lib/Miyako/API/basic_data.rb +183 -41
  8. data/lib/Miyako/API/bitmap.rb +474 -2
  9. data/lib/Miyako/API/choices.rb +215 -48
  10. data/lib/Miyako/API/collision.rb +267 -251
  11. data/lib/Miyako/API/diagram.rb +58 -70
  12. data/lib/Miyako/API/drawing.rb +93 -52
  13. data/lib/Miyako/API/fixedmap.rb +233 -120
  14. data/lib/Miyako/API/font.rb +59 -40
  15. data/lib/Miyako/API/input.rb +34 -27
  16. data/lib/Miyako/API/layout.rb +154 -172
  17. data/lib/Miyako/API/map.rb +285 -159
  18. data/lib/Miyako/API/map_event.rb +4 -4
  19. data/lib/Miyako/API/modules.rb +1 -1
  20. data/lib/Miyako/API/movie.rb +8 -5
  21. data/lib/Miyako/API/parts.rb +44 -9
  22. data/lib/Miyako/API/plane.rb +37 -2
  23. data/lib/Miyako/API/screen.rb +90 -22
  24. data/lib/Miyako/API/shape.rb +118 -37
  25. data/lib/Miyako/API/sprite.rb +475 -61
  26. data/lib/Miyako/API/sprite_animation.rb +83 -63
  27. data/lib/Miyako/API/spriteunit.rb +47 -13
  28. data/lib/Miyako/API/story.rb +123 -47
  29. data/lib/Miyako/API/textbox.rb +361 -132
  30. data/lib/Miyako/API/utility.rb +388 -0
  31. data/lib/Miyako/API/viewport.rb +54 -349
  32. data/lib/Miyako/API/yuki.rb +570 -353
  33. data/lib/Miyako/EXT/miyako_cairo.rb +5 -3
  34. data/lib/Miyako/EXT/slides.rb +22 -1
  35. data/lib/Miyako/miyako.rb +12 -13
  36. data/logo/EGSR_logo.png +0 -0
  37. data/logo/EGSR_logo_bg.png +0 -0
  38. data/logo/EGSR_logo_fg.png +0 -0
  39. data/logo/EGSR_title_banner.png +0 -0
  40. data/logo/EGSR_title_logo.png +0 -0
  41. data/logo/miyako.png +0 -0
  42. data/logo/miyako_banner.png +0 -0
  43. data/logo/space.png +0 -0
  44. data/miyako_basicdata.c +590 -0
  45. data/miyako_bitmap.c +1225 -0
  46. data/miyako_collision.c +403 -0
  47. data/miyako_drawing.c +187 -0
  48. data/miyako_font.c +334 -0
  49. data/miyako_hsv.c +830 -0
  50. data/miyako_layout.c +191 -0
  51. data/miyako_no_katana.c +1074 -0
  52. data/miyako_transform.c +438 -0
  53. data/miyako_utility.c +288 -0
  54. data/sample/Animation1/m1ku.rb +10 -31
  55. data/sample/Animation1/readme.txt +6 -6
  56. data/sample/Animation2/lex.rb +1 -0
  57. data/sample/Animation2/readme.txt +6 -6
  58. data/sample/Diagram_sample/diagram_sample_yuki2.rb +152 -48
  59. data/sample/Diagram_sample/readme.txt +9 -6
  60. data/sample/Room3/blue.rb +234 -187
  61. data/sample/Room3/ending.rb +68 -63
  62. data/sample/Room3/green.rb +159 -124
  63. data/sample/Room3/main.rb +50 -32
  64. data/sample/Room3/main_component.rb +3 -2
  65. data/sample/Room3/readme.txt +6 -6
  66. data/sample/Room3/red.rb +161 -134
  67. data/sample/Room3/room3.rb +1 -0
  68. data/sample/Room3/title.rb +75 -62
  69. data/sample/ball_action_sample.rb +204 -0
  70. data/sample/blit_rop.rb +70 -0
  71. data/sample/cairo_sample.rb +25 -0
  72. data/sample/circle_collision_test.rb +66 -0
  73. data/sample/collision_test.rb +33 -0
  74. data/sample/collision_test2.rb +108 -0
  75. data/sample/fixed_map_test/fixed_map_sample.rb +23 -32
  76. data/sample/fixed_map_test/readme.txt +38 -38
  77. data/sample/map_test/chara.rb +17 -9
  78. data/sample/map_test/main_parts.rb +30 -9
  79. data/sample/map_test/main_scene.rb +57 -41
  80. data/sample/map_test/map_manager.rb +13 -30
  81. data/sample/map_test/map_test.rb +2 -2
  82. data/sample/map_test/oasis.rb +17 -11
  83. data/sample/map_test/readme.txt +50 -48
  84. data/sample/map_test/route.rb +46 -33
  85. data/sample/map_test/town.rb +19 -13
  86. data/sample/polygon_test.rb +35 -0
  87. data/sample/rasterscroll.rb +25 -0
  88. data/sample/takahashi.rb +42 -0
  89. data/sample/text.png +0 -0
  90. data/sample/textbox_sample.rb +190 -0
  91. data/sample/transform.rb +54 -0
  92. data/sample/utility_test.rb +73 -0
  93. data/sample/utility_test2.rb +61 -0
  94. data/sample/utility_test3.rb +64 -0
  95. data/sample/utility_test4.rb +73 -0
  96. data/uninstall_miyako.rb +19 -0
  97. data/win/miyako_no_katana.so +0 -0
  98. metadata +165 -148
  99. data/miyako.png +0 -0
  100. data/miyako_banner.png +0 -0
  101. data/miyako_no_katana/miyako_no_katana.c +0 -3301
  102. data/sample/fixed_map_test/map_sample.rb +0 -121
@@ -2,7 +2,7 @@
2
2
  =begin
3
3
  --
4
4
  Miyako v2.0
5
- Copyright (C) 2007-2008 Cyross Makoto
5
+ Copyright (C) 2007-2009 Cyross Makoto
6
6
 
7
7
  This library is free software; you can redistribute it and/or
8
8
  modify it under the terms of the GNU Lesser General Public
@@ -22,10 +22,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
22
 
23
23
  module Miyako
24
24
  #==選択肢構造体
25
- #選択肢を構成する要素の集合
25
+ # 選択肢を構成する要素の集合
26
26
  #
27
- #複数のChoice構造体のインスタンスをまとめて、配列として構成されている
28
- #選択肢を表示させるときは、body 自体の表示位置を変更させる必要がある
27
+ # 複数のChoice構造体のインスタンスをまとめて、配列として構成されている
28
+ # 選択肢を表示させるときは、body 自体の表示位置を変更させる必要がある
29
29
  #
30
30
  #_body_:: 選択肢を示す画像
31
31
  #_body_selected_:: 選択肢を示す画像(選択時)
@@ -37,10 +37,14 @@ module Miyako
37
37
  #_up_:: 上方向を選択したときに参照するChoice構造体のインスタンス
38
38
  #_down_:: 下方向を選択したときに参照するChoice構造体のインスタンス
39
39
  #_base_:: 構造体が要素となっている配列
40
- Choice = Struct.new(:body, :body_selected, :condition, :selected, :result, :left, :right, :up, :down, :base)
40
+ #_attribute_:: 属性を示すハッシュ
41
+ #_end_select_proc_:: この選択肢を選択したときに優先的に処理するブロック。
42
+ #ブロックは1つの引数を取る(コマンド選択テキストボックス))。
43
+ #デフォルトはnil(何もしない)
44
+ Choice = Struct.new(:body, :body_selected, :condition, :selected, :result, :left, :right, :up, :down, :base, :attribute, :end_select_proc)
41
45
 
42
46
  #==選択肢を管理するクラス
43
- #選択肢は、Shapeクラスから生成したスプライトもしくは画像で構成される
47
+ # 選択肢は、Shapeクラスから生成したスプライトもしくは画像で構成される
44
48
  class Choices
45
49
  include Layout
46
50
  include SpriteBase
@@ -48,18 +52,34 @@ module Miyako
48
52
  include Enumerable
49
53
  extend Forwardable
50
54
 
55
+ attr_accessor :visible #レンダリングの可否(true->描画 false->非描画)
56
+
51
57
  # インスタンスを生成する
52
58
  # 返却値:: 生成された Choices クラスのインスタンス
53
59
  def initialize
60
+ init_layout
54
61
  @choices = []
55
62
  @now = nil
56
63
  @non_select = false
57
64
  @last_selected = nil
65
+ @result = nil
66
+ @visible = true
67
+ set_layout_size(1, 1)
68
+ end
69
+
70
+ def update_layout_position #:nodoc:
71
+ dx = @layout.pos[0] - rect[0]
72
+ dy = @layout.pos[1] - rect[1]
73
+ @choices.each{|ch|
74
+ ch.each{|cc|
75
+ cc.body.move(dx, dy)
76
+ cc.body_selected.move(dx, dy) if cc.body_selected && cc.body != cc.body_selected
77
+ }
78
+ }
58
79
  end
59
80
 
60
81
  # 選択肢を作成する
61
82
  # Choice 構造体のインスタンスを作成する
62
- #
63
83
  # 構造体には、引数bodyと、必ず true を返す条件ブロックが登録されている。残りは nil
64
84
  #_body_:: 選択肢を示す画像
65
85
  #_body_selected_:: 選択肢を示す画像(選択時)。デフォルトはnil
@@ -67,7 +87,7 @@ module Miyako
67
87
  #返却値:: 生成された Choice構造体のインスタンス
68
88
  def Choices.create_choice(body, body_selected = nil, selected = false)
69
89
  choice = Choice.new(body, body_selected, Proc.new{ true }, selected,
70
- nil, nil, nil, nil, nil, nil)
90
+ nil, nil, nil, nil, nil, nil, {}, nil)
71
91
  choice.left = choice
72
92
  choice.right = choice
73
93
  choice.up = choice
@@ -80,6 +100,8 @@ module Miyako
80
100
  choices.each{|v| v.base = choices}
81
101
  @choices.push(choices)
82
102
  @last_selected = @choices[0][0] if (@choices.length == 1 && @last_selcted == nil)
103
+ rect = self.broad_rect
104
+ set_layout_size(rect.w, rect.h)
83
105
  return self
84
106
  end
85
107
 
@@ -96,32 +118,76 @@ module Miyako
96
118
 
97
119
  def_delegators(:@choices, :push, :pop, :shift, :unshift, :[], :[]=, :clear, :length)
98
120
 
121
+ #===選択を開始しているかどうかを問い合わせる
122
+ # start_choiceメソッドを呼び出して、コマンド選択が始まっているかどうかを問い合わせ、始まっているときはtrueを返す
123
+ #返却値:: 選択を開始しているときはtrueを返す
124
+ def choicing?
125
+ return @now != nil
126
+ end
127
+
99
128
  #===選択を開始する
100
- #選択肢の初期位置を指定することができる
129
+ # 選択肢の初期位置を指定することができる
130
+ # 第1引数にnilを渡すと、最後に選択した選択肢が最初に選択状態にある選択肢となる
131
+ # (例)
132
+ # choices.start_choice # [0][0]で示す位置の選択肢を選択する
133
+ # choices.start_choice(5,1) # [5][1]で示す位置の選択肢を選択する
134
+ # choices.start_choice(nil) # 最後に選択した選択肢を選択する(未選択だったときは全省略時の呼び出しと等価)
101
135
  #_x_:: 初期位置(x 座標)。規定値は 0。nilを渡すと、最後に選択した選択肢が選ばれる。
102
136
  #_y_:: 初期位置(y 座標)。規定値は 0
103
137
  def start_choice(x = 0, y = 0)
104
- raise MiyakoError, "Illegal choice position! [#{x}][#{y}]" if (x != nil && x < 0 || x >= @choices.length || y < 0 || y >= @choices[x].length)
138
+ raise MiyakoError, "Illegal choice position! [#{x}][#{y}]" if (x != nil && (x < 0 || x >= @choices.length || y < 0 || y >= @choices[x].length))
105
139
  @now = x ? @choices[x][y] : @last_selected
106
140
  @now.selected = true
107
141
  @last_selected = @now
108
142
  @non_select = false
143
+ @result = nil
144
+ end
145
+
146
+ #===選択を終了する
147
+ # 選択の終了処理を行う
148
+ # 引数に選択に使用したテキストボックスを渡し、選択状態にあるしたChoice構造体に
149
+ #end_select_procブロックを渡しているとき、そのブロックを評価する
150
+ # (そのとき、引数とした渡ってきたテキストボックスをブロック引数に取る)。
151
+ #
152
+ #_command_box_:: 選択に使用したテキストボックス。デフォルトはnil
153
+ def end_choice(command_box = nil)
154
+ return unless @now
155
+ return @now.end_select_proc.call(command_box) if (command_box != nil && @now.end_select_proc != nil)
156
+ @result = @now.result
157
+ @now.selected = false
158
+ @last_selected = @now
159
+ @now = nil
160
+ @non_select = true
109
161
  end
110
162
 
111
163
  #===選択肢本体を取得する
112
- #選択肢の表示対象となる
113
- #返却値::
164
+ # 選択肢の表示対象となるインスタンスを取得する
165
+ # Choice構造体にbody_selectedが設定されている時はbody_selected、そうでなければbodyを返す
166
+ # まだ選択が開始されていなければnilが返る
167
+ #返却値:: 選択肢本体(選択時)
114
168
  def body
169
+ return nil unless @now
115
170
  return @now.body_selected ? @now.body_selected : @now.body
116
171
  end
117
172
 
118
173
  #===選択結果を取得する
119
- #現在の選択肢が所持している結果インスタンスを返す
174
+ # 現在の選択肢が所持している結果インスタンスを返す
175
+ # まだ選択が開始されていなければnilが返る
120
176
  #返却値:: 選択結果
121
177
  def result
178
+ return @result unless @now
122
179
  return @now.result
123
180
  end
124
181
 
182
+ #===現在選択している選択肢の属性をアクセスする
183
+ # 属性を編集・参照できるハッシュを取得する
184
+ # まだ選択が開始されていなければnilが返る
185
+ #返却値:: 属性(対応するChoice#attributeメソッドの値)
186
+ def attribute
187
+ return nil unless @now
188
+ return @now.attribute
189
+ end
190
+
125
191
  def update_choices(org, nxt) #:nodoc:
126
192
  obase = org.base
127
193
  nbase = nxt.base
@@ -143,27 +209,73 @@ module Miyako
143
209
  #現在の選択状態を、全部選択していない状態にする
144
210
  #返却値:: 自分自身を返す
145
211
  def non_select
146
- @now.base.each{|c| c.selected = false }
212
+ @now.base.each{|c| c.selected = false } if @now
147
213
  @non_select = true
148
214
  return self
149
215
  end
150
216
 
217
+ #===選択肢が選択状態かを問い合わせる
218
+ #現在、選択肢が選択状態か非選択状態(non_selectメソッド呼び出しなど)かを問い合わせる
219
+ #返却値:: 選択状態ならtrue、非選択状態ならfalseを返す
220
+ def any_select?
221
+ return !@non_select
222
+ end
223
+
151
224
  #===選択肢を変更する
152
- #現在の選択状態を、全部選択していない状態にする
225
+ #指定の位置の現在の選択状態を、選択状態にする
153
226
  #_x_:: x方向位置
154
227
  #_y_:: y方向位置
155
228
  #返却値:: 自分自身を返す
156
229
  def select(x, y)
230
+ raise MiyakoError, "Not select yet!" unless @now
157
231
  raise MiyakoError, "Illegal choice position! [#{x}][#{y}]" if (x < 0 || x >= @choices.length || y < 0 || y >= @choices[x].length)
158
- @now = @choices[x][y]
232
+ @non_select = false
233
+ @last_selected = @now
234
+ @now.selected = false
235
+ obj = @choices[x][y]
236
+ update_choices(@now, obj)
237
+ @now = obj
238
+ @now.selected = true
159
239
  return self
160
240
  end
161
241
 
242
+ #===画面上の座標から、該当する選択肢を変更する
243
+ #マウスカーソル位置などの座標から、座標を含む選択肢を選択状態にする
244
+ #該当する場所が無ければfalseを返す
245
+ #まだ選択を開始していないときはfalseを返す
246
+ #_x_:: x方向位置
247
+ #_y_:: y方向位置
248
+ #返却値:: 選択肢が見つかったときはtrue、見つからなかったときはfalseを返す
249
+ def attach(x, y)
250
+ return false unless @now
251
+ obj = @now.base.detect{|ch| ch.selected ? ch.body_selected.broad_rect.in_range?(x, y) : ch.body.broad_rect.in_range?(x, y) }
252
+ return false unless obj
253
+ @non_select = false
254
+ @last_selected = @now
255
+ @now.selected = false
256
+ update_choices(@now, obj)
257
+ @now = obj
258
+ @now.selected = true
259
+ return true
260
+ end
261
+
262
+ #===画面上の座標から、該当する選択肢があるかどうかを問い合わせる
263
+ #マウスカーソル位置などの座標から、座標を含む選択肢があるときはtrue、無いときはfalseを返す
264
+ #まだ選択を開始していないときはfalseを返す
265
+ #_x_:: x方向位置
266
+ #_y_:: y方向位置
267
+ #返却値:: 選択肢が見つかったときはtrue、見つからなかったときはfalseを返す
268
+ def attach?(x, y)
269
+ return false unless @now
270
+ obj = @now.base.detect{|ch| ch.selected ? ch.body_selected.broad_rect.in_range?(x, y) : ch.body.broad_rect.in_range?(x, y) }
271
+ return obj ? true : false
272
+ end
273
+
162
274
  #===選択肢を非選択状態に変更する
163
275
  #現在の選択状態を、全部選択していない状態にする
164
276
  #返却値:: 自分自身を返す
165
277
  def non_select
166
- @now.base.each{|c| c.selected = false }
278
+ @now.base.each{|c| c.selected = false } if @now
167
279
  @non_select = true
168
280
  return self
169
281
  end
@@ -172,8 +284,11 @@ module Miyako
172
284
  #現在表示できる選択肢を、現在の状態で描画するよう指示する
173
285
  #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
174
286
  #ブロックの引数は、|インスタンスのSpriteUnit, 画面のSpriteUnit|となる。
287
+ #visibleメソッドの値がfalseのとき、選択が開始されていない時は描画されない。
175
288
  #返却値:: 自分自身を返す
176
289
  def render(&block)
290
+ return unless @visible
291
+ return self unless @now
177
292
  @now.base.each{|c|
178
293
  ((c.body_selected && c.selected) ?
179
294
  c.body_selected.render(&block) :
@@ -186,9 +301,12 @@ module Miyako
186
301
  #現在表示できる選択肢を、現在の状態で描画するよう指示する
187
302
  #ブロック付きで呼び出し可能(レシーバに対応したSpriteUnit構造体が引数として得られるので、補正をかけることが出来る。
188
303
  #ブロックの引数は、|インスタンスのSpriteUnit, 画像のSpriteUnit|となる。
304
+ #visibleメソッドの値がfalseのとき、選択が開始されていない時は描画されない。
189
305
  #_dst_:: 描画対象の画像インスタンス
190
306
  #返却値:: 自分自身を返す
191
307
  def render_to(dst, &block)
308
+ return self unless @visible
309
+ return self unless @now
192
310
  @now.base.each{|c|
193
311
  ((c.body_selected && c.selected) ?
194
312
  c.body_selected.render_to(dst, &block) :
@@ -199,35 +317,55 @@ module Miyako
199
317
 
200
318
  #===スプライトに変換した画像を表示する
201
319
  #すべてのパーツを貼り付けた、1枚のスプライトを返す
320
+ #引数1個のブロックを渡せば、スプライトに補正をかけることが出来る
321
+ #ただし、選択が開始されていなければnilを返す
202
322
  #返却値:: 生成したスプライト
203
323
  def to_sprite
324
+ return nil unless @now
204
325
  rect = self.broad_rect
205
326
  sprite = Sprite.new(:size=>rect.to_a[2,2], :type=>:ac)
327
+ Drawing.fill(sprite, [0,0,0])
328
+ Bitmap.ck_to_ac!(sprite, [0,0,0])
206
329
  self.render_to(sprite){|sunit, dunit| sunit.x -= rect.x; sunit.y -= rect.y }
330
+ yield sprite if block_given?
207
331
  return sprite
208
332
  end
209
333
 
210
- #===現在の画面の最大の大きさを矩形で取得する
211
- #選択肢の状態により、取得できる矩形の大きさが変わる
212
- #但し、選択肢が一つも見つからなかったときはnilを返す
334
+ #===現在登録している選択肢の最大の大きさを矩形で取得する
335
+ # 現在インスタンスが所持している選択肢全てから左上座標、右下座標を取得し、矩形の形式で返す
336
+ # 但し、選択肢が一つも登録されていない時はRect(0,0,1,1)を返す
213
337
  #返却値:: 生成された矩形(Rect構造体のインスタンス)
214
338
  def broad_rect
215
- choice_list = @now.base.find_all{|c| c.condition.call }.map{|c| (c.body_selected && c.selected) ? c.body_selected : c.body}
216
- return nil if choice_list.length == 0
217
- return Rect.new(*(choice_list[0].rect.to_a)) if choice_list.length == 1
218
- rect = choice_list.shift.to_a
219
- rect_list = rect.zip(*(choice_list.map{|c| c.broad_rect.to_a}))
220
- # width -> right
221
- rect_list[2] = rect_list[2].zip(rect_list[0]).map{|xw| xw[0] + xw[1]}
222
- # height -> bottom
223
- rect_list[3] = rect_list[3].zip(rect_list[1]).map{|xw| xw[0] + xw[1]}
224
- x, y = rect_list[0].min, rect_list[1].min
225
- return Rect.new(x, y, rect_list[2].max - x, rect_list[3].max - y)
226
- end
227
-
228
- # 選択肢を左移動させる
339
+ return Rect.new(0, 0, 1, 1) if @choices.length == 0
340
+ xx = []
341
+ yy = []
342
+ @choices.each{|ch|
343
+ ch.each{|cc|
344
+ xx << cc.body.x
345
+ yy << cc.body.y
346
+ if cc.body_selected
347
+ xx << cc.body_selected.x
348
+ yy << cc.body_selected.y
349
+ end
350
+ }
351
+ }
352
+ min_x, max_x = xx.minmax
353
+ min_y, max_y = yy.minmax
354
+ return Rect.new(min_x, min_y, max_x-min_x+1, max_y-min_y+1)
355
+ end
356
+
357
+ #===現在登録している選択肢の大きさを矩形で取得する
358
+ # 内容はbroad_rectメソッドの結果と同じ
359
+ #返却値:: 生成された矩形(Rect構造体のインスタンス)
360
+ def rect
361
+ return self.broad_rect
362
+ end
363
+
364
+ #===選択肢を左移動させる
365
+ # 但し、まだ選択が開始されていなければ何もしない
229
366
  # 返却値:: 自分自身を返す
230
- def left
367
+ def left_choice
368
+ return self unless @now
231
369
  @last_selected = @now
232
370
  @now.selected = false
233
371
  obj = @now.left
@@ -237,9 +375,11 @@ module Miyako
237
375
  return self
238
376
  end
239
377
 
240
- # 選択肢を右移動させる
378
+ #===選択肢を右移動させる
379
+ # 但し、まだ選択が開始されていなければ何もしない
241
380
  # 返却値:: 自分自身を返す
242
- def right
381
+ def right_choice
382
+ return self unless @now
243
383
  @last_selected = @now
244
384
  @now.selected = false
245
385
  obj = @now.right
@@ -249,9 +389,11 @@ module Miyako
249
389
  return self
250
390
  end
251
391
 
252
- # 選択肢を上移動させる
392
+ #===選択肢を上移動させる
393
+ # 但し、まだ選択が開始されていなければ何もしない
253
394
  # 返却値:: 自分自身を返す
254
- def up
395
+ def up_choice
396
+ return self unless @now
255
397
  @last_selected = @now
256
398
  @now.selected = false
257
399
  obj = @now.up
@@ -261,9 +403,11 @@ module Miyako
261
403
  return self
262
404
  end
263
405
 
264
- # 選択肢を下移動させる
406
+ #===選択肢を下移動させる
407
+ # 但し、まだ選択が開始されていなければ何もしない
265
408
  # 返却値:: 自分自身を返す
266
- def down
409
+ def down_choice
410
+ return self unless @now
267
411
  @last_selected = @now
268
412
  @now.selected = false
269
413
  obj = @now.down
@@ -273,31 +417,54 @@ module Miyako
273
417
  return self
274
418
  end
275
419
 
276
- # 選択肢のアニメーションを開始する
420
+ #===選択肢のアニメーションを開始する
421
+ # 但し、まだ選択が開始されていなければ何もしない
277
422
  # 返却値:: 自分自身を返す
278
423
  def start
279
- @now.base.each{|c| c.body.start if c.condition.call }
424
+ return self unless @now
425
+ @now.base.each{|c|
426
+ if c.condition.call
427
+ c.body.start
428
+ c.body_selected.start if c.body != c.body_selected
429
+ end
430
+ }
280
431
  return self
281
432
  end
282
433
 
283
- # 選択肢のアニメーションを終了させる
434
+ #===選択肢のアニメーションを終了させる
435
+ # 但し、まだ選択が開始されていなければ何もしない
284
436
  # 返却値:: 自分自身を返す
285
437
  def stop
286
- @now.base.each{|c| c.body.stop if c.condition.call }
438
+ return self unless @now
439
+ @now.base.each{|c|
440
+ if c.condition.call
441
+ c.body.stop
442
+ c.body_selected.stop if c.body != c.body_selected
443
+ end
444
+ }
287
445
  return self
288
446
  end
289
447
 
290
- # 選択肢のアニメーションの再生位置を最初に戻す
448
+ #===選択肢のアニメーションの再生位置を最初に戻す
449
+ # 但し、まだ選択が開始されていなければ何もしない
291
450
  # 返却値:: 自分自身を返す
292
451
  def reset
293
- @now.base.each{|c| c.body.reset if c.condition.call }
452
+ return self unless @now
453
+ @now.base.each{|c|
454
+ if c.condition.call
455
+ c.body.reset
456
+ c.body_selected.reset if c.body != c.body_selected
457
+ end
458
+ }
294
459
  return self
295
460
  end
296
461
 
297
- # 選択肢のアニメーションを更新させる
462
+ #===選択肢のアニメーションを更新させる
298
463
  # (手動で更新する必要があるときに呼び出す)
464
+ # 但し、まだ選択が開始されていなければ何もしない
299
465
  # 返却値:: 自分自身を返す
300
466
  def update_animation
467
+ return self unless @now
301
468
  @now.base.each{|c|
302
469
  ((c.body_selected && c.selected) ?
303
470
  c.body_selected.update_animation :
@@ -2,7 +2,7 @@
2
2
  =begin
3
3
  --
4
4
  Miyako v2.0
5
- Copyright (C) 2007-2008 Cyross Makoto
5
+ Copyright (C) 2007-2009 Cyross Makoto
6
6
 
7
7
  This library is free software; you can redistribute it and/or
8
8
  modify it under the terms of the GNU Lesser General Public
@@ -21,135 +21,74 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
21
  =end
22
22
 
23
23
  module Miyako
24
- #==当たり判定領域(コリジョン)クラス
25
- #コリジョンの範囲は、元データ(スプライト等)の左上端を[0,0]として考案する
26
- #本クラスに設定できる方向(direction)・移動量(amount)は、コリジョンの範囲・位置に影響しない
24
+ #==矩形当たり判定領域(コリジョン)クラス
25
+ # コリジョンの範囲は、元データ(スプライト等)の左上端を[0.0,0.0]として考案する
26
+ # コリジョンで使用する値は、実数での設定が可能
27
27
  class Collision
28
28
  extend Forwardable
29
29
 
30
30
  # コリジョンの範囲([x,y,w,h])
31
- attr_accessor :rect
32
- # 元データの位置([x,y])
33
- attr_accessor :pos
34
- # 移動方向([dx,dy], dx,dy:-1,0,1)
35
- attr_accessor :direction
36
- # 移動量([w,h])
37
- attr_accessor :amount
31
+ attr_reader :rect
32
+ # 移動時イベントブロック配列
38
33
 
39
34
  #===コリジョンのインスタンスを作成する
35
+ # 幅・高さが0以下のときは例外が発生する
36
+ # 内部では、矩形当たり判定相手の時でも対応できるように矩形情報に変換して同時に持っている。
37
+ # そのとき、引数circumがtrueのときは、円を矩形の外接円と認識して、内部の矩形(正方形)の長さを算出する。
38
+ # circumがfalseのときは、円を矩形の内接円と認識して、内部の矩形(正方形)の長さを算出する。
40
39
  #_rect_:: コリジョンを設定する範囲
41
- #_pos_:: 元データの位置
40
+ #_circum_:: 矩形当たり判定とみなす時、円を外接円とするときはtrueを設定する。デフォルトはtrue
42
41
  #返却値:: 作成されたコリジョン
43
- def initialize(rect, pos)
42
+ def initialize(rect, circum = true)
44
43
  @rect = Rect.new(*(rect.to_a[0..3]))
45
- @pos = Point.new(*(pos.to_a[0..1]))
46
- @direction = Point.new(0, 0)
47
- @amount = Size.new(0, 0)
48
- end
49
-
50
- #===コリジョンの方向を転換する
51
- #_dx_:: 変換する方向(x軸方向、-1,0,1の3種類)
52
- #_dy_:: 変換する方向(y軸方向、-1,0,1の3種類)
53
- #返却値:: 自分自身を返す
54
- def turn(dx, dy)
55
- @direction = Point.new(dx, dy)
56
- return self
57
- end
58
-
59
- #===コリジョンの移動量を変更する
60
- #_mx_:: 変更する移動量(x軸方向)
61
- #_my_:: 変更する移動量(y軸方向)
62
- #返却値:: 自分自身を返す
63
- def adjust(mx, my)
64
- @amount = Size.new(mx, my)
65
- return self
44
+ raise MiyakoError, "Illegal width! #{@rect[2]}" if @rect[2] < Float::EPSILON
45
+ raise MiyakoError, "Illegal height! #{@rect[3]}" if @rect[3] < Float::EPSILON
46
+ w = @rect[2].to_f
47
+ h = @rect[2].to_f
48
+ @center = Point.new(@rect[0].to_f + w / 2.0, @rect[1].to_f + h / 2.0)
49
+ @radius = circum ? Math.sqrt(w ** 2 + h ** 2) / 2.0 : [w, h].min / 2.0
66
50
  end
67
51
 
68
52
  #===当たり判定を行う(領域が重なっている)
53
+ #_pos1_:: 自分自身の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
69
54
  #_c2_:: 判定対象のコリジョンインスタンス
55
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
70
56
  #返却値:: 1ピクセルでも重なっていれば true を返す
71
- def collision?(c2)
72
- return Collision.collision?(self, c2)
57
+ def collision?(pos1, c2, pos2)
58
+ return Collision.collision?(self, pos1, c2, pos2)
73
59
  end
74
60
 
75
- #===当たり判定を行う(領域が当たっている(重なっていない))
61
+ #===当たり判定を行う(領域がピクセル単位で隣り合っている)
62
+ #_pos1_:: 自分自身の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
76
63
  #_c2_:: 判定対象のコリジョンインスタンス
77
- #返却値:: 領域が当たっていれば true を返す
78
- def meet?(c2)
79
- return Collision.meet?(self, c2)
80
- end
81
-
82
- #===当たり判定を行う(移動後に領域が重なっている(移動前は重なっていない))
83
- #_c2_:: 判定対象のコリジョンインスタンス
84
- #返却値:: 1ピクセルでも重なっていれば true を返す
85
- def into?(c2)
86
- return Collision.into?(self, c2)
87
- end
88
-
89
- #===当たり判定を行う(移動後に領域が離れている(移動前は重なっている))
90
- #_c2_:: 判定対象のコリジョンインスタンス
91
- #返却値:: 1ピクセルでも重なっていれば true を返す
92
- def out?(c2)
93
- return Collision.out?(self, c2)
64
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
65
+ #返却値:: 領域が隣り合っていれば true を返す
66
+ def meet?(pos1, c2, pos2)
67
+ return Collision.meet?(self, pos1, c2, pos2)
94
68
  end
95
69
 
96
70
  #===当たり判定を行う(どちらかの領域がもう一方にすっぽり覆われている))
71
+ #_pos1_:: 自分自身の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
97
72
  #_c2_:: 判定対象のコリジョンインスタンス
73
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
98
74
  #返却値:: 領域が覆われていれば true を返す
99
- def cover?(c2)
100
- return Collision.cover?(self, c2)
101
- end
102
-
103
- #===コリジョンをの位置を、指定の移動量で移動する
104
- #_x_:: 移動量(x方向)。単位はピクセル
105
- #_y_:: 移動量(y方向)。単位はピクセル
106
- #返却値:: 自分自身を返す
107
- def move(x, y)
108
- @pos.move(x, y)
109
- return self
110
- end
111
-
112
- #===コリジョンをの位置を、指定の位置へ移動する
113
- #_x_:: 移動先の位置(x方向)。単位はピクセル
114
- #_y_:: 移動先の位置(y方向)。単位はピクセル
115
- #返却値:: 自分自身を返す
116
- def move_to(x, y)
117
- @pos.move_to(x, y)
118
- return self
75
+ def cover?(pos1, c2, pos2)
76
+ return Collision.cover?(self, pos1, c2, pos2)
119
77
  end
120
78
 
121
79
  #===当たり判定を行う(領域が重なっている)
122
80
  #_c1_:: 判定対象のコリジョンインスタンス(1)
81
+ #_pos1_:: c1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
123
82
  #_c2_:: 判定対象のコリジョンインスタンス(2)
83
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
124
84
  #返却値:: 1ピクセルでも重なっていれば true を返す
125
- def Collision.collision?(c1, c2)
126
- l1 = c1.pos[0] + c1.rect[0]
127
- t1 = c1.pos[1] + c1.rect[1]
128
- r1 = l1 + c1.rect[2] - 1
129
- b1 = t1 + c1.rect[3] - 1
130
- l2 = c2.pos[0] + c2.rect[0]
131
- t2 = c2.pos[1] + c2.rect[1]
132
- r2 = l2 + c2.rect[2] - 1
133
- b2 = t2 + c2.rect[3] - 1
134
- v = 0
135
- v |= 1 if l1 <= l2 && l2 <= r1
136
- v |= 1 if l1 <= r2 && r2 <= r1
137
- v |= 2 if t1 <= t2 && t2 <= b1
138
- v |= 2 if t1 <= b2 && b2 <= b1
139
- return v == 3
140
- end
141
-
142
- #===当たり判定を行う(移動後の領域が重なっている)
143
- #_c1_:: 判定対象のコリジョンインスタンス(1)
144
- #_c2_:: 判定対象のコリジョンインスタンス(2)
145
- #返却値:: 1ピクセルでも重なっていれば true を返す
146
- def Collision.collision_with_move?(c1, c2)
147
- l1 = c1.pos[0] + c1.rect[0] + c1.direction[0] * c1.amount[0]
148
- t1 = c1.pos[1] + c1.rect[1] + c1.direction[1] * c1.amount[1]
85
+ def Collision.collision?(c1, pos1, c2, pos2)
86
+ l1 = pos1[0] + c1.rect[0]
87
+ t1 = pos1[1] + c1.rect[1]
149
88
  r1 = l1 + c1.rect[2] - 1
150
89
  b1 = t1 + c1.rect[3] - 1
151
- l2 = c2.pos[0] + c2.rect[0] + c2.direction[0] * c2.amount[0]
152
- t2 = c2.pos[1] + c2.rect[1] + c2.direction[1] * c2.amount[1]
90
+ l2 = pos2[0] + c2.rect[0]
91
+ t2 = pos2[1] + c2.rect[1]
153
92
  r2 = l2 + c2.rect[2] - 1
154
93
  b2 = t2 + c2.rect[3] - 1
155
94
  v = 0
@@ -160,17 +99,19 @@ module Miyako
160
99
  return v == 3
161
100
  end
162
101
 
163
- #===当たり判定を行う(領域が当たっている(重なっていない))
102
+ #===当たり判定を行う(領域がピクセル単位で隣り合っている)
164
103
  #_c1_:: 判定対象のコリジョンインスタンス(1)
104
+ #_pos1_:: c1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
165
105
  #_c2_:: 判定対象のコリジョンインスタンス(2)
166
- #返却値:: 領域が当たっていれば true を返す
167
- def Collision.meet?(c1, c2)
168
- l1 = c1.pos[0] + c1.rect[0]
169
- t1 = c1.pos[1] + c1.rect[1]
106
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
107
+ #返却値:: 領域が隣り合っていれば true を返す
108
+ def Collision.meet?(c1, pos1, c2, pos2)
109
+ l1 = pos1[0] + c1.rect[0]
110
+ t1 = pos1[1] + c1.rect[1]
170
111
  r1 = l1 + c1.rect[2]
171
112
  b1 = t1 + c1.rect[3]
172
- l2 = c2.pos[0] + c2.rect[0]
173
- t2 = c2.pos[1] + c2.rect[1]
113
+ l2 = pos2[0] + c2.rect[0]
114
+ t2 = pos2[1] + c2.rect[1]
174
115
  r2 = l2 + c2.rect[2]
175
116
  b2 = t2 + c2.rect[3]
176
117
  v = 0
@@ -181,104 +122,231 @@ module Miyako
181
122
  return v == 1
182
123
  end
183
124
 
184
- #===当たり判定を行う(移動後に領域が重なっている(移動前は重なっていない))
125
+ #===当たり判定を行う(どちらかの領域がもう一方にすっぽり覆われている))
185
126
  #_c1_:: 判定対象のコリジョンインスタンス(1)
127
+ #_pos1_:: c1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
186
128
  #_c2_:: 判定対象のコリジョンインスタンス(2)
129
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
130
+ #返却値:: 領域が覆われていれば true を返す
131
+ def Collision.cover?(c1, pos1, c2, pos2)
132
+ l1 = pos1[0] + c1.rect[0]
133
+ t1 = pos1[1] + c1.rect[1]
134
+ r1 = l1 + c1.rect[2]
135
+ b1 = t1 + c1.rect[3]
136
+ l2 = pos2[0] + c2.rect[0]
137
+ t2 = pos2[1] + c2.rect[1]
138
+ r2 = l2 + c2.rect[2]
139
+ b2 = t2 + c2.rect[3]
140
+ v = 0
141
+ v |= 1 if l1 >= l2 && r2 <= r1
142
+ v |= 2 if t1 >= t2 && b2 <= b1
143
+ v |= 4 if l2 >= l1 && r1 <= r2
144
+ v |= 8 if t2 >= t1 && b1 <= b2
145
+ return v & 3 == 3 || v & 12 == 12
146
+ end
147
+
148
+ #== インスタンスの内容を解放する
149
+ #返却値:: なし
150
+ def dispose
151
+ @rect = nil
152
+ end
153
+ end
154
+
155
+ #==円形当たり判定領域(サークルコリジョン)クラス
156
+ # 円形の当たり判定を実装する。
157
+ # コリジョンは中心位置と半径で構成され、円形当たり判定同士で衝突判定を行う
158
+ # コリジョンで使用する値は、実数での設定が可能
159
+ class CircleCollision
160
+ extend Forwardable
161
+
162
+ # コリジョンの中心点([x,y])
163
+ attr_reader :center
164
+ # コリジョンの半径
165
+ attr_reader :radius
166
+ # 移動時イベントブロック配列
167
+
168
+ #===コリジョンのインスタンスを作成する
169
+ # コリジョンの半径が0もしくはマイナスのとき例外が発生する
170
+ # 内部では、矩形当たり判定相手の時でも対応できるように矩形情報に変換して同時に持っている。
171
+ # そのとき、引数circumがtrueのときは、円を矩形の外接円と認識して、内部の矩形(正方形)の長さを算出する。
172
+ # circumがfalseのときは、円を矩形の内接円と認識して、内部の矩形(正方形)の長さを算出する。
173
+ #_center_:: コリジョンを設定する範囲
174
+ #_radius_:: コリジョンの半径
175
+ #_circum_:: 矩形当たり判定とみなす時、円を外接円とするときはtrueを設定する。デフォルトはtrue
176
+ #返却値:: 作成されたコリジョン
177
+ def initialize(center, radius, circum = true)
178
+ raise MiyakoError, "illegal radius! #{radius}" if radius < Float::EPSILON
179
+ @center = Point.new(*(center.to_a[0..1]))
180
+ @radius = radius
181
+ if circum
182
+ rad = @radius.to_f / Math.sqrt(2.0)
183
+ @rect = Rect.new(@center[0]-rad, @center[1]-rad, rad*2.0, rad*2.0)
184
+ else
185
+ @rect = Rect.new(@center[0]-@radius, @center[1]-@radius, @radius*2.0, @radius*2.0)
186
+ end
187
+ end
188
+
189
+ #===当たり判定間の距離を算出する
190
+ #_pos1_:: 自分自身の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
191
+ #_c2_:: 判定対象のコリジョンインスタンス
192
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
193
+ #返却値:: 1ピクセルでも重なっていれば true を返す
194
+ def interval(pos1, c2, pos2)
195
+ return CircleCollision.interval(self, pos1, c2, pos2)
196
+ end
197
+
198
+ #===当たり判定を行う(領域が重なっている)
199
+ #_pos1_:: 自分自身の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
200
+ #_c2_:: 判定対象のコリジョンインスタンス
201
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
187
202
  #返却値:: 1ピクセルでも重なっていれば true を返す
188
- def Collision.into?(c1, c2)
189
- f1 = Collision.collision?(c1, c2)
190
- f2 = Collision.collision_with_move?(c1, c2)
191
- return !f1 & f2
203
+ def collision?(pos1, c2, pos2)
204
+ return CircleCollision.collision?(self, pos1, c2, pos2)
192
205
  end
193
206
 
194
- #===当たり判定を行う(移動後に領域が離れている(移動前は重なっている))
207
+ #===当たり判定を行う(領域がピクセル単位で隣り合っている)
208
+ #_pos1_:: 自分自身の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
209
+ #_c2_:: 判定対象のコリジョンインスタンス
210
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
211
+ #返却値:: 領域が隣り合っていれば true を返す
212
+ def meet?(pos1, c2, pos2)
213
+ return CircleCollision.meet?(self, pos1, c2, pos2)
214
+ end
215
+
216
+ #===当たり判定を行う(どちらかの領域がもう一方にすっぽり覆われている))
217
+ #_pos1_:: 自分自身の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
218
+ #_c2_:: 判定対象のコリジョンインスタンス
219
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
220
+ #返却値:: 領域が覆われていれば true を返す
221
+ def cover?(pos1, c2, pos2)
222
+ return CircleCollision.cover?(self, pos1, c2, pos2)
223
+ end
224
+
225
+ #===当たり判定間の距離を算出する
226
+ # 2つの当たり判定がどの程度離れているかを算出する。
227
+ # 返ってくる値は、衝突していなければ正の実数、衝突していれば負の実数で返ってくる
195
228
  #_c1_:: 判定対象のコリジョンインスタンス(1)
229
+ #_pos1_:: c1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
196
230
  #_c2_:: 判定対象のコリジョンインスタンス(2)
231
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
232
+ #返却値:: 当たり判定間の距離
233
+ def CircleCollision.interval(c1, pos1, c2, pos2)
234
+ #2点間の距離を求める
235
+ d = Math.sqrt((((c1.center[0].to_f + pos1[0].to_f) - (c2.center[0].to_f + pos2[0].to_f)) ** 2) +
236
+ (((c1.center[1].to_f + pos1[1].to_f) - (c2.center[1].to_f + pos2[1].to_f)) ** 2))
237
+ #半径の和を求める
238
+ r = c1.radius.to_f + c2.radius.to_f
239
+ distance = d - r
240
+ return distance.abs < Float::EPSILON ? 0.0 : distance
241
+ end
242
+
243
+ #===当たり判定を行う(領域が重なっている)
244
+ #_c1_:: 判定対象のコリジョンインスタンス(1)
245
+ #_pos1_:: c1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
246
+ #_c2_:: 判定対象のコリジョンインスタンス(2)
247
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
197
248
  #返却値:: 1ピクセルでも重なっていれば true を返す
198
- def Collision.out?(c1, c2)
199
- f1 = Collision.collision?(c1, c2)
200
- f2 = Collision.collision_with_move?(c1, c2)
201
- return f1 & !f2
249
+ def CircleCollision.collision?(c1, pos1, c2, pos2)
250
+ #2点間の距離を求める
251
+ d = (((c1.center[0] + pos1[0]) - (c2.center[0] + pos2[0])) ** 2) +
252
+ (((c1.center[1] + pos1[1]) - (c2.center[1] + pos2[1])) ** 2)
253
+ #半径の和を求める
254
+ r = (c1.radius + c2.radius) ** 2
255
+ return d <= r
256
+ end
257
+
258
+ #===当たり判定を行う(領域がピクセル単位で隣り合っている)
259
+ # 但し、実際の矩形範囲が偶数の時は性格に判定できない場合があるため注意
260
+ #_c1_:: 判定対象のコリジョンインスタンス(1)
261
+ #_pos1_:: c1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
262
+ #_c2_:: 判定対象のコリジョンインスタンス(2)
263
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
264
+ #返却値:: 領域が隣り合っていれば true を返す
265
+ def CircleCollision.meet?(c1, pos1, c2, pos2)
266
+ #2点間の距離を求める
267
+ d = (((c1.center[0] + pos1[0]) - (c2.center[0] + pos2[0])) ** 2) +
268
+ (((c1.center[1] + pos1[1]) - (c2.center[1] + pos2[1])) ** 2)
269
+ #半径の和を求める
270
+ r = (c1.radius + c2.radius) ** 2
271
+ return d == r
202
272
  end
203
273
 
204
274
  #===当たり判定を行う(どちらかの領域がもう一方にすっぽり覆われている))
205
275
  #_c1_:: 判定対象のコリジョンインスタンス(1)
276
+ #_pos1_:: c1の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
206
277
  #_c2_:: 判定対象のコリジョンインスタンス(2)
278
+ #_pos2_:: c2の位置(Point/Rect/Square構造体、2要素以上の配列、もしくはx,yメソッドを持つインスタンス)
207
279
  #返却値:: 領域が覆われていれば true を返す
208
- def Collision.cover?(c1, c2)
209
- l1 = c1.pos[0] + c1.rect[0]
210
- t1 = c1.pos[1] + c1.rect[1]
211
- r1 = l1 + c1.rect[2]
212
- b1 = t1 + c1.rect[3]
213
- l2 = c2.pos[0] + c2.rect[0]
214
- t2 = c2.pos[1] + c2.rect[1]
215
- r2 = l2 + c2.rect[2]
216
- b2 = t2 + c2.rect[3]
217
- v = 0
218
- v |= 1 if l1 <= l2 && r2 <= r1
219
- v |= 2 if t1 <= t2 && b2 <= b1
220
- v |= 4 if l2 <= l1 && r1 <= r2
221
- v |= 8 if t2 <= t1 && b1 <= b2
222
- return v == 3 || v == 12
280
+ def CircleCollision.cover?(c1, pos1, c2, pos2)
281
+ #2点間の距離を求める
282
+ d = ((c1.center[0] + pos1[0]) - (c2.center[0] + pos2[0])) ** 2 +
283
+ ((c1.center[1] + pos1[1]) - (c2.center[1] + pos2[1])) ** 2
284
+ #半径の差分を求める
285
+ r = c1.radius ** 2 - 2 * (c1.radius * c2.radius) + c2.radius ** 2
286
+ return d <= r
223
287
  end
224
288
 
225
- #===あとで書く
226
- #返却値:: あとで書く
289
+ #== インスタンスの内容を解放する
290
+ #返却値:: なし
227
291
  def dispose
228
- @pos.clear
229
- @pos = nil
230
- @rect.clear
231
- @rect = nil
232
- @amount.clear
233
- @amount = nil
234
- @direction.clear
235
- @direction = nil
292
+ @point = nil
236
293
  end
237
294
  end
238
295
 
239
296
  #==コリジョン管理クラス
240
- #複数のコリジョンと元オブジェクトを配列の様に一括管理できる
241
- #当たり判定を一括処理することで高速化を図る
297
+ # 複数のコリジョンと元オブジェクトを配列の様に一括管理できる
298
+ # 当たり判定を一括処理することで高速化を図る
242
299
  class Collisions
243
300
  include Enumerable
244
301
  extend Forwardable
245
302
 
246
303
  #===コリジョンのインスタンスを作成する
304
+ # points引数の各要素は、以下の3つの条件のどれかに適合する必要がある。しない場合は例外が発生する
305
+ # 1)[x,y]の要素を持つ配列
306
+ # 2)Point構造体、Rect構造体、もしくはSquare構造体
307
+ # 3)x,yメソッドを持つ
247
308
  #_collisions_:: コリジョンの配列。デフォルトは []
248
- #_pos_:: 元データの配列。デフォルトは []
309
+ #_points_:: 位置情報の配列。デフォルトは []
249
310
  #返却値:: 作成されたインスタンス
250
- def initialize(collisions=[], bodies=[])
251
- @collisions = Array.new(collisions).zip(bodies)
311
+ def initialize(collisions=[], points=[])
312
+ @collisions = Array.new(collisions).zip(points)
252
313
  end
253
314
 
254
- #===コリジョンと本体を追加する
315
+ #===コリジョンと位置情報を追加する
316
+ # point引数は、以下の3つの条件のどれかに適合する必要がある。しない場合は例外が発生する
317
+ # 1)[x,y]の要素を持つ配列
318
+ # 2)Point構造体、Rect構造体、もしくはSquare構造体
319
+ # 3)x,yメソッドを持つ
255
320
  #_collisions_:: コリジョン
256
- #_pos_:: 元データ
321
+ #_point_:: 位置情報
257
322
  #返却値:: 自分自身を返す
258
- def add(collision, body)
259
- @collisions << [collision, body]
323
+ def add(collision, point)
324
+ @collisions << [collision, point]
260
325
  return self
261
326
  end
262
327
 
263
- #===インスタンスに、コリジョンと本体の集合を追加する
328
+ #===インスタンスに、コリジョンと位置情報の集合を追加する
329
+ # points引数の各要素は、以下の3つの条件のどれかに適合する必要がある。しない場合は例外が発生する
330
+ # 1)[x,y]の要素を持つ配列
331
+ # 2)Point構造体、Rect構造体、もしくはSquare構造体
332
+ # 3)x,yメソッドを持つ
264
333
  #_collisions_:: コリジョンの配列
265
- #_pos_:: 元データの配列
334
+ #_points_:: 位置情報の配列
266
335
  #返却値:: 自分自身を返す
267
- def append(collisions, bodies)
268
- @collisions.concat(collisions.zip(bodies))
336
+ def append(collisions, points)
337
+ @collisions.concat(collisions.zip(points))
269
338
  return self
270
339
  end
271
340
 
272
341
  #===インデックス形式でのコリジョン・本体の取得
273
342
  #_idx_:: 配列のインデックス番号
274
- #返却値:: インデックスに対応したコリジョンと本体との対。
343
+ #返却値:: インデックスに対応したコリジョンと位置情報との対。
275
344
  #インデックスが範囲外の時はnilが返る
276
345
  def [](idx)
277
346
  return @collisions[idx]
278
347
  end
279
348
 
280
349
  #===コリジョン・本体の削除
281
- #対応したインデックスのコリジョンと
282
350
  #_idx_:: 配列のインデックス番号
283
351
  #返却値:: 削除したコリジョンと本体との対
284
352
  #インデックスが範囲外の時はnilが返る
@@ -295,8 +363,8 @@ module Miyako
295
363
  end
296
364
 
297
365
  #===タッピングを行う
298
- #ブロックを渡すことにより、タッピングを行う
299
- #ブロック内の引数は、|コリジョン,本体|の2が渡される
366
+ # ブロックを渡すことにより、タッピングを行う
367
+ # ブロック内の引数は、|コリジョン,本体|の2が渡される
300
368
  #返却値:: 自分自身を返す
301
369
  def each
302
370
  @collisions.each{|cb| yield cb[0], cb[1] }
@@ -304,138 +372,86 @@ module Miyako
304
372
  end
305
373
 
306
374
  #===タッピングを行う
307
- #ブロックを渡すことにより、タッピングを行う
308
- #ブロック内の引数は、|コリジョン,本体|の2が渡される
375
+ # ブロックを渡すことにより、タッピングを行う
376
+ # ブロック内の引数は、|コリジョン,本体|の2が渡される
309
377
  #_idx_:: 配列のインデックス
310
378
  #返却値:: 自分自身を返す
311
379
  def tap(idx)
312
380
  yield @collisions[idx][0], @collisions[idx][1]
313
381
  return self
314
382
  end
315
-
316
- #===すべてのコリジョンの方向を転換する
317
- #_dx_:: 変換する方向(x軸方向、-1,0,1の3種類)
318
- #_dy_:: 変換する方向(y軸方向、-1,0,1の3種類)
319
- #返却値:: 自分自身を返す
320
- def turn(dx, dy)
321
- @collisions.each{|cs| cs.turn(dx, dy) }
322
- return self
323
- end
324
-
325
- #===すべてのコリジョンの移動量を変更する
326
- #_mx_:: 変更する移動量(x軸方向)
327
- #_my_:: 変更する移動量(y軸方向)
328
- #返却値:: 自分自身を返す
329
- def adjust(mx, my)
330
- @collisions.each{|cs| cs.adjust(mx, my) }
331
- return self
332
- end
333
383
 
334
- #===当たり判定を行う(領域が重なっている)
335
- #判定に引っかかったコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
336
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
384
+ #===当たり判定を行う(配列のどれかの領域が重なっている)
385
+ # 重なったコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
386
+ # 重なったコリジョンが無い場合はnilを返す
337
387
  #_c_:: 判定対象のコリジョンインスタンス
388
+ #_pos_:: cの位置(Point/Rect/Square構造体、もしくは2要素の配列)
338
389
  #返却値:: コリジョンと本体の対。
339
- def collision?(c)
340
- return @collisions.detect{|cc| c.collision?(cc[0])}
390
+ def collision?(c, pos)
391
+ return @collisions.detect{|cc| c.collision?(pos, cc[0], cc[1])}
341
392
  end
342
393
 
343
- #===当たり判定を行う(領域が当たっている(重なっていない))
344
- #判定に引っかかったコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
345
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
394
+ #===当たり判定を行う(配列のどれかの領域がピクセル単位で隣り合っている)
395
+ # 隣り合ったコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
396
+ # 隣り合ったコリジョンが無い場合はnilを返す
346
397
  #_c_:: 判定対象のコリジョンインスタンス
347
- #返却値:: コリジョンと本体の対。
348
- #返却値:: 領域が当たっていれば true を返す
349
- def meet?(c)
350
- return @collisions.detect{|cc| c.meet?(cc[0])}
351
- end
352
-
353
- #===当たり判定を行う(移動後に領域が重なっている(移動前は重なっていない))
354
- #判定に引っかかったコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
355
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
356
- #_c_:: 判定対象のコリジョンインスタンス
357
- #返却値:: コリジョンと本体の対。
358
- #返却値:: 1ピクセルでも重なっていれば true を返す
359
- def into?(c)
360
- return @collisions.detect{|cc| c.into?(cc[0])}
361
- end
362
-
363
- #===当たり判定を行う(移動後に領域が離れている(移動前は重なっている))
364
- #判定に引っかかったコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
365
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
366
- #_c_:: 判定対象のコリジョンインスタンス
367
- #返却値:: コリジョンと本体の対。
368
- #返却値:: 1ピクセルでも重なっていれば true を返す
369
- def out?(c)
370
- return @collisions.detect{|cc| c.out?(cc[0])}
398
+ #_pos_:: cの位置(Point/Rect/Square構造体、もしくは2要素の配列)
399
+ #返却値:: 隣り合っていれば true を返す
400
+ def meet?(c, pos)
401
+ return @collisions.detect{|cc| c.meet?(pos, cc[0], cc[1])}
371
402
  end
372
403
 
373
404
  #===当たり判定を行う(どちらかの領域がもう一方にすっぽり覆われている))
374
- #判定に引っかかったコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
375
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
405
+ # 覆われたコリジョンが一つでもあれば、最初に引っかかったコリジョンを返す
406
+ # 覆われたコリジョンが無い場合はnilを返す
376
407
  #_c_:: 判定対象のコリジョンインスタンス
377
- #返却値:: コリジョンと本体の対。
408
+ #_pos_:: cの位置(Point/Rect/Square構造体、もしくは2要素の配列)
378
409
  #返却値:: 領域が覆われていれば true を返す
379
- def cover?(c)
380
- return @collisions.detect{|cc| c.cover?(cc[0])}
410
+ def cover?(c, pos)
411
+ return @collisions.detect{|cc| c.cover?(pos, cc[0], cc[1])}
381
412
  end
382
413
 
383
414
  #===当たり判定を行う(領域が重なっている)
384
- #判定に引っかかったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
385
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
386
- #_c_:: 判定対象のコリジョンインスタンス
387
- #返却値:: コリジョンと本体の対の配列。
388
- def collision_all?(c)
389
- return @collisions.select{|cc| c.collision?(cc[0])}
390
- end
391
-
392
- #===当たり判定を行う(領域が当たっている(重なっていない))
393
- #判定に引っかかったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
394
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
395
- #_c_:: 判定対象のコリジョンインスタンス
396
- #返却値:: コリジョンと本体の対の配列。
397
- def meet_all?(c)
398
- return @collisions.select{|cc| c.meet?(cc[0])}
399
- end
400
-
401
- #===当たり判定を行う(移動後に領域が重なっている(移動前は重なっていない))
402
- #判定に引っかかったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
403
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
415
+ # 重なったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
416
+ # 重なったコリジョンが無い場合はnilを返す
404
417
  #_c_:: 判定対象のコリジョンインスタンス
418
+ #_pos_:: cの位置(Point/Rect/Square構造体、もしくは2要素の配列)
405
419
  #返却値:: コリジョンと本体の対の配列。
406
- def into_all?(c)
407
- return @collisions.select{|cc| c.into?(cc[0])}
420
+ def collision_all?(c, pos)
421
+ return @collisions.select{|cc| c.collision?(pos, cc[0], cc[1])}
408
422
  end
409
423
 
410
- #===当たり判定を行う(移動後に領域が離れている(移動前は重なっている))
411
- #判定に引っかかったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
412
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
424
+ #===当たり判定を行う(領域がピクセル単位で隣り合っている)
425
+ # 隣り合ったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
426
+ # 隣り合ったコリジョンが無い場合はnilを返す
413
427
  #_c_:: 判定対象のコリジョンインスタンス
428
+ #_pos_:: cの位置(Point/Rect/Square構造体、もしくは2要素の配列)
414
429
  #返却値:: コリジョンと本体の対の配列。
415
- def out_all?(c)
416
- return @collisions.select{|cc| c.out?(cc[0])}
430
+ def meet_all?(c, pos)
431
+ return @collisions.select{|cc| c.meet?(pos, cc[0], cc[1])}
417
432
  end
418
433
 
419
434
  #===当たり判定を行う(どちらかの領域がもう一方にすっぽり覆われている))
420
- #判定に引っかかったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
421
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
435
+ # 覆われたコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
436
+ # 覆われたコリジョンが無い場合はnilを返す
422
437
  #_c_:: 判定対象のコリジョンインスタンス
438
+ #_pos_:: cの位置(Point/Rect/Square構造体、もしくは2要素の配列)
423
439
  #返却値:: コリジョンと本体の対の配列。
424
- def cover_all?(c)
425
- return @collisions.select{|cc| c.cover?(cc[0])}
440
+ def cover_all?(c, pos)
441
+ return @collisions.select{|cc| c.cover?(pos, cc[0], cc[1])}
426
442
  end
427
443
 
428
444
  #===インデックス形式でのコリジョン・本体の取得
429
- #判定に引っかかったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
430
- #当たり判定に引っかかったコリジョンが無い場合はnilを返す
445
+ # 判定に引っかかったコリジョンが一つでもあれば、すべてのコリジョンの配列を返す
446
+ # 当たり判定に引っかかったコリジョンが無い場合はnilを返す
431
447
  #_idx_:: 配列のインデックス番号
432
448
  #返却値:: インデックスに対応したコリジョンと本体との対
433
449
  def [](idx)
434
450
  return [@collisions[idx], @bodies[idx]]
435
451
  end
436
452
 
437
- #===あとで書く
438
- #返却値:: あとで書く
453
+ #===オブジェクトを解放する
454
+ #返却値:: なし
439
455
  def dispose
440
456
  @collisions.clear
441
457
  @collisions = nil