2013/12/24(火) [n年前の日記]
#3 [dxruby][game] DXRubyで地形アタリを取りながらプレイヤーキャラの移動その2
今日も、DXRuby を使って、地形の上でプレイヤーキャラを動かす実験をしてみますよ。
以下のソースを動かすには、 _DXRubyでtmxファイルを使ってBG表示 で公開してる、 _dxruby_map_disp_20131222.zip と、 _player_512x256_64x64.png が必要です。
以下のソースを動かすには、 _DXRubyでtmxファイルを使ってBG表示 で公開してる、 _dxruby_map_disp_20131222.zip と、 _player_512x256_64x64.png が必要です。
◎ 昨日のソースの補足。 :
_昨日のソース
について、言及することを忘れてた部分があるので、念のために補足しておきます。
床とアタリチェックする時、ちょっと妙なことをしていまして。
「なんでそんな珍妙なことするの? 足元のBGアタリだけ見ればいいじゃん?」と思う方も居るかもしれませんね。ですので、あえて、足元しか見ないソースを書いて動かしてみました。
斜め床を登っていく時はいいのですけど、下る時に「あわわわわ!」みたいな状態になりますな。
要は、以下のようなことが起きてしまうわけです。
昔のゲームでも、こういうの、たまーに見かけましたけどね…。
なので、足元からちょっと下のあたりをチェックしてるわけです。
ですが、ジャンプ中や落下中も、同じように足元からちょっと下を見てるままだと、よろしくない状態になります。
ですので、「床の上に立っている時」と「ジャンプ中・落下中」で、BGアタリを見る位置を変えてみたのでした。
このあたり、もっと上手い方法があるんじゃないかと思うのですけど…。これもこれで、地形によっては何か問題が出そうな気もするんですよね…。まあ、今後の課題ってことで。
床とアタリチェックする時、ちょっと妙なことをしていまして。
if pimgnum == 16 # 落下中 yadd = 0 else # 床の上に居る # 足元よりちょっと下の座標でアタリを取る yadd = 16 end nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP)図で描くと、下のような感じです。
「なんでそんな珍妙なことするの? 足元のBGアタリだけ見ればいいじゃん?」と思う方も居るかもしれませんね。ですので、あえて、足元しか見ないソースを書いて動かしてみました。
# 足元しか見ないとどうなるかな…? yadd = 1 nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP)_playermove1_bug1.rb.txt
斜め床を登っていく時はいいのですけど、下る時に「あわわわわ!」みたいな状態になりますな。
要は、以下のようなことが起きてしまうわけです。
なので、足元からちょっと下のあたりをチェックしてるわけです。
ですが、ジャンプ中や落下中も、同じように足元からちょっと下を見てるままだと、よろしくない状態になります。
ですので、「床の上に立っている時」と「ジャンプ中・落下中」で、BGアタリを見る位置を変えてみたのでした。
このあたり、もっと上手い方法があるんじゃないかと思うのですけど…。これもこれで、地形によっては何か問題が出そうな気もするんですよね…。まあ、今後の課題ってことで。
◎ 壁補正をしてみたり。 :
さておき。
_昨日のソース
は、壁の中に入ってしまうと大惨事になったので、壁補正を入れてみました。
_playermove2_bug.rb.txt
さて、結果は。
Oops! 左右に進めません…。なんでや…。
こういう状態になってるわけですな。
さて、どうやって解決しよう…。
考えてみたら、壁として扱うべきBGアタリは、今のところ四角いブロックだけですので…。横方向にBGアタリがあった際、ソレが四角いブロック(壁相当)だった時だけ、壁補正をすることにしてみましょうか。
_playermove2.rb.txt
…Ruby って、「その範囲の中に入ってるか?」を、こういう風に書けるのですな。今まで知りませんでした…。(ググってみて知りました…。) Ruby、便利だなあ。
うむ。これで大丈夫そうです。
しかし、コレ、穴に落ちたら脱出できませんな…。明日は、ジャンプ処理を追加して、もっとあちこちに動けるようにしましょうかね。
_playermove2_bug.rb.txt
# プレイヤーキャラを動かしてみるサンプルその2 # # 横移動、落下処理、床補正に加えて、壁補正もするが… require 'dxruby' require 'tmx' require_relative 'dxrbtmx' require_relative 'bgatari' # 画像読み込み pimg = Image.loadTiles("player_512x256_64x64.png", 512 / 64, 256 / 64) bgimg = Image.loadTiles("bg_attari.png", 256 / 16, 256 / 16) # tmx読み込み scrw, scrh = Window.width, Window.height tmx = DxrbTmx.new("./bg_atari_test.tmx", scrw, scrh) # Bgレイヤーマップデータ取得 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, bgth = tmx.screenwidth, tmx.screenheight # BGアタリテーブル作成 bgatari = BgAtari.new(bgimg, atari_layer, scrw, scrh, 0, 22, 30) # カーソル描画用メソッド 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 # プレイヤーのアニメパターンを定義 ppat = { "walk" => 0, "jump" => 16} pimgnum = ppat["jump"] bx, by = 0, 0 px, py = scrw / 2, scrh / 2 dx, dy = 0, 0 gravity = 0.45 bgatari_disp = false # メインループ Window.loop do break if Input.keyPush?(K_ESCAPE) # Bキーを押したらBGアタリ表示と切替 bgatari_disp = !bgatari_disp if Input.keyPush?(K_B) # プレイヤー移動処理 # 左右キーで横移動 # x速度に、キー入力に応じて加速度を加算 dx += Input.x * 0.2 # 横方向の最大速度を超えないようにする spdmax = 6.0 dx = spdmax if dx >= spdmax dx = -spdmax if dx < -spdmax # 左右キーを押してなければ、速度を減らしていく dx *= 0.95 if Input.x == 0 # 速度を加算 px += dx py += dy # ---------------------------------------- # 壁アタリで補正する ← new! # 右側にBGアタリがあるかチェック xadd, yadd = 32, -32 nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_LEFT) if nx # 右方向にアタリがある px = nx - xadd # 座標を補正 dx = 0 # x速度を0に end # 左側にBGアタリがあるかチェック xadd, yadd = -32, -32 nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_RIGHT) if nx # 左方向にアタリがある px = nx -xadd # 座標を補正 dx = 0 # x速度を0に end # 壁アタリ補正ここまで # ---------------------------------------- # 床アタリで補正する # 床の上に居る時だけ、足元よりちょっと下の座標でアタリを取る yadd = (pimgnum == ppat["jump"])? 0 : 12 nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP) if nx == nil # 足元に床が無い dy += gravity # 重力加速度を、速度に加算 pimgnum = ppat["jump"] # 落下ポーズに変更 else # 足元に床がある py = ny dy = 0 # y速度を0にする pimgnum = ppat["walk"] # 床の上に居るポーズに変更 end # プレイヤー移動処理ここまで # プレイヤーの位置から、BGスクロール座標を決定 bx += ((px.to_i - (scrw / 2) - bx) * 0.2).to_i by += ((py.to_i - (scrh / 2) - by) * 0.2).to_i # BG描画 if bgatari_disp Window.drawTile(0, 0, atari_layer, bgimg, bx, by, bgtw, bgth) else 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 # プレイヤー描画 x = px - bx y = py - by img = pimg[pimgnum] Window.draw(x - 32, y - 57, img) # プレイヤー座標にカーソルを描画 draw_cursor(x, y, C_RED) draw_cursor(x + 32, y - 32, C_RED) draw_cursor(x - 32, y - 32, C_RED) end床補正をする直前に、壁補正を入れてみました。
さて、結果は。
Oops! 左右に進めません…。なんでや…。
こういう状態になってるわけですな。
さて、どうやって解決しよう…。
考えてみたら、壁として扱うべきBGアタリは、今のところ四角いブロックだけですので…。横方向にBGアタリがあった際、ソレが四角いブロック(壁相当)だった時だけ、壁補正をすることにしてみましょうか。
_playermove2.rb.txt
# 右側にBGアタリがあるかチェック xadd, yadd = 32, -32 nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_LEFT) if nx and (1..2).member?(bgatari.bg_code) # 右方向に「壁」アタリがある px = nx - xadd # 座標を補正 dx = 0 # x速度を0に end(1..2).member?(bgatari.bg_code) で、BGアタリ番号が 1〜2 の時だけ、壁補正をする、という処理になってます。
…Ruby って、「その範囲の中に入ってるか?」を、こういう風に書けるのですな。今まで知りませんでした…。(ググってみて知りました…。) Ruby、便利だなあ。
うむ。これで大丈夫そうです。
しかし、コレ、穴に落ちたら脱出できませんな…。明日は、ジャンプ処理を追加して、もっとあちこちに動けるようにしましょうかね。
◎ 壁補正についての余談。 :
ところで。上記の解決方法 ―― 壁相当とだけ壁補正をするというやり方も、ちと問題がありまして。下のような地形では、マズイことになるのです。
どうやって解決するかは…。さて、どうすればいいのでしょう?
自分が今思いつくのは、2つぐらい、かなあ…。
一つは、壁相当とだけ壁補正するのはやっぱりやめて、BGアタリがあったらとにかく「壁」扱いしちゃう方法。最初の実装に戻しちゃうというか。その代わり、斜め床まで壁になったりしない程度に、壁をチェックする距離を短くする、とか。
もう一つは、壁アタリをチェックする位置を、もっと増やす方法。
ただし、メインの壁補正 → 床補正 → サブの壁補正、といった具合に、チェックする順番に工夫が必要かもしれません。そうしないと、下図のようなバグが発生しそうだなと。
あるいは、「どうも壁っぽいものがありそうなんだけど…普段見ている位置のBGアタリ番号だけでは確定できないなあ。念のために他の位置もあちこち見て判断するか」てな対処でもいいのかしら。
まあ、手っ取り早い解決策として、「おかしなことになる地形は作らない」という手も…。最悪、解決策がさっぱり思いつかないなら、そういうルールでマップを用意するのもアリですね。
どうやって解決するかは…。さて、どうすればいいのでしょう?
自分が今思いつくのは、2つぐらい、かなあ…。
一つは、壁相当とだけ壁補正するのはやっぱりやめて、BGアタリがあったらとにかく「壁」扱いしちゃう方法。最初の実装に戻しちゃうというか。その代わり、斜め床まで壁になったりしない程度に、壁をチェックする距離を短くする、とか。
もう一つは、壁アタリをチェックする位置を、もっと増やす方法。
まあ、手っ取り早い解決策として、「おかしなことになる地形は作らない」という手も…。最悪、解決策がさっぱり思いつかないなら、そういうルールでマップを用意するのもアリですね。
◎ 2017/03/19追記。 :
Dropboxのpublicフォルダが死んだのでファイルの置き場所を変更。
[ ツッコむ ]
以上です。