mieki256's diary



2013/12/22() [n年前の日記]

#1 [ruby] YARDってreadme.mdをindex.htmlに反映してくれるのか…

.rbファイルと一緒に readme.md を書いて置いといたら、yardoc 実行時、index.html が readme.md の内容を取り込んだ状態になって、一瞬困惑しつつも感動したり。気が利くなあ…。

ただ、readme.md から doc/ 以下にリンクを張ろうとしていたので困ったりもして。doc/ 以下に置かれること前提で書いといたほうがいいのかな。しかしソレだと、readme.md を単体で読もうとしたときに、よく分からない状態に。どうしよう。

yardoc のコマンドラインオプションに、-r、--readme、--main FILE というのがあるあたりも気になる。--no-readme とか無いのかな。

#2 [dxruby][game] DXRubyでtmxファイルを使ってBG表示

_Tiled Map Editor の .tmxファイルを、tmx ライブラリを使って読み込んで、DXRuby で表示、かつ、地形アタリ処理をしてみるソレが、そこそこなんとか動くようになってきた…ような気がするのでアップロード。

動作してる様子

以下のソースで動いてます。(メイン処理のみ)

mapdisp.rb
#= Tiledの .tmx を読んで、表示と地形アタリ判定をするサンプル
#
# * カーソルキーでカーソル移動
# * WASDキーでスクロール
# * Bキーで、BGアタリレイヤーを表示/非表示
# * Hキーで、ぶら下がり棒とアタリをとるか否かを切替
# * ESCキーで終了

require 'dxruby'
require 'tmx'
require_relative 'dxrbtmx'
require_relative 'bgatari'

font = Font.new(14)
Window.frameskip = false

# 画面サイズ(ドット数)を取得
scrw = Window.width
scrh = Window.height

# BG描画に使うタイル画像を読み込む
bgimg = Image.loadTiles("bg_attari.png", 256/16, 256/16)

# BGマップファイル(.tmx)を読み込む
tmx = DxrbTmx.new("./bg_atari_test.tmx", scrw, scrh)

# レイヤー名を指定して、DXRubyの描画用マップデータ(二次元配列)を取得
atari_layer = tmx.get_layer("bg_atari")
bg_layer0 = tmx.get_layer("layer0")
bg_layer1 = tmx.get_layer("layer1")
bg_layer2 = tmx.get_layer("layer2")
bg_layer3 = tmx.get_layer("layer3")

# 画面を占めるタイル個数を取得
bgtw = tmx.screenwidth
bgth = tmx.screenheight

# BGアタリ判定用テーブルを作成
#
# 以下の引数を渡す
#
# 1. アタリ判定用の画像配列(Image.loadTiles() で読み込んだ画像)
# 2. BGアタリマップデータ(二次元配列)
# 3. 画面横幅ドット数
# 4. 画面縦幅ドット数
# 5. 抜けアタリ番号 (省略時は 0番を抜けとして扱う)
# 6. 非床アタリ開始番号 (省略可能)
# 7. 非床アタリ終了番号 (省略可能)
#
bgatari = BgAtari.new(bgimg, atari_layer, scrw, scrh, 0, 22, 30)

bx, by = 0, 0 # スクロール位置初期化
px, py = scrw / 2, scrh / 2 # カーソル位置初期化
atari_disp = true # BGアタリを描画するかどうかのフラグ
floor = true # ぶら下がり棒のアタリは無視するか否かのフラグ

# カーソル描画用メソッド
def draw_cursor(x, y, col)
  w = 2
  Window.drawLine(x - w, y, x + w, y, col)
  Window.drawLine(x, y - w, x, y + (w + 1), col)
