2014/12/13(土) [n年前の日記]
#1 [dxruby] DXRubyとBMFont
ゲーム制作時に使うビットマップフォントのフォーマットの一つに、BMFont?ってのがあるのですけど。Unityあたりでも使えたりする、のかな。たしかそのはず。
_Bitmap Font Generator 、もしくは、 _ShoeBox で作ることができる。以下の2種類のファイルで構成されているのですが。

_mplus1p_heavy_0-export.fnt
コイツを、DXRuby で表示してみたい、と思ったわけです。
とりあえず、ShoeBox で BMFont画像と .fnt を作成してから、 _SFontぽいもの - mirichiの日記 を参考にしつつソースを書いてみました。参考にというか、丸写しですけど。
_bmfont.rb
こんな感じの表示に。
他のスクリプトから呼ぶときは、以下のような感じ。
_main.rb
とりあえず、ファイル一式を置いときます。
_bmfontsupport_20141213.zip
同梱のBMFont画像は、M+フォントで作ったので、たぶん自由に使えるはず。
スクリプトソースは、DXRuby作者様のソースを丸写しに近いのでライセンスはよくわかりませんが、たぶん自由に使っていいんじゃないかなと。DXRubyのヘルプファイルにも、
_Bitmap Font Generator 、もしくは、 _ShoeBox で作ることができる。以下の2種類のファイルで構成されているのですが。
- 文字をギッシリ詰めたテクスチャ画像。
- どこに何の文字があるかを列挙した .fntファイル。(中身はテキストファイル)

