cyross-ruby-miyako 2.0.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 (125) hide show
  1. data/README +977 -0
  2. data/Rakefile +7 -0
  3. data/img/cursor.png +0 -0
  4. data/img/cursors.png +0 -0
  5. data/img/dice.png +0 -0
  6. data/img/wait_cursor.png +0 -0
  7. data/img/win_base.png +0 -0
  8. data/img/window.png +0 -0
  9. data/install_miyako.rb +75 -0
  10. data/lib/Miyako/API/audio.rb +198 -0
  11. data/lib/Miyako/API/basic_data.rb +431 -0
  12. data/lib/Miyako/API/bitmap.rb +35 -0
  13. data/lib/Miyako/API/choices.rb +308 -0
  14. data/lib/Miyako/API/collision.rb +444 -0
  15. data/lib/Miyako/API/diagram.rb +573 -0
  16. data/lib/Miyako/API/drawing.rb +110 -0
  17. data/lib/Miyako/API/fixedmap.rb +315 -0
  18. data/lib/Miyako/API/font.rb +384 -0
  19. data/lib/Miyako/API/input.rb +440 -0
  20. data/lib/Miyako/API/layout.rb +451 -0
  21. data/lib/Miyako/API/map.rb +403 -0
  22. data/lib/Miyako/API/map_event.rb +198 -0
  23. data/lib/Miyako/API/modules.rb +109 -0
  24. data/lib/Miyako/API/movie.rb +151 -0
  25. data/lib/Miyako/API/parts.rb +154 -0
  26. data/lib/Miyako/API/plane.rb +131 -0
  27. data/lib/Miyako/API/screen.rb +257 -0
  28. data/lib/Miyako/API/shape.rb +362 -0
  29. data/lib/Miyako/API/sprite.rb +338 -0
  30. data/lib/Miyako/API/sprite_animation.rb +461 -0
  31. data/lib/Miyako/API/spriteunit.rb +113 -0
  32. data/lib/Miyako/API/story.rb +224 -0
  33. data/lib/Miyako/API/textbox.rb +496 -0
  34. data/lib/Miyako/API/viewport.rb +435 -0
  35. data/lib/Miyako/API/yuki.rb +779 -0
  36. data/lib/Miyako/EXT/miyako_cairo.rb +60 -0
  37. data/lib/Miyako/EXT/raster_scroll.rb +138 -0
  38. data/lib/Miyako/EXT/slides.rb +136 -0
  39. data/lib/Miyako/miyako.rb +172 -0
  40. data/miyako.png +0 -0
  41. data/miyako_banner.png +0 -0
  42. data/miyako_no_katana/extconf.rb +34 -0
  43. data/miyako_no_katana/miyako_no_katana.c +3301 -0
  44. data/sample/Animation1/m1ku.rb +89 -0
  45. data/sample/Animation1/m1ku_arm_0.png +0 -0
  46. data/sample/Animation1/m1ku_arm_1.png +0 -0
  47. data/sample/Animation1/m1ku_arm_2.png +0 -0
  48. data/sample/Animation1/m1ku_arm_3.png +0 -0
  49. data/sample/Animation1/m1ku_back.jpg +0 -0
  50. data/sample/Animation1/m1ku_body.png +0 -0
  51. data/sample/Animation1/m1ku_eye_0.png +0 -0
  52. data/sample/Animation1/m1ku_eye_1.png +0 -0
  53. data/sample/Animation1/m1ku_eye_2.png +0 -0
  54. data/sample/Animation1/m1ku_eye_3.png +0 -0
  55. data/sample/Animation1/m1ku_hair_front.png +0 -0
  56. data/sample/Animation1/m1ku_hair_rear.png +0 -0
  57. data/sample/Animation1/readme.txt +72 -0
  58. data/sample/Animation2/lex.rb +95 -0
  59. data/sample/Animation2/lex_back.png +0 -0
  60. data/sample/Animation2/lex_body.png +0 -0
  61. data/sample/Animation2/lex_roadroller.png +0 -0
  62. data/sample/Animation2/lex_wheel_0.png +0 -0
  63. data/sample/Animation2/lex_wheel_1.png +0 -0
  64. data/sample/Animation2/lex_wheel_2.png +0 -0
  65. data/sample/Animation2/readme.txt +72 -0
  66. data/sample/Animation2/song_title.png +0 -0
  67. data/sample/Diagram_sample/back.png +0 -0
  68. data/sample/Diagram_sample/chr01.png +0 -0
  69. data/sample/Diagram_sample/chr02.png +0 -0
  70. data/sample/Diagram_sample/cursor.png +0 -0
  71. data/sample/Diagram_sample/diagram_sample_yuki2.rb +283 -0
  72. data/sample/Diagram_sample/readme.txt +87 -0
  73. data/sample/Diagram_sample/wait_cursor.png +0 -0
  74. data/sample/Room3/blue.rb +250 -0
  75. data/sample/Room3/ending.rb +175 -0
  76. data/sample/Room3/green.rb +185 -0
  77. data/sample/Room3/image/akamatsu.png +0 -0
  78. data/sample/Room3/image/aoyama.png +0 -0
  79. data/sample/Room3/image/congra.png +0 -0
  80. data/sample/Room3/image/congratulation.png +0 -0
  81. data/sample/Room3/image/congratulation_bg.png +0 -0
  82. data/sample/Room3/image/cursor.png +0 -0
  83. data/sample/Room3/image/midori.png +0 -0
  84. data/sample/Room3/image/mittsu_no_oheya.png +0 -0
  85. data/sample/Room3/image/mittsu_no_oheya_logo.png +0 -0
  86. data/sample/Room3/image/room_blue.png +0 -0
  87. data/sample/Room3/image/room_green.png +0 -0
  88. data/sample/Room3/image/room_red.png +0 -0
  89. data/sample/Room3/image/start.png +0 -0
  90. data/sample/Room3/image/three_doors.png +0 -0
  91. data/sample/Room3/image/wait_cursor.png +0 -0
  92. data/sample/Room3/main.rb +102 -0
  93. data/sample/Room3/main_component.rb +58 -0
  94. data/sample/Room3/readme.txt +76 -0
  95. data/sample/Room3/red.rb +200 -0
  96. data/sample/Room3/room3.rb +26 -0
  97. data/sample/Room3/title.rb +171 -0
  98. data/sample/fixed_map_test/cursor.png +0 -0
  99. data/sample/fixed_map_test/fixed_map_sample.rb +149 -0
  100. data/sample/fixed_map_test/map.csv +19 -0
  101. data/sample/fixed_map_test/map_01.png +0 -0
  102. data/sample/fixed_map_test/map_sample.rb +121 -0
  103. data/sample/fixed_map_test/mapchip.csv +23 -0
  104. data/sample/fixed_map_test/monster.png +0 -0
  105. data/sample/fixed_map_test/readme.txt +72 -0
  106. data/sample/map_test/chara.rb +50 -0
  107. data/sample/map_test/chr1.png +0 -0
  108. data/sample/map_test/cursor.png +0 -0
  109. data/sample/map_test/main_parts.rb +48 -0
  110. data/sample/map_test/main_scene.rb +137 -0
  111. data/sample/map_test/map.png +0 -0
  112. data/sample/map_test/map2.png +0 -0
  113. data/sample/map_test/map_layer.csv +127 -0
  114. data/sample/map_test/map_manager.rb +92 -0
  115. data/sample/map_test/map_test.rb +23 -0
  116. data/sample/map_test/mapchip.csv +21 -0
  117. data/sample/map_test/oasis.rb +65 -0
  118. data/sample/map_test/readme.txt +87 -0
  119. data/sample/map_test/route.rb +144 -0
  120. data/sample/map_test/sea.png +0 -0
  121. data/sample/map_test/town.rb +68 -0
  122. data/sample/map_test/wait_cursor.png +0 -0
  123. data/sample/map_test/window.png +0 -0
  124. data/win/miyako_no_katana.so +0 -0
  125. metadata +194 -0
