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のヘルプファイルにも、
添付のサンプルスクリプト及びドキュメント内のスクリプトは全てパブリックドメインとします。著作者人格権は行使しません。そのまま使うなり、改造するなり、著作権表示など一切いりませんのでご自由にどうぞ。と書いてありますし…。
[ ツッコむ ]
#2 [dxruby][cg_tools] BMFontの作り方
一応、
_ShoeBox
を使った BMFont の作り方もメモ。
ShoeBox を起動して、「GUI」タブを選択。
「Bitmap Font」のアイコンをクリックすると、「Cpoied Text to Clipboard」ってメッセージが点滅表示されて、必要な文字列がクリップボードにコピーされます。
_bmfont_string.txt
に、文字列を貼り付けときました。
この文字列を使って、一旦、横に長いフォント画像を作成します。
自分の場合はGIMPで作成。画像を新規作成。
横幅が6,000ドットぐらいの、でかい画像に。
テキストツールを選択。
テキストツールを使って、先ほどクリップボードにコピーしてあった文字列を貼り付けて(Ctrl +V で貼り付け)、文字を描画。
ブレンドツール(グラデーション塗りするツール)その他を使って化粧。
レイヤーウインドウで右クリックして「可視レイヤーの統合」。
「画像」→「画像の自動切り抜き」で、最小限の大きさの画像に。レイヤー統合する前にコレ使うと切り取られ過ぎちゃうので、レイヤー統合してから使ってます。
「ファイル」→「Export As...」で、png画像として保存。
ShoeBox に、今保存したpng画像をドラッグアンドドロップ。
すると、下のようなウインドウが開く…はず。
右下の「Settings」で、テクスチャの詰め方や、ビットマップフォントのフォーマットを選べるようですが、とりあえず「Default」にしておけばヨサゲ。
「Save Font」をクリックすれば、元のpng画像のあるフォルダに、
ShoeBox を起動して、「GUI」タブを選択。

「Bitmap Font」のアイコンをクリックすると、「Cpoied Text to Clipboard」ってメッセージが点滅表示されて、必要な文字列がクリップボードにコピーされます。

この文字列を使って、一旦、横に長いフォント画像を作成します。
自分の場合はGIMPで作成。画像を新規作成。

横幅が6,000ドットぐらいの、でかい画像に。

テキストツールを選択。

テキストツールを使って、先ほどクリップボードにコピーしてあった文字列を貼り付けて(Ctrl +V で貼り付け)、文字を描画。

ブレンドツール(グラデーション塗りするツール)その他を使って化粧。

レイヤーウインドウで右クリックして「可視レイヤーの統合」。

「画像」→「画像の自動切り抜き」で、最小限の大きさの画像に。レイヤー統合する前にコレ使うと切り取られ過ぎちゃうので、レイヤー統合してから使ってます。

「ファイル」→「Export As...」で、png画像として保存。
ShoeBox に、今保存したpng画像をドラッグアンドドロップ。
すると、下のようなウインドウが開く…はず。
右下の「Settings」で、テクスチャの詰め方や、ビットマップフォントのフォーマットを選べるようですが、とりあえず「Default」にしておけばヨサゲ。
「Save Font」をクリックすれば、元のpng画像のあるフォルダに、
- 元画像-export.fnt
- 元画像-export.png
[ ツッコむ ]
#3 [nitijyou] 某所に行ってきた
Word文書とExcel文書を作成できたので、電動自転車で届けに。PM03:00-PM04:45までお邪魔してきた。詳細はGRPでメモ。
帰りは雪が降ってきた。トホホ。リオンドールとダイソーに回って、ファイルやら夜食やらを購入。
帰りは雪が降ってきた。トホホ。リオンドールとダイソーに回って、ファイルやら夜食やらを購入。
◎ イイ感じの教え方はないものか。 :
相手は、PCに触ること自体が初めての方なので、
仮に本を渡したとしても、ほとんどの場合、読んでもらえないだろうし。TV番組っぽい動画チュートリアルでもあれば分かりやすいのだろうか。
アプリの言うとおりに操作していくと覚えられる、みたいなソフトって無いのかな。ソースネクストあたりで出してそうだな…。
ググってみたら、Excel の操作を覚えられるアプリ、みたいなものがソースネクストから出てるらしい。しかし、2007/2010/2013対応版…。2003版はもう入手不可っぽい。当たり前か。なかなか難しい。
- マウスの左ボタン、右ボタン、ホイールの使い分け
- Deleteキー、Page Up/Downキー、カーソルキーの存在
仮に本を渡したとしても、ほとんどの場合、読んでもらえないだろうし。TV番組っぽい動画チュートリアルでもあれば分かりやすいのだろうか。
アプリの言うとおりに操作していくと覚えられる、みたいなソフトって無いのかな。ソースネクストあたりで出してそうだな…。
ググってみたら、Excel の操作を覚えられるアプリ、みたいなものがソースネクストから出てるらしい。しかし、2007/2010/2013対応版…。2003版はもう入手不可っぽい。当たり前か。なかなか難しい。
[ ツッコむ ]
以上、1 日分です。