end

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE) # ESCキー押しで終了

  # Bキーで、BGアタリを描画するかしないかを切り替える
  atari_disp = !atari_disp if Input.keyPush?(K_B)

  # Hキーで、ぶら下がり棒アタリを無視するかしないかを切り替える
  floor = !floor if Input.keyPush?(K_H)

  # WASDキーでスクロール
  spd = 4.0
  bx -= spd if Input.keyDown?(K_A)
  bx += spd if Input.keyDown?(K_D)
  by -= spd if Input.keyDown?(K_W)
  by += spd if Input.keyDown?(K_S)
  
  # カーソルキーでカーソル移動
  spd = 1.0
  px += Input.x * spd
  py += Input.y * spd

  # BG描画
  if atari_disp
    # BGアタリのみ描画
    Window.drawTile(0, 0, atari_layer, bgimg, bx, by, bgtw, bgth)
  else
    # 通常BGのみ描画
    Window.drawTile(0, 0, bg_layer3, bgimg, bx / 8, by / 8, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer2, bgimg, bx / 4, by / 4, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer1, bgimg, bx / 2, by / 2, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer0, bgimg, bx, by, bgtw, bgth)
  end

  # カーソル座標のBGアタリ番号を取得
  x = bx + px
  y = by + py
  bg_code = bgatari.get_bg_code(x, y)

  # カーソル座標がBGと当たってるかチェック
  chk_hit = bgatari.check_bg_hit(x, y, BgAtari::ADJUST_NONE, floor)
  col = (chk_hit)? [192, 255, 0, 0] : [192, 0, 128, 255]

  # カーソル座標描画
  draw_cursor(px, py, col)

  # 床補正座標を得る
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_UP, floor)
  hosei_code = bgatari.bg_code
  draw_cursor(nx - bx, ny - by, C_CYAN) if nx

  # 天井補正の座標を得る
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_DOWN, floor)
  draw_cursor(nx - bx, ny - by, C_CYAN) if nx

  # 壁補正の座標を得る
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_LEFT, floor)
  draw_cursor(nx - bx, ny - by, C_YELLOW) if nx
  
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_RIGHT, floor)
  draw_cursor(nx - bx, ny - by, C_YELLOW) if nx

  # BGアタリ番号その他の情報を描画
  yh = 16
  Window.drawFont(16, yh * 0, "FPS: #{Window.real_fps}", font)
  Window.drawFont(16, yh * 1, "input CURSOR、WASD,B,H key", font)
  Window.drawFont(16, yh * 2, "#{bg_code} : BG code", font)
  Window.drawFont(16, yh * 3, "#{hosei_code} : BG code (Floor adjust)", font)

end
一見すると長いのですが、見栄えを良くするために行数が増えちゃってるだけで…。処理の実体は、
.tmx の読み込みと変換
tmx = DxrbTmx.new( tmxファイル名, 画面横幅, 画面縦幅 )
レイヤー名を指定してBGマップデータ(二次元配列)を取得
atari_layer = tmx.get_layer(レイヤー名)
BGアタリ処理用のテーブル作成
bgatari = BgAtari.new(BGアタリ用画像配列, BGアタリに使うマップデータ, 画面横幅, 画面縦幅, 抜けアタリ番号, 床として扱わないアタリ開始番号, 床として扱わないアタリ終了番号)
BGアタリ番号を取得
bg_code = bgatari.get_bg_code(x, y)
BGと当たってるかチェック
chk_hit = bgatari.check_bg_hit(x, y, BgAtari::ADJUST_NONE, 床のみチェックするかをtrue/falseで)
BGアタリを元に座標補正(床補正)
nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_UP, 床のみチェックするかをtrue/falseで)
このあたりです。

使い回しができるように、別クラスにしてみました。
.tmxファイル、画像ファイル、スクリプト、各クラスのドキュメントを、zip にして Dropbox に置いておきます。Public Domain ってことで。

_dxruby_map_disp_20131222.zip

tmxライブラリについて。 :

_tmxライブラリ は、
gem install tmx
でインストールできます。 _multi_json_nokogiri も一緒にインストールされる模様。

tmx、nokogiri、multi_json、どれも MIT License のようですね。

アタリ判定用画像について。 :

アタリ判定用画像は、以下の画像(1タイル = 16x16ドット)を使ってます。

アタリ判定用画像

一番左上から、右に向かって、
  1. 抜けアタリ
  2. 進めない床
  3. フツーの床
  4. 斜め床…
と続いて…。青いところが、ぶら下がり棒用のアタリ。0〜31番までをアタリ判別用として使ってる状態です。

bgatari.rb の中で、この0〜31番を、1個ずつ、16x16ドットを全スキャンして、アルファ値が128以上ならその座標はアタリ有り、として扱ってます。

結局、やってることは、画像を読んで、ドットを見て、
[ [ [y最小値, y最大値] x 横ドット数 ], [ [x最小値, x最大値] x 縦ドット数 ] ]
という配列を作ってるだけなので、事前にそういう配列を用意して渡すように修正すれば、DXRuby 以外のライブラリでも bgatari.rb が使えるようになるのではと。…そういう作りにしといたほうがいいのかな。

先日アップした画像が参考になるかもしれないので再掲。

y最小値とy最大値があればアタリ判定できる

テーブルで持ってしまう

アタリ判定用データの扱いについて。 :

今回は、画像をスキャンして、アタリ判定用データを作ってるわけですが。

このあたり、以下のような作りでもいいんですけど、というか昔の自分は、そういうやり方してたんですけど。
  • あらかじめ、BGマップを作る前に、アタリ種類を決めておく。
  • アタリ種類毎に、数式だの条件分岐だので、必要な値を求める処理を書いておく。(一般的には switch 〜 case、Ruby なら case 〜 when になると思う)
  • BGアタリ番号と、アタリ種類の対応表を作っておく。