_mplus1p_heavy_0-export.fnt
info face="C:\home\Pictures\_work\bitmapfont\mplus1p_heavy_0-export" size=32 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 common lineHeight=80 base=26 scaleW=256 scaleH=256 pages=1 packed=0 alphaChnl=1 redChnl=0 greenChnl=0 blueChnl=0 page id=0 file="C:\home\Pictures\_work\bitmapfont\mplus1p_heavy_0-export.png" chars count=96 char id=33 x=175 y=149 width=13 height=24 xoffset=0 yoffset=56 xadvance=14 page=0 chnl=0 letter="!" char id=34 x=156 y=173 width=18 height=15 xoffset=0 yoffset=55 xadvance=19 page=0 chnl=0 letter=""" char id=35 x=26 y=151 width=23 height=24 xoffset=0 yoffset=56 xadvance=24 page=0 chnl=0 letter="#" char id=36 x=95 y=125 width=20 height=29 xoffset=0 yoffset=54 xadvance=21 page=0 chnl=0 letter="$" ... ... ... char id=125 x=156 y=122 width=18 height=30 xoffset=0 yoffset=55 xadvance=19 page=0 chnl=0 letter="}" char id=126 x=50 y=159 width=22 height=13 xoffset=0 yoffset=63 xadvance=23 page=0 chnl=0 letter="~" char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=0 xadvance=20 page=0 chnl=0 letter=" " char id=9 x=0 y=0 width=0 height=0 xoffset=0 yoffset=0 xadvance=160 page=0 chnl=0 letter=" " kernings count=0
コイツを、DXRuby で表示してみたい、と思ったわけです。
とりあえず、ShoeBox で BMFont画像と .fnt を作成してから、 _SFontぽいもの - mirichiの日記 を参考にしつつソースを書いてみました。参考にというか、丸写しですけど。
_bmfont.rb
require 'dxruby'
# DXRuby BMFont 描画用クラス
#
# ShoeBox で作成したビットマップフォントを描画する
# @see http://renderhjs.net/shoebox/
#
# @example
# require 'dxruby'
# require_relative 'bmfont'
# bmfont = BMFont.new("bmfont.png", "bmfont.fnt")
# Window.loop do
# Window.draw_bmfont(100, 20, "Hello BMFont", bmfont)
# end
#
# @version 0.0.2
#
class BMFont
# フォントの各文字を格納する構造体
BMFontData = Struct.new(:image, :w, :h, :xofs, :yofs, :xadvance)
# @return [Integer] 文字間スペース(単位はドット)
attr_accessor :spacing
# @return [Integer] フォント縦幅(単位はドット)
attr_reader :height
# @return [Integer] フォント縦幅調整値(単位はドット)
attr_reader :line_height
# @return [Integer] フォントベースライン位置
attr_reader :baseofs
# コンストラクタ
# @param [String] imgfilename 画像ファイル名
# @param [String] fntfilename 文字配置情報(.fnt)ファイル名
# @param [Integer] spacing 文字間スペース
def initialize(imgfilename, fntfilename, spacing = 0)
img = Image.load(imgfilename)
@bmfont_array = {}
@spacing = spacing
@height = 0
@line_height = 0
@baseofs = 0
@chars_count = 0
cnt = 0
# .fntファイルを1行ずつ読み込んで処理
open(fntfilename) {|file|
while l = file.gets
l.chomp!
if l =~ /^chars count=(\d+)$/
# 文字数取得
@chars_count = $1.to_i
elsif l =~ /^common (.+)$/
# フォントの縦幅やベースライン位置を取得
p = $1
p.split(' ').each do |s|
if s=~ /^(\S+)=(\d+)$/
case $1
when "lineHeight"
@line_height = $2.to_i
when "base"
@baseofs = $2.to_i
end
end
end
elsif l =~ /^char (.+) letter=\"(.)\"$/
# 1文字分の情報を取得
str, c = $1, $2
p = {}
str.split(' ').each do |s|
p[$1] = $2.to_i if s =~ /^(\S+)=(\d+)$/
end
id, x, y, w, h = p["id"], p["x"], p["y"], p["width"], p["height"]
xs, ys, xa = p["xoffset"], p["yoffset"], p["xadvance"]
cimg = img.slice(x, y, w, h) # 画像切り出し
@bmfont_array[id] = BMFontData.new(cimg, w, h, xs, ys, xa)
@height = h if @height < h
cnt += 1
end
end
}
img.dispose
end
# 配列として指定した際に、BMFont情報の構造体を返す
# @param [Integer] index 配列添字
def [](index)
return @bmfont_array[index]
end
end
# Windowクラスに追加するBMFont描画用メソッド
module Window
# BMFontを描画
# @param [Number] x 描画x座標
# @param [Number] y 描画y座標
# @param [String] str 描画文字列
# @param [Object] bmfont BMFontクラス
# @param [Number] z 描画優先順位
def self.draw_bmfont(x, y, str, bmfont, z = 0)
str.each_byte do |code|
x1 = x + bmfont[code].xofs
y1 = y + bmfont[code].yofs - bmfont.line_height + bmfont.baseofs
Window.draw(x1, y1, bmfont[code].image, z)
# Window.drawBoxFill(x, y, x+2, y+2, C_RED)
x += bmfont[code].xadvance + bmfont.spacing
end
end
end
# Imageクラスに追加するBMFont描画用メソッド
class Image
# BMFontを描画
# @param [Number] x 描画x座標
# @param [Number] y 描画y座標
# @param [String] str 描画文字列
# @param [Object] bmfont BMFontクラス
def draw_bmfont(x, y, str, bmfont)
str.each_byte do |code|
x1 = x + bmfont[code].xofs
y1 = y + bmfont[code].yofs - bmfont.line_height + bmfont.baseofs
self.draw(x1, y1, bmfont[code].image)
x += bmfont[code].xadvance + bmfont.spacing
end
end
end
if $0 == __FILE__
#テストコード
lst = [
"!\"\#$%&'()*+,-./0",
"123456789:;<=>?@",
"A B C D EFGHIJKLMNOP",
"QRSTUVWXYZ[\]^_`",
"abcdefghijklmnop",
"qrstuvwxyz{|}~"
]
# BMFontクラスを生成
bmfont = BMFont.new('mplus1p_heavy_0-export.png', 'mplus1p_heavy_0-export.fnt')
# 画像に描画してみる例
image = Image.new(640, 240)
x, y = 0, 0
lst.each do |s|
image.draw_bmfont(x, y, s, bmfont)
y += bmfont.height
end
Window.bgcolor = [96, 96, 96]
Window.loop do
break if Input.keyPush?(K_ESCAPE)
# 画面に描画してみる例
x, y = 0, 0
lst.each do |s|
Window.draw_bmfont(x, y, s, bmfont)
y += bmfont.height
end
Window.draw(0, 240, image)
end
end
こんな感じの表示に。
他のスクリプトから呼ぶときは、以下のような感じ。
_main.rb
require 'dxruby'
require_relative 'bmfont'
bmfont = BMFont.new("mplus1p_heavy_0-export.png", "mplus1p_heavy_0-export.fnt")
Window.loop do
y = 20
Window.draw_bmfont(100, y, "Hello DXRuby", bmfont)
y += bmfont.height
Window.draw_bmfont(100, y, " & BMFont", bmfont)
end
とりあえず、ファイル一式を置いときます。
_bmfontsupport_20141213.zip
同梱のBMFont画像は、M+フォントで作ったので、たぶん自由に使えるはず。
スクリプトソースは、DXRuby作者様のソースを丸写しに近いのでライセンスはよくわかりませんが、たぶん自由に使っていいんじゃないかなと。DXRubyのヘルプファイルにも、
添付のサンプルスクリプト及びドキュメント内のスクリプトは全てパブリックドメインとします。著作者人格権は行使しません。そのまま使うなり、改造するなり、著作権表示など一切いりませんのでご自由にどうぞ。と書いてありますし…。
[ ツッコむ ]
以上です。
