#!ruby -Ks # -*- mode: ruby; encoding: sjis -*- # Last updated: <2014/08/31 18:42:41 +0900> # # GMCMTのプロジェクトファイルを読みこんでみるテスト require 'dxruby' require 'pp' require 'json' class GmcmtAnimeObj attr_accessor :infile attr_accessor :gms_file attr_accessor :gmm_file attr_accessor :proj_info attr_accessor :gmm_info attr_accessor :gmm_parts_info attr_accessor :parts attr_accessor :parts_names attr_accessor :parts_count attr_accessor :parts_index_name attr_accessor :parts_indexs attr_accessor :imgs attr_accessor :dbg def initialize(infile, debug = false) @infile = infile @dbg = debug @parts = {} # パーツ配置情報を格納 @parts_count = 0 @parts_names = [] @gmm_info = {} @gmm_parts_info = {} @imgs = {} @parts_index_name = {} @proj_info = load_project_file(@infile) @gms_file = @proj_info["Project"]["PartsSetFileName"] @gmm_file = @proj_info["Project"]["MotionSetFileName"] # gmsファイル(json、パーツ配置情報)を読み込んで解析 load_gms(@gms_file) # 画像をロード load_imgs(@parts) end # # gmpファイル(プロジェクト設定)を読み込む # # @param [String] infile gmpファイル名 # @return [Hash] プロジェクト設定が入ったハッシュを返す # def load_project_file(infile) projinfo = Hash.new() name = "" f = File.open(infile, 'r') f.each do |l| next if l =~ /^$/ next if l =~ /^\s*\/\// if l =~ /^\[(.+)\]$/ name = $1 projinfo[name] = Hash.new() next elsif l =~ /^(\S+)\s*=\s*\"(.+)\"$/ projinfo[name][$1] = $2 next elsif l =~ /^(\S+)\s*=\s*(\S+)$/ projinfo[name][$1] = $2 next end puts "Unknown line" puts l end f.close return projinfo end # # gmsファイル(json、パーツ配置情報)を読み込んで解析 # # @param [String] gms_file gmsファイル名 # def load_gms(gms_file) json_data = open(gms_file) do |io| JSON.load(io) end json_data.each_key do |key| if key =~ /^(.+):([A-Z_]+)$/ objname = $1 classname = $2 case classname when "GMSPRITE_PARTS_NAME_JST_PARAMS" dt = json_data[key] @parts_names.push(dt["PartsName"]) when "GMSPRITE_PARTS_JST_PARAMS" @parts[objname] = json_data[key] when "GMSPRITE_JST_PARAMS" @gmm_info[objname] = json_data[key] when "GMSPRITE_PARTS_ARRAY_JST_PARAMS" @gmm_parts_info[objname] = json_data[key] @parts_count = @gmm_parts_info[objname]["PartsCount"].to_i else puts "#{objname} [#{classname}]" end next end puts "unknown line : #{key}" end end # # gmmファイル(json、モーション情報)を読み込んで解析 # # @param [String] gmm_file gmmファイル名 # def load_gms(gmm_file) json_data = open(gmm_file) do |io| JSON.load(io) end json_data.each_key do |key| if key =~ /^(.+):([A-Z_]+)$/ objname = $1 classname = $2 case classname when "GMSPRITE_PARTS_NAME_JST_PARAMS" dt = json_data[key] @parts_names.push(dt["PartsName"]) when "GMSPRITE_PARTS_JST_PARAMS" @parts[objname] = json_data[key] when "GMSPRITE_JST_PARAMS" @gmm_info[objname] = json_data[key] when "GMSPRITE_PARTS_ARRAY_JST_PARAMS" @gmm_parts_info[objname] = json_data[key] @parts_count = @gmm_parts_info[objname]["PartsCount"].to_i else puts "#{objname} [#{classname}]" end next end puts "unknown line : #{key}" end end # # 使用する画像をロード # # @param [Hash] parts パーツ配置情報 # def load_imgs(parts) @imgs = {} @parts_index_name = {} parts.each_key do |name| dt = parts[name] img_name = dt["SpriteName"] # 画像をロード @imgs[img_name] = Image.load(img_name) unless @imgs.has_key?(img_name) # インデックス値を配列に記録 @parts_index_name[dt["PartsIndex"].to_i] = name end # インデックス配列のソート @parts_indexs = @parts_index_name.keys.sort @parts_indexs.each do |idx| name = @parts_index_name[idx] puts "unknown #{idx} : #{name}" unless parts.has_key?(name) end end # # 度からラジアンに変換 # # @param [Number] deg 度 # @return [Number] ラジアン値 # def deg2rad(deg); return (deg * Math::PI / 180.0); end # # ラジアンから度に変換 # # @param [Number] rad ラジアン値 # @return [Number] 度 # def rad2deg(rad); return (rad * 180.0 / Math::PI); end # # 任意の座標値を回転 # # @param [Number] x x座標 # @param [Number] y y座標 # @param [Number] rad 回転角度(単位はラジアン) # @return [Array] 回転後のx,y座標 # def rot_point(x, y, rad) nsin = Math.sin(rad) ncos = Math.cos(rad) rx = x * ncos - y * nsin ry = x * nsin + y * ncos return rx, ry end # # 指定座標に十字を描画 # # @param [Number] x x座標 # @param [Number] y y座標 # @param [Number] col 描画色。[r,g,b] # def draw_cross(x, y, col) z = 100 w = 4 Window.drawLine(x, y - w, x, y + w, col, z) Window.drawLine(x - w, y, x + w, y, col, z) end # # グリッドを描画 # # @param [Number] bx 中心x座標 # @param [Number] by 中心y座標 # @param [Array] col 描画色配列 [r,g,b]。省略時は灰色 # @param [Number] w グリッド幅。省略時は64dot # def draw_grid(bx, by, col = [128,128,128], w = 64) 0.step(Window.width / 2, w) do |x| Window.drawLine(bx + x, 0, bx + x, 480, col) Window.drawLine(bx - x, 0, bx - x, 480, col) end 0.step(Window.height / 2, w) do |y| Window.drawLine(0, by + y, 640, by + y, col) Window.drawLine(0, by - y, 640, by - y, col) end end # # 多関節キャラを描画 # # @param [Number] bx 描画基準座標x # @param [Number] by 描画基準座標y # @param [Number] brot 描画基準角度 (単位は度) # def draw(bx, by, base_rot) parts_pos = {} parts_pos[""] = { :x => bx, :y => by, :bonelen => 0.0, :rot => deg2rad(base_rot) } @parts_indexs.each do |i| name = @parts_index_name[i] dt = @parts[name] img_name = dt["SpriteName"] parent = dt["ParentName"] z = dt["Priority"] bone_len = dt["fBoneLength"] f_rot = dt["fRotation"].to_f # rad float_bone = dt["bFloatBone"] afpt_x, afpt_y = dt["afPt"] imgax, imgay = dt["afImagePt"] scalex, scaley = dt["afImageScale"] imgrot = dt["fImageRotation"].to_f # rad # 親の座標情報等を得る pdt = parts_pos[parent] px = pdt[:x] py = pdt[:y] plen = pdt[:bonelen] prot = pdt[:rot] crot = prot + f_rot rot = rad2deg(crot + imgrot) if float_bone # 浮動ボーン ax, ay = rot_point(afpt_x, afpt_y, -prot) cx = px + ax cy = py - ay ax, ay = rot_point(imgax, -imgay, crot) x = cx + ax y = cy + ay else # 固定ボーン cx = px + (plen * Math.cos(prot)) cy = py + (plen * Math.sin(prot)) ax, ay = rot_point(imgax, imgay, crot) x = cx + ax y = cy + ay end if @dbg # 中心点を十字で描画 draw_cross(cx, cy, C_RED) draw_cross(x, y, C_BLUE) end # 画像を描画 Window.draw_ex(x, y, @imgs[img_name], :scalex => scalex, :scaley => scaley, :angle => rot, :z => z, :offset_sync => true) # 自身の座標や角度を親情報として記録 parts_pos[name] = { :x => cx, :y => cy, :bonelen => bone_len, :rot => crot } end end end # ---------------------------------------- # 動作確認 if __FILE__ == $0 # infile = "pos_set_test.gmp" infile = "walk_test.gmp" obj = GmcmtAnimeObj.new(infile) bx, by = 320, 240 brot = 0 Window.loop do break if Input.keyPush?(K_ESCAPE) # 本体角度をキー入力で変更 brot += 1 if Input.keyDown?(K_UP) brot -= 1 if Input.keyDown?(K_DOWN) obj.draw_grid(bx, by) # グリッドを描画 obj.draw(bx, by, brot) # 全パーツを描画 end end