しかし…。
  • マップエディタやドットエディタで作業してるうちに、「もうちょっとアタリ種類を増やしたいな…」と考えてしまいがち。
  • アタリ種類を増やすの、メンドクサイ。数式や条件分岐を一々書くのは、メンドクサイ。
  • BGアタリ番号と、アタリ種類の対応表を作るのって、地味にメンドクサイ。
  • BGマップ側で使うアタリ種類の並びが変わっただけでも、対応表を作り直すので、メンドクサイ。
  • 曲線的なアタリの形に対応するのが、メンドクサイ。
とにかくメンドクサイ。

その点、今回のように、画像をスキャンして判別用データを作る方法なら…。
  • アタリ種類を増やしたり、並びを変える作業が、CGツール上で完結する。
  • 人間様が対応表を作らなくて済む。
  • 曲線的なアタリにも対応できる。
メンドクサくない。

その代り、
  • 画像の読み込み、かつ、ドットをチェックできるライブラリが必要。どこでも使い回せるソースにならない。
  • 毎回ゲームを動かすたびに、判別用データと対応表を作り直してるので、その処理時間が、ガチで無駄。
  • アタリ種類分のテクスチャ領域を、無駄遣いしてる。
というデメリットはありますが。

とりあえず、プロトタイプをサクッと、てな段階では、今回のやり方も有効なのかもしれないなと。このあたり、判別用データを別途出力するスクリプトを書くだけでも作業は楽になると思うのですが、そのスクリプトを動かす操作すら、プロトタイプ作成段階ではメンドクサイよなと…。

アプリとして完成間近で、実行バイナリに、無駄な処理も無駄なデータも入れたくない、という状態なら…。ツールを作って、判別用データを出力して、それをソース内に列挙、あるいは、別ファイルとして同梱して読み込む、という流れがベターではないかと。

でも、LL使ってゲーム作ってる時点で…。どうせ富豪的プログラミングをしてるわけですし…。このあたりのデータを毎回作り直しちゃってもいいよな、という気もするのでした。ンMbitのROMに収めて、ンMHzのCPUで動かすわけでもないし。

2017/03/19追記。 :

Dropboxのpublicフォルダが死んだのでファイルの置き場所を変更。

#3 [game] ドンキーコングと斜め床

先日、 _ファミコンリミックスなるゲームの宣伝映像? を眺めてたら、「あっ!」と気付いたことがあって。

最初の頃のマリオには斜め床は無いと思ってたけど、そもそもマリオが初登場した _ドンキーコング で、1面からいきなり斜め床だったのですな…。すっかり忘れてましたよ…。

ドンキーコングは、「樽が転がってくるからジャンプして避けるべし」というゲームだったけど。「樽が転がってくるんだよ」ということを、見ただけで間違いなく伝えるためには、斜め床は必須だよなと思えてきたり。あの床が平らだったら、樽がどっちに転がってくるのか分からないので、ビミョーにクソゲーになりそうな予感も。

_MZ-700のドンキーゴリラ はどうだったかな…。うむ…平らだ…。なかなか厳しい…のかなと思ったけど、意外とそうでもないような。樽は一方向にしか転がらないので、全体の流れはまだ分かるなと。樽より、火の玉の動きのほうが、よほどヤバイ。どう動くか分からん。

ターザンのゲームも思い出した。 :

_ジャングルキング というタイトルだったらしい。タイトー製。小学生の頃、駄菓子屋でコレをプレイしたのが、TVゲーム初体験、だったかなあ…。自分に限らず、近所の子供達が皆でコレに夢中になったものだから、学校+PTAで問題になった、と、後になってから聞いたっけ。

記憶の中では、左→右へと進んでたと思ってたけど。右→左、つまり一般的な横スクロールゲームとは逆方向だったのだな。記憶って、容易に改竄されてしまうのだなと、なんだか怖くなってきた。

それはともかく。3面目で斜め床が出てくる。コレも、「岩が転がってくるから避けるべし」という、ドンキーコングと同じ遊びで。何かが転がってくるぞとプレイヤーに分からせる際、斜め床は視覚的に大変有効、なのかもしれないと思えてきたり。

さておき、1面目で、多関節のロープが動いてるあたりが気になる…。当時からこんなスゴイことやってたのか…。しかし、気にはなるんだけど、なんだか各ロープにつかまった時に、プレイヤーキャラの座標移動のフレームレートが変わってるような気もする。もしかして、ロープの動きは全部テーブルで持ってて、アニメの再生速度を変えてるだけ、だったのでは。どうなんだろう。まあ、それでも、どうやって実装すればいいのか考え始めると、ちょっと軽く悩んじゃうのだけど。