@@ -0,0 +1,315 @@
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
+ require 'csv'
24
+ require 'forwardable'
25
+
26
+ module Miyako
27
+ #==スクロールしないマップクラス
28
+ class FixedMap
29
+ include Layout
30
+
31
+ @@idx_ix = [-1, 2, 4]
32
+ @@idx_iy = [-1, 0, 6]
33
+
34
+ attr_reader :name, :map_layers, :pos, :w, :h
35
+
36
+ #==あとで書く
37
+ class FixedMapLayer #:nodoc: all
38
+ extend Forwardable
39
+
40
+ @@use_chip_list = Hash.new(nil)
41
+
42
+ attr_accessor :mapchip_units
43
+ attr_reader :pos
44
+
45
+ def round(v, max) #:nodoc:
46
+ v = max + (v % max) if v < 0
47
+ v %= max if v >= max
48
+ return v
49
+ end
50
+
51
+ def reSize #:nodoc:
52
+ @cw = @real_size.w % @ow == 0 ? @real_size.w / @ow : (@real_size.w + @ow - 1)/ @ow + 1
53
+ @ch = @real_size.h % @oh == 0 ? @real_size.h / @oh : (@real_size.h + @oh - 1)/ @oh + 1
54
+ end
55
+
56
+ def initialize(mapchip, mapdat, layer_size, pos) #:nodoc:
57
+ @mapchip = mapchip
58
+ @pos = pos.dup
59
+ @size = layer_size.dup
60
+ @ow = @mapchip.chip_size.w
61
+ @oh = @mapchip.chip_size.h
62
+ @real_size = Size.new(@size.w * @ow, @size.h * @oh)
63
+ @mapdat = mapdat
64
+ @baseimg = nil
65
+ @baseimg = @mapchip.chip_image
66
+ @units = nil
67
+ @visible = false
68
+ @divpx = get_div_array(0, @real_size.w, @ow)
69
+ @divpy = get_div_array(0, @real_size.h, @oh)
70
+ @modpx = get_mod_array(0, @real_size.w, @ow)
71
+ @modpy = get_mod_array(0, @real_size.h, @oh)
72
+ @modpx2 = get_mod_array(0, @size.w * 2 + 1, @size.w)
73
+ @modpy2 = get_mod_array(0, @size.h * 2 + 1, @size.h)
74
+ @cdivsx = get_div_array(0, @mapchip.chips, @mapchip.size.w)
75
+ @cmodsx = get_mod_array(0, @mapchip.chips, @mapchip.size.w)
76
+ @cdivsy = get_div_array(0, @mapchip.chips, @mapchip.size.h)
77
+ @cmodsy = get_mod_array(0, @mapchip.chips, @mapchip.size.h)
78
+ @cdivsx = @cdivsx.map{|v| v * @ow }
79
+ @cdivsy = @cdivsy.map{|v| v * @oh }
80
+ @cmodsx = @cmodsx.map{|v| v * @ow }
81
+ @cmodsy = @cmodsy.map{|v| v * @oh }
82
+ @mapchip_units = Array.new(@mapchip.chips){|idx|
83
+ SpriteUnitFactory.create(:bitmap=>@baseimg.bitmap,
84
+ :ox => (idx % @mapchip.size.w) * @ow, :oy => (idx / @mapchip.size.w) * @oh,
85
+ :ow => @ow, :oh => @oh)
86
+ }
87
+ reSize
88
+ end
89
+
90
+ def get_div_array(s, t, v) #:nodoc:
91
+ a = Array.new
92
+ (s..t).each{|i| a.push(i / v)}
93
+ return a
94
+ end
95
+
96
+ def get_mod_array(s, t, v) #:nodoc:
97
+ a = Array.new
98
+ (s..t).each{|i| a.push(i % v)}
99
+ return a
100
+ end
101
+
102
+ def convert_position(x, y) #:nodoc:
103
+ return Point.new(@modpx2[round(x, @size.w)],
104
+ @modpy2[round(y, @size.h)])
105
+ end
106
+
107
+ def get_code(x, y) #:nodoc:
108
+ pos = convert_position(x, y)
109
+ return @mapdat[pos.y][pos.x]
110
+ end
111
+
112
+ def dispose #:nodoc:
113
+ @mapdat = nil
114
+ @baseimg = nil
115
+ end
116
+
117
+ def_delegators(:@size, :w, :h)
118
+ end
119
+
120
+ #===あとで書く
121
+ #_mapchip_:: あとで書く
122
+ #_layer_csv_:: あとで書く
123
+ #_event_manager_:: MapEventManagerクラスのインスタンス
124
+ #_pos_:: あとで書く
125
+ #返却値:: あとで書く
126
+ def initialize(mapchip, layer_csv, event_manager, pos = Point.new(0, 0))
127
+ init_layout
128
+ @em = event_manager.dup
129
+ @em.set(self)
130
+ @mapchip = mapchip
131
+ @pos = Point.new(*(pos.to_a))
132
+ @coll = Collision.new(Rect.new(0, 0, 0, 0), Point.new(0, 0))
133
+ layer_data = CSV.readlines(layer_csv)
134
+
135
+ raise MiyakoError, "This file is not Miyako Map Layer file! : #{layer_csv}" unless layer_data.shift[0] == "Miyako Maplayer"
136
+
137
+ tmp = layer_data.shift # 空行の空読み込み
138
+
139
+ layer_size = Size.new(tmp[0].to_i, tmp[1].to_i)
140
+ @w = layer_size.w * @mapchip.chip_size.w
141
+ @h = layer_size.h * @mapchip.chip_size.h
142
+
143
+ layers = layer_data.shift[0].to_i
144
+
145
+ brlist = {}
146
+ layers.times{|n|
147
+ name = layer_data.shift[0]
148
+ if name == "<event>"
149
+ name = :event
150
+ else
151
+ name = /\<(\d+)\>/.match(name).to_a[1].to_i
152
+ end
153
+ values = []
154
+ layer_size.h.times{|y|
155
+ values << layer_data.shift.map{|m| m.to_i}
156
+ }
157
+ brlist[name] = values
158
+ }
159
+
160
+ @map_layers = Array.new
161
+ @event_layer = nil
162
+
163
+ if brlist.has_key?(:event)
164
+ @event_layer = Array.new
165
+ brlist[:event].each_with_index{|ly, y|
166
+ ly.each_with_index{|code, x|
167
+ next unless @em.include?(code)
168
+ @event_layer.push(@em.create(code, x * @mapchip.chip_size.w, y * @mapchip.chip_size.h))
169
+ }
170
+ }
171
+ layers -= 1
172
+ end
173
+ @map_layers = []
174
+ layers.times{|i|
175
+ br = brlist[i].map{|b| b.map{|bb| bb >= @mapchip.chips ? -1 : bb } }
176
+ @map_layers.push(FixedMapLayer.new(@mapchip, br, layer_size, pos))
177
+ }
178
+ set_layout_size(@w, @h)
179
+ end
180
+
181
+ #===マップにイベントを追加する
182
+ #_code_:: イベント番号(FixedMap.newメソッドで渡したイベント番号に対応)
183
+ #_x_:: マップ上の位置(x方向)
184
+ #_y_:: マップ常温位置(y方向)
185
+ #返却値:: 自分自身を返す
186
+ def add_event(code, x, y)
187
+ return self unless @em.include?(code)
188
+ @event_layer.push(@em.create(code, x, y))
189
+ return self
190
+ end
191
+
192
+ def update_layout_position #:nodoc:
193
+ d = Point.new(@layout.pos[0]-@pos.x, @layout.pos[1]-@pos.y)
194
+ @pos.move_to(*@layout.pos)
195
+ @map_layers.each{|ml| ml.pos.move_to(*@pos) }
196
+ end
197
+
198
+ def [](idx) #:nodoc:
199
+ return @map_layers[idx]
200
+ end
201
+
202
+ #===あとで書く
203
+ #_idx_:: あとで書く
204
+ #_x_:: あとで書く
205
+ #_y_:: あとで書く
206
+ #返却値:: あとで書く
207
+ def get_code_real(idx, x, y)
208
+ code = @map_layers[idx].get_code((x-@pos[0]) / @mapchip.chip_size[0], (y-@pos[1]) / @mapchip.chip_size[1])
209
+ yield code if block_given?
210
+ return code
211
+ end
212
+
213
+ #===あとで書く
214
+ #_idx_:: あとで書く
215
+ #_x_:: あとで書く
216
+ #_y_:: あとで書く
217
+ #返却値:: あとで書く
218
+ def get_code(idx, x, y)
219
+ code = @map_layers[idx].get_code(x, y)
220
+ yield code if block_given?
221
+ return code
222
+ end
223
+
224
+ #===あとで書く
225
+ #_idx_:: あとで書く
226
+ #_code_:: あとで書く
227
+ #_base_:: あとで書く
228
+ #返却値:: あとで書く
229
+ def set_mapchip_base(idx, code, base)
230
+ @map_layers[idx].mapchip_units[code] = base
231
+ return self
232
+ end
233
+
234
+ #===あとで書く
235
+ #_type_:: あとで書く
236
+ #_rect_:: あとで書く
237
+ #_collision_:: あとで書く
238
+ #返却値:: あとで書く
239
+ def get_amount_by_rect(type, rect, collision)
240
+ mma = MapMoveAmount.new([], collision.direction.dup)
241
+ return mma if(mma.amount[0] == 0 && mma.amount[1] == 0)
242
+ dx, dy = collision.direction[0]*collision.amount[0], collision.direction[1]*collision.amount[1]
243
+ x, y = rect[0]-@pos[0], rect[1]-@pos[1]
244
+ collision.pos = Point.new(x, y)
245
+ px1, px2 = (x+dx) / @mapchip.chip_size[0], (x+rect[2]-1+dx) / @mapchip.chip_size[0]
246
+ py1, py2 = (y+dy) / @mapchip.chip_size[1], (y+rect[3]-1+dy) / @mapchip.chip_size[1]
247
+ (py1..py2).each{|py|
248
+ rpy = py * @mapchip.chip_size[1]
249
+ (px1..px2).each{|px|
250
+ rpx = px * @mapchip.chip_size[0]
251
+ @map_layers.each_with_index{|ml, idx|
252
+ code = ml.get_code(px, py)
253
+ next if code == -1 # not use chip
254
+ @coll = @mapchip.collision_table[type][code].dup
255
+ @coll.pos = Point.new(rpx, rpy)
256
+ atable = @mapchip.access_table[type][code]
257
+ if @coll.into?(collision)
258
+ mma.amount[0] = mma.amount[0] & atable[@@idx_ix[collision.direction[0]]]
259
+ mma.amount[1] = mma.amount[1] & atable[@@idx_iy[collision.direction[1]]]
260
+ mma.collisions << [idx, code, :into]
261
+ end
262
+ }
263
+ }
264
+ }
265
+ mma.amount[0] *= collision.amount[0]
266
+ mma.amount[1] *= collision.amount[1]
267
+ yield mma if block_given?
268
+ return mma
269
+ end
270
+
271
+ #===現在の画面の最大の大きさを矩形で取得する
272
+ #但し、FixedMapの場合は最大の大きさ=画面の大きさなので、rectと同じ値が得られる
273
+ #返却値:: 画像の大きさ(Rect構造体のインスタンス)
274
+ def broad_rect
275
+ return self.rect
276
+ end
277
+
278
+ #===あとで書く
279
+ #返却値:: あとで書く
280
+ def chipSize
281
+ return @mapchip.chip_size
282
+ end
283
+
284
+ #===あとで書く
285
+ #返却値:: あとで書く
286
+ def final
287
+ @event_layer.each{|e| e.final } if @event_layer
288
+ end
289
+
290
+ #===あとで書く
291
+ #返却値:: あとで書く
292
+ def dispose
293
+ @map_layers.each{|l|
294
+ l.dispose
295
+ l = nil
296
+ }
297
+ @map_layers = Array.new
298
+ if @event_layer
299
+ @event_layer.each{|e| e.dispose }
300
+ @event_layer = nil
301
+ end
302
+ end
303
+
304
+ def re_size #:nodoc:
305
+ @map_layers.each{|l| l.reSize }
306
+ return self
307
+ end
308
+
309
+ #===マップに登録しているイベントインスタンス(マップイベント)を取得する
310
+ #返却値:: マップイベントの配列
311
+ def events
312
+ return @event_layer || []
313
+ end
314
+ end
315
+ end
@@ -0,0 +1,384 @@
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
+ # フォント関連クラス(群)
24
+ module Miyako
25
+
26
+ =begin rdoc
27
+ ==フォント管理クラス
28
+ =end
29
+ class Font
30
+ extend Forwardable
31
+
32
+ attr_reader :size, :line_skip, :height, :ascent, :descent
33
+ attr_accessor :color, :use_shadow, :shadow_color, :shadow_margin, :vspace, :draw_type
34
+
35
+ @@font_cache = {}
36
+
37
+ @@name_2_font_path = Hash.new
38
+
39
+ @@font_base_path = Hash.new
40
+ @@font_base_path["win"] = ENV['SystemRoot'] ? ["./", ENV['SystemRoot'].tr("\\", "/") + "/fonts/"] : ["./"]
41
+ @@font_base_path["linux"] = ["./", "/usr/share/fonts/", "/usr/X11R6/lib/X11/fonts/"]
42
+ @@font_base_path["mac_osx"] = ["./", "~/Library/Fonts/", "/Library/Fonts/", "/System/Library/Fonts/",
43
+ "/ライブラリ/Fonts/", "/システム/ライブラリ/Fonts/"]
44
+
45
+ @@font_base_name = Hash.new
46
+ @@font_base_name["win"] = [{:serif=>"msmincho.ttc", :sans_serif=>"meiryo.ttc"},
47
+ {:serif=>"msmincho.ttc", :sans_serif=>"msgothic.ttc"},
48
+ {:serif=>"VL-Gothic-Regular.ttf", :sans_serif=>"VL-Gothic-Regular.ttf"},
49
+ {:serif=>"umeplus-gothic.ttf", :sans_serif=>"umeplus-gothic.ttf"}]
50
+ @@font_base_name["linux"] = [{:serif=>"sazanami-mincho.ttf", :sans_serif=>"sazanami-gothic.ttf"},
51
+ {:serif=>"VL-Gothic-Regular.ttf", :sans_serif=>"VL-Gothic-Regular.ttf"},
52
+ {:serif=>"umeplus-gothic.ttf", :sans_serif=>"umeplus-gothic.ttf"}]
53
+ @@font_base_name["mac_osx"] = [{:serif=>"Hiragino Mincho Pro W3.otf", :sans_serif=>"Hiragino Kaku Gothic Pro W3.otf"},
54
+ {:serif=>"Hiragino Mincho Pro W6.otf", :sans_serif=>"Hiragino Kaku Gothic Pro W6.otf"},
55
+ {:serif=>"ヒラギノ明朝 Pro W3.otf", :sans_serif=>"ヒラギノ角ゴ Pro W3.otf"},
56
+ {:serif=>"ヒラキ゛ノ明朝 Pro W3.otf", :sans_serif=>"ヒラキ゛ノ角コ゛ Pro W3.otf"},
57
+ {:serif=>"ヒラギノ明朝 Pro W6.otf", :sans_serif=>"ヒラギノ角ゴ Pro W6.otf"},
58
+ {:serif=>"ヒラキ゛ノ明朝 Pro W6.otf", :sans_serif=>"ヒラキ゛ノ角コ゛ Pro W6.otf"},
59
+ {:serif=>"VL-Gothic-Regular.ttf", :sans_serif=>"VL-Gothic-Regular.ttf"},
60
+ {:serif=>"umeplus-gothic.ttf", :sans_serif=>"umeplus-gothic.ttf"}]
61
+
62
+ def Font.search_font_path_file(hash, path) #:nodoc:
63
+ Dir.glob(path+"*"){|d|
64
+ hash = Font.search_font_path_file(hash, d+"/") if test(?d, d)
65
+ d = Iconv.conv("UTF-8-MAC", "UTF-8", d.toutf8) if Miyako.getOSName == "mac_osx" # MacOSXはパス名がUTF-8固定のため
66
+ d = d.tr("\\", "\/")
67
+ hash[$1] = d if (d =~ /\/([^\/\.]+\.tt[fc])\z/ || d =~ /\/([^\/\.]+\.otf)\z/) # MacOSX対応
68
+ }
69
+ return hash
70
+ end
71
+
72
+ def Font.create_font_path #:nodoc:
73
+ osn = Miyako::getOSName
74
+ @@font_base_path[osn].each{|path|
75
+ path = Iconv.conv("UTF-8-MAC", "UTF-8", path.toutf8) if Miyako.getOSName == "mac_osx" # MacOSXはパス名がUTF-8固定のため
76
+ path = path.tr("\\", "\/")
77
+ @@name_2_font_path = Font.search_font_path_file(@@name_2_font_path, path)
78
+ }
79
+ end
80
+
81
+ def Font.findFontPath(fname) #:nodoc:
82
+ fname = Iconv.conv("UTF-8-MAC", "UTF-8", fname.toutf8) if Miyako.getOSName == "mac_osx" # MacOSXはパス名がUTF-8固定のため
83
+ return @@name_2_font_path.fetch(fname, nil)
84
+ end
85
+
86
+ def Font.get_font_inner(fname, fpath, size=16) #:nodoc:
87
+ if Miyako.getOSName == "mac_osx" # MacOSXはパス名がUTF-8固定のため
88
+ fname = Iconv.conv("UTF-8-MAC", "UTF-8", fname.toutf8)
89
+ fpath = Iconv.conv("UTF-8-MAC", "UTF-8", fpath.toutf8)
90
+ end
91
+ @@font_cache[fname] ||= {}
92
+ @@font_cache[fname][size] ||= SDL::TTF.open(fpath, size)
93
+ return @@font_cache[fname][size]
94
+ end
95
+
96
+ def init_height #:nodoc:
97
+ @line_skip = @font.line_skip
98
+ @height = @font.height
99
+ @ascent = @font.ascent
100
+ @descent = @font.descent
101
+ end
102
+
103
+ private :init_height
104
+
105
+ #===インスタンス生成
106
+ #_fname_:: フォントファイル名(フォントファミリー名不可)。システムフォントのときはディレクトリ指定不要
107
+ #_size_:: フォントの大きさ。単位はピクセル。デフォルトは 16
108
+ #返却値:: 生成されたインスタンスを返す
109
+ def initialize(fname, size=16)
110
+ @size = size
111
+ @color = [255, 255, 255]
112
+ @fname = fname
113
+ @vspace = 0
114
+ @bold = false
115
+ @italic = false
116
+ @under_line = false
117
+ @draw_type = :mild
118
+ @fpath = Font.findFontPath(@fname) or raise MiyakoError, "Cannot Find Font! : #{@fname}"
119
+ @font = Font.get_font_inner(@fname, @fpath, @size)
120
+ @font.style = SDL::TTF::STYLE_NORMAL
121
+ init_height
122
+ @draw_text = {:solid => self.method(:_draw_text), :mild => self.method(:_draw_text_mild)}
123
+ @use_shadow = false
124
+ @shadow_color = [128, 128, 128]
125
+ @shadow_margin = [2, 2]
126
+ @unit = SpriteUnitFactory.create
127
+ end
128
+
129
+ #===フォントの大きさを変更する
130
+ #_sz_:: 変更するフォントの大きさ(単位:ピクセル)
131
+ #返却値:: 変更されたフォントのインスタンス
132
+ def size=(sz)
133
+ @size = sz
134
+ @font = Font.get_font_inner(@fname, @fpath, @size)
135
+ @font.style = (@bold ? SDL::TTF::STYLE_BOLD : 0) | (@italic ? SDL::TTF::STYLE_ITALIC : 0) | (@under_line ? SDL::TTF::STYLE_UNDERLINE : 0)
136
+ init_height
137
+ return self
138
+ end
139
+
140
+ #===ブロック評価中のみ、フォントの大きさを変更する
141
+ #_sz_:: 変更するフォントの大きさ(単位:ピクセル)
142
+ #返却値:: 自分自身を返す
143
+ def size_during(sz)
144
+ raise MiyakoError, "not given block!" unless block_given?
145
+ tsize = @size
146
+ self.size = sz
147
+ yield
148
+ self.size = tsize
149
+ return self
150
+ end
151
+
152
+ #===ブロック評価中のみ、フォントの文字の色を変更する
153
+ #_color_:: 変更する色([r,g,b]の3要素の配列(値:0~255))
154
+ #返却値:: 自分自身を返す
155
+ def color_during(color)
156
+ raise MiyakoError, "not given block!" unless block_given?
157
+ tcolor, self.color = @color, color
158
+ yield
159
+ self.color = tcolor
160
+ return self
161
+ end
162
+
163
+ #===ブロック評価中のみ、影文字文字の色・マージンを変更する
164
+ #また、ブロック評価中は影文字が強制的に有効になる
165
+ #_color_:: 変更する色([r,g,b]の3要素の配列(値:0~255))、デフォルトはFont#shadow_colorメソッドの値([128,128,128])
166
+ #_margin_:: 変更する色(2要素の整数の配列、デフォルトはFont#shadow_marginメソッドの値([2,2])
167
+ #返却値:: 自分自身を返す
168
+ def shadow_during(color = @shadow_color, margin = @shadow_margin)
169
+ raise MiyakoError, "not given block!" unless block_given?
170
+ tflag, @use_shadow = @use_shadow, true
171
+ tcolor, @shadow_color = @shadow_color, color
172
+ tmargin, @shadow_margin = @shadow_margin, margin
173
+ yield
174
+ @use_shadow = tflag
175
+ @shadow_color = tcolor
176
+ @shadow_margin = tmargin
177
+ return self
178
+ end
179
+
180
+ #===指定したピクセル数のフォントが十分(欠けることなく)収まるピクセル数を取得する
181
+ #_size_:: フォントの大きさ(単位:ピクセル)
182
+ #返却値:: 算出されたピクセル数
183
+ def get_fit_size(size)
184
+ path = Font.findFontPath(@fname)
185
+ font = SDL::TTF.open(path, size)
186
+ return (size.to_f * (size.to_f / font.line_skip.to_f)).to_i
187
+ end
188
+
189
+ #===フォントサイズ(yやjなどの下にはみ出る箇所も算出)を取得する
190
+ #返却値:: 算出されたフォントサイズ
191
+ def line_height
192
+ return @line_skip + @vspace + (@use_shadow ? @shadow_margin[1] : 0)
193
+ end
194
+
195
+ #===フォントインスタンスを解放する
196
+ def dispose
197
+ @font = nil
198
+ end
199
+
200
+ #===フォントの属性をbold(太文字)に設定する
201
+ #ブロックを渡したときは、ブロック評価中のみ太字になる
202
+ #文字が領域外にはみ出る場合があるので注意!
203
+ #返却値:: 自分自身
204
+ def bold
205
+ if block_given?
206
+ tbold, self.bold = self.bold?, true
207
+ yield
208
+ self.bold = tbold
209
+ else
210
+ self.bold = true
211
+ end
212
+ return self
213
+ end
214
+
215
+ #===フォントのbold属性の有無を返す
216
+ #返却値:: bold属性かどうか(true/false)
217
+ def bold?
218
+ return @bold
219
+ end
220
+
221
+ #===フォントのbold属性を設定する
222
+ #_f_:: bold属性かどうか(true/false)
223
+ def bold=(f)
224
+ @bold = f
225
+ @font.style |= SDL::TTF::STYLE_BOLD
226
+ @font.style -= SDL::TTF::STYLE_BOLD unless @bold
227
+ return self
228
+ end
229
+
230
+ #===フォントの属性をitalic(斜め)に設定する
231
+ #ブロックを渡したときは、ブロック評価中のみ斜体文字になる
232
+ #文字が領域外にはみ出る場合があるので注意!
233
+ #返却値:: 自分自身
234
+ def italic
235
+ if block_given?
236
+ titalic, self.italic = self.italic?, true
237
+ yield
238
+ self.italic = titalic
239
+ else
240
+ self.italic = true
241
+ end
242
+ return self
243
+ end
244
+
245
+ #===フォントのitalic属性の有無を返す
246
+ #返却値:: italic属性かどうか(true/false)
247
+ def italic?
248
+ return @italic
249
+ end
250
+
251
+ #===フォントのitalic属性を設定する
252
+ #_f_:: italic属性かどうか(true/false)
253
+ def italic=(f)
254
+ @italic = f
255
+ @font.style |= SDL::TTF::STYLE_ITALIC
256
+ @font.style -= SDL::TTF::STYLE_ITALIC unless @italic
257
+ return self
258
+ end
259
+
260
+ #===フォントの属性をunder_line(下線)に設定する
261
+ #ブロックを渡したときは、ブロック評価中のみ下線付き文字になる
262
+ #返却値:: 自分自身
263
+ def under_line
264
+ if block_given?
265
+ tunder_line, self.under_line = self.under_line?, true
266
+ yield
267
+ self.under_line = tunder_line
268
+ else
269
+ self.under_line = true
270
+ end
271
+ return self
272
+ end
273
+
274
+ #===フォントのunder_line属性の有無を返す
275
+ #返却値:: under_line属性かどうか(true/false)
276
+ def under_line?
277
+ return @under_line
278
+ end
279
+
280
+ #===フォントのunder_line属性を設定する
281
+ #_f_:: under_line属性かどうか(true/false)
282
+ def under_line=(f)
283
+ @under_line = f
284
+ @font.style |= SDL::TTF::STYLE_UNDERLINE
285
+ @font.style -= SDL::TTF::STYLE_UNDERLINE unless @under_line
286
+ return self
287
+ end
288
+
289
+ #===フォントの属性をすべてクリアする
290
+ #_f_:: 自分自身
291
+ def normal
292
+ @font.style = 0
293
+ return self
294
+ end
295
+
296
+ #===文字列を描画する
297
+ #対象のスプライトに文字列を描画する
298
+ #_dst_:: 描画先スプライト
299
+ #_str_:: 描画する文字列
300
+ #_x_:: 描画位置x軸
301
+ #_y_:: 描画位置Y軸
302
+ def draw_text(dst, str, x, y)
303
+ str = str.toutf8
304
+ str = Iconv.conv("UTF-8-MAC", "UTF-8", str) if Miyako.getOSName == "mac_osx"
305
+ return @draw_text[@draw_type][dst, str, x, y]
306
+ end
307
+
308
+ def _draw_text(dst, str, x, y) #:nodoc:
309
+ @font.drawSolidUTF8(dst.bitmap, str, x + @shadow_margin[0], y + @shadow_margin[1], @shadow_color[0], @shadow_color[1], @shadow_color[2]) if @use_shadow
310
+ @font.drawSolidUTF8(dst.bitmap, str, x, y, @color[0], @color[1], @color[2])
311
+ return x + @font.textSize(str)[0]
312
+ end
313
+
314
+ def _draw_text_mild(dst, str, x, y) #:nodoc:
315
+ src = @font.renderBlendedUTF8(str, @color[0], @color[1], @color[2])
316
+ if src
317
+ if @use_shadow
318
+ src2 = @font.renderBlendedUTF8(str, @shadow_color[0], @shadow_color[1], @shadow_color[2])
319
+ SpriteUnitFactory.apply(@unit, {:bitmap=>src2, :ow=>src2.w, :oh=>src2.h})
320
+ Miyako::Bitmap.blit_aa!(@unit, dst.to_unit, x+@shadow_margin[0], y+@shadow_margin[1])
321
+ end
322
+ SpriteUnitFactory.apply(@unit, {:bitmap=>src, :ow=>src.w, :oh=>src.h})
323
+ Miyako::Bitmap.blit_aa!(@unit, dst.to_unit, x, y)
324
+ else
325
+ return x
326
+ end
327
+ return x + @font.textSize(str)[0]
328
+ end
329
+
330
+ #===文字列描画したときの大きさを取得する
331
+ #現在のフォントの設定で指定の文字列を描画したとき、予想される描画サイズを返す。実際に描画は行われない。
332
+ #_txt_:: 算出したい文字列
333
+ #返却値:: 文字列を描画したときの大きさ([w,h]の配列)
334
+ def text_size(txt)
335
+ return [txt.chars.inject(0){|r, c| r += (c.length == 1 ? @size >> 1 : @size) } + (@use_shadow ? @shadow_margin[0] : 0),
336
+ self.line_height]
337
+ end
338
+
339
+ #===指定した高さで描画する際のマージンを求める
340
+ #現在のフォントの設定で指定の文字列を描画したとき、予想される描画サイズを返す。実際に描画は行われない。
341
+ #第1引数に渡す"align"は、以下の3種類のシンボルのどれかを渡す
342
+ #:top:: 上側に描画(マージンはゼロ)
343
+ #:middle:: 中間に描画
344
+ #:bottom:: 下部に描画
345
+ #
346
+ #_align_:: 描画位置
347
+ #_height_:: 描画する高さ
348
+ #返却値:: マージンの値
349
+ def margin_height(align, height)
350
+ case align
351
+ when :top
352
+ return 0
353
+ when :middle
354
+ return (height - self.line_height) >> 1
355
+ when :bottom
356
+ return height - self.line_height
357
+ end
358
+ #else
359
+ raise MiyakoError, "Illegal margin_height align! : #{align}"
360
+ end
361
+
362
+ Font.create_font_path
363
+
364
+ #===Serifフォント(明朝フォント)を取得する
365
+ #マルチプラットフォームのソフトを作る際、OS間の差異を吸収するため、共通の名称でフォントインスタンスを取得するときに使う(主に明朝フォント)
366
+ #返却値:: OSごとに設定されたフォントイン寸タンス(フォントサイズは16)
367
+ def Font::serif
368
+ filename = @@font_base_name[Miyako::getOSName].detect{|base| Font.findFontPath(base[:serif]) }[:serif]
369
+ return Font.new(filename)
370
+ end
371
+
372
+ #===Sans Serifフォント(ゴシックフォント)を取得する
373
+ #マルチプラットフォームのソフトを作る際、OS間の差異を吸収するため、共通の名称でフォントインスタンスを取得するときに使う(主にゴシックフォント)
374
+ #返却値:: OSごとに設定されたフォントイン寸タンス(フォントサイズは16)
375
+ def Font::sans_serif
376
+ filename = @@font_base_name[Miyako::getOSName].detect{|base| Font.findFontPath(base[:sans_serif]) }[:sans_serif]
377
+ return Font.new(filename)
378
+ end
379
+
380
+ def Font::system_font #:nodoc:
381
+ return Font.serif
382
+ end
383
+ end
384
+ end