マリオ3が気になる。 :

_「マリオ1には斜め床は無いが、マリオ3には斜め床がある」 という話を知って、興味が湧いてきたり。自分、マリオ1しか遊んでないので、2とか3とか全然知らなくて。どういうゲームだったんだろう…。

ググって辿り着いた、 _マリオ3小ネタ集 - YouTube_スーパーマリオ3  ファミコン スーパープレイ 最短攻略 TAS - YouTube を眺めて、「あわわわ…」てな気分になってきたり。地形アタリ絡みのバグは…精神衛生上よくないなと…。いや、バグじゃなくて、こういう仕様なのかもしれないか。

画面を見ていて、「なんだか _ギミック! みたいだな」と思ったけれど。発売日を調べてみたら、ギミックより何年も前だったらしい。ていうかソニックよりも前なので、どうもソニックの回転技は、マリオ3の回転技からのインスパイアだったのかなと思えてきたけど、そのへんどうなんでしょうか。

ギミックは、斜め床に立つとつるつる滑り落ちる仕様だったけど。マリオ3もそれっぽい動きをしてる時があるように見えるので、「斜め床=滑り落ちるので操作が大変」という遊びを入れるのが常、だったりするのかなとも思えてきたり。

SFC版魂斗羅も思い出してきた。 :

1面目の、爆撃機が近づいてくるシーンで ―― 爆撃機なのに何故かヘリコプターの「バタバタバタ」という音を出してるあたりが魂斗羅らしさだと思うのだけど ―― あのシーンで、斜め床の上に立って両手に銃を構える例のポーズを取っていたことを今頃思い出したり。あの時、足は、ちゃんと斜め床と一致した角度になってた気がする。

_魂斗羅スピリッツ (Contra 3 : The Alien Wars) 1/3 - YouTube の1:50〜や5:30〜あたりを見て、やっぱりそうだったなと。なるほど、その流れで、ガンスターヒーローズも斜め床用のポーズを持ってたのかしら。

アーケード版の魂斗羅はどうだったかなと思って動画を探してみたけど、無印は斜め床が無くて、Superで斜め床アリになったようで。ただ、斜め床の上で止まってるシーンが見つからず。まあ、平らな床の上でも足を閉じて銃を撃ってるから、斜め床でも足を閉じて撃ってそうかなと…。だとすれば、SFC版以降から斜め床用のポーズをちゃんと用意するようになった、ということになるのかしらん。

お行儀よく足を閉じて撃ってるポーズより、足をガバッと開いて踏ん張って撃ってるほうが、見た目カッコイイなと。例えばロックマンも、足を閉じて撃ってたら、それはなんかちょっと…。

ただ、斜め床用のポーズを作るのって、地味に面倒で。

斜め床に対応させるとパターン数がグングン増える。 :

一般的に2Dゲームって、キャラが右向きから左向きになる時、グラフィックを左右反転すればいいのだけど。 *1 斜め床用のポーズを作ってある場合は、そう単純にはいかなくて。右上がりの坂+右向きで立ってる状態から、十字ボタンを押して左向きにした際、ただ左右反転だけしちゃうと足がとんでもない状態に。

加えて、走りアニメも、伏せをする時も、床の角度に対応させようとか考え始めると…。「床の角度に合わせた足の角度にする」だけで、パターン数がグングン増えていって、頭が少しこんがらがってくる…。

しかも、銃を八方向に撃てる、なんて仕様だと…。今まで書いてきたことの、更に8倍のパターン数に。いや、右を向いている時は左には撃てない、とかなら、パターン数が8→5に減って、まだちょっとアレだけど。右向きに走ってるけど左にも撃てるよ、みたいな仕様だったら、もう何が何やら。上半身と下半身を分割して管理したほうがいいのかな…。PS1の某3Dゲームも、ちょっとそんな感じがしたなあ…。上半身と下半身が別々に動いてる感じで…。

そんなわけで、銃を撃つタイプの2Dゲームは、昔のロックマンみたいに、右向きなら右にしか、左向きなら左にしか撃てない仕様だと、随分楽になりそうだなと思えてきたり。そういう仕様なら、斜め床も対応できそうな気がしてくる…。更に、走りながらは撃てない、撃つ時は必ず止まる、てな仕様だともっと楽に。ってそこまで楽しちゃうとアレですね。

*1: もちろん、右向き左向きでちゃんとグラフィックを変更する、こだわって作ってあるタイトルも多々あるけれど。

以上、1 日分です。

過去ログ表示

Prev - 2013/12 - Next
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project