2013/12/25(水) [n年前の日記]
#3 [dxruby][game] DXRubyで地形アタリを取りながらプレイヤーキャラの移動その3ひとまず完結編
今日も、DXRubyを使って、プレイヤーキャラを動かしてみますよ。
_昨日の時点 では、壁にめり込まなくなったものの、穴に落ちるとそこから脱出できなくなったので、今日はジャンプ処理を追加してみようかと。
下のようなソースになりました。
playermove3.rb
途中で、空中床(?)にも飛び乗れてますが…。どうやっているのかと言うと…。
ちなみに、マップの一番右のほうに、怪しいことが起きそうな地形を、いくつか置いておきました。個人的には、小さい段差で「ガクッ」と補正されるあたりが、気になりますなあ…。
とりあえず、ここまでのソースも画像も、zipファイルにまとめて、Dropboxに置いときますね。exeファイル以外は Public Domain ってことで。(exeファイルだけは、MIT License の tmxライブラリを含んでるので、ライセンスがよく分からず…。再配布するぐらいなら問題ないと思ってるんですが、どうなんだろう?)
_dxruby_map_disp_20131225.zip
他にも実装したい部分はありますが…。
今回は、というか今年の DXRuby関係の記事は、これで最後にしたいと思います。どうにか、「一人DXRuby Advent Calendar 201」 も、そこそこやり遂げられたような気もしますし…! *1
_昨日の時点 では、壁にめり込まなくなったものの、穴に落ちるとそこから脱出できなくなったので、今日はジャンプ処理を追加してみようかと。
下のようなソースになりました。
playermove3.rb
# プレイヤーキャラを動かしてみるサンプルその3 # # 横移動、落下処理、床補正、壁補正、 # ジャンプ、天井補正をする。 require 'dxruby' require 'tmx' require_relative 'dxrbtmx' require_relative 'bgatari' font = Font.new(12) # 画像読み込み 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) # 空中床 float_floor = 21 # カーソル描画用メソッド 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 wall_dist = 16 # 壁アタリをチェックする距離 ceiling_dist = 54 # 天井アタリをチェックする距離 # スクロール座標の範囲 scrl_spc = 16 bx_min = scrl_spc by_min = scrl_spc bx_max = tmx.map_width - Window.width - scrl_spc by_max = tmx.map_height - Window.height - scrl_spc # メインループ 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 # ジャンプボタン(Zキー/ゲームパッドのボタン0)が押されていたら、ジャンプする # …このままだと空中でもジャンプできちゃうけど、なんだか面白いから残しとく # if Input.padPush?(P_BUTTON0) if Input.padDown?(P_BUTTON0) # dy = -16 # y速度を上向きに設定 dy = -10 # y速度を上向きに設定 pimgnum = ppat["jump"] # ジャンプポーズにする end # 速度を加算 px += dx py += dy # 天井アタリで補正する if dy < 0 # y速度が上向きの時だけ天井アタリを見る xadd, yadd = 0, -ceiling_dist nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_DOWN) if nx and bgatari.bg_code != float_floor # 天井側に、空中床以外のBGアタリがある py = ny - yadd # 座標を補正 dy = 0 # y速度を0にする end end # 壁アタリで補正する # 右側にBGアタリがあるかチェック # xadd, yadd = 32, -32 xadd, yadd = wall_dist, -32 nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_LEFT) if nx and bgatari.bg_code != float_floor # 右方向に、空中床以外のアタリがある px = nx - xadd # 座標を補正 dx = 0 # x速度を0に end # 左側にBGアタリがあるかチェック # xadd, yadd = -32, -32 xadd, yadd = -wall_dist, -32 nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_RIGHT) if nx and bgatari.bg_code != float_floor # 左方向に、空中床以外のアタリがある px = nx - xadd # 座標を補正 dx = 0 # x速度を0に end # 床アタリで補正する if dy < 0 # 上向きに飛んでいる dy += gravity # 重力加速度を、速度に加算 else # 下向きに飛んでいる、もしくは、床の上に居る # 床の上に居る時だけ、足元よりちょっと下の座標でアタリを取る 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 end # プレイヤー移動処理ここまで # プレイヤーの位置から、BGスクロール座標を決定 bx += ((px.to_i - (scrw / 2) - bx) * 0.25).to_i by += ((py.to_i - (scrh / 2) - by) * 0.25).to_i if true # スクロール範囲を制限する場合 bx = bx_min if bx < bx_min by = by_min if by < by_min bx = bx_max if bx > bx_max by = by_max if by > by_max end # 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 Window.draw(x - 32, y - 57, pimg[pimgnum]) # プレイヤー座標にカーソルを描画 draw_cursor(x, y, C_RED) draw_cursor(x + wall_dist, y - 32, C_RED) draw_cursor(x - wall_dist, y - 32, C_RED) draw_cursor(x, y - ceiling_dist, C_RED) Window.drawFont(8, 8, "Move: ← → / Jump: Z / BG atari: B", font) end
- ジャンプ処理と、天井にぶつかったら座標補正する処理を追加しました。
- 床アタリを取るときに、y速度が上向きの場合を追加しました。
- 壁補正は、結局、壁チェックする距離を短くして、何かと当たったら全部壁、という扱いに戻しちゃいました。
- Zキーがジャンプボタンです。
- ジャンプボタンをずっと押しっぱなしにすれば、いつまでも上に行きます。
- 空中でもジャンプ可能です。
途中で、空中床(?)にも飛び乗れてますが…。どうやっているのかと言うと…。
- 上向きに飛んで天井アタリを調べる時、または壁アタリを調べる時は、そこが空中床のBGアタリ番号だったら、アタリはないものとして扱う。
- 下に落ちてる時は、空中床も床として扱うので、そこに乗れる。
ちなみに、マップの一番右のほうに、怪しいことが起きそうな地形を、いくつか置いておきました。個人的には、小さい段差で「ガクッ」と補正されるあたりが、気になりますなあ…。
とりあえず、ここまでのソースも画像も、zipファイルにまとめて、Dropboxに置いときますね。exeファイル以外は Public Domain ってことで。(exeファイルだけは、MIT License の tmxライブラリを含んでるので、ライセンスがよく分からず…。再配布するぐらいなら問題ないと思ってるんですが、どうなんだろう?)
_dxruby_map_disp_20131225.zip
- playermove3.rb が、上記のスクリプトです。
- exeファイルも同梱しておきました。playermove3.exe を実行すれば、Ruby + DXRuby の入ってない Windows環境でも動かせる、はずです。
- カーソルキーの左右で移動。Zキーでジャンプです。
- Bキーを押すと、BGアタリ表示と通常BG表示を切り替えられます。
他にも実装したい部分はありますが…。
- 床の上に立っている時だけジャンプさせたい。
- 空中床から真下に飛び降りたい。
- 崖から落ちるときにガクッと動くのが気になる。
- 崖(?)のギリギリ端っこにも立ちたい。
- 天井にぶら下がりたい。
- 壁をよじ登りたい。
- ぶら下がり棒に、ぶら下がりたい。
- 壁を蹴って三角飛びしたい。
- 斜め床の上では移動速度を変えたい。平らな床と同じ速度で動くのは気になる。
- 小さい段差の上に乗るとガクッと動くのが気になる。
- 動く足場を作りたい。
今回は、というか今年の DXRuby関係の記事は、これで最後にしたいと思います。どうにか、「一人DXRuby Advent Calendar 201」 も、そこそこやり遂げられたような気もしますし…! *1
◎ 課題のヒント。 :
- 床の上に立っている時だけジャンプさせたい。
- 床の上に立っている時だけ、ジャンプボタンが押されたかチェック。
- 空中床から真下に飛び降りたい。
- 飛び降り始めてから一定距離は、床アタリを無視。ただし、空中床の上に居ると分かってる時だけ、飛び降り操作を受け付ける。
- 崖(?)のギリギリ端っこにも立ちたい。
- 床補正時に見る位置を、足元の一点だけではなく、両脇にも増やす。
- 崖から落ちるときにガクッと動くのが気になる。
- 崖のギリギリ端っこに立てるようになれば、気にならないかも。
- 天井にぶら下がりたい。
- 床アタリに対してやってることを、上下逆にして、頭のあたりの座標を使って行う。
- 壁をよじ登りたい。
- 床アタリに対してやってることを(以下略
- ぶら下がり棒に、ぶら下がりたい。
- 床アタリに対してやってることを、頭のあたりの座標を使って行う。ただし、ぶら下がり棒のBGアタリ番号以外は無視。
- 壁を蹴って三角飛びしたい。
- ジャンプ中、かつ、壁補正された時に、ジャンプボタンを受け付ける。
- 斜め床の上では移動速度を変えたい。平らな床と同じ速度で動くのは気になる。
- BGアタリ種類と、速度もしくは角度の対応表を作っておく。足元のBGアタリ番号を見て速度を決定。
- 小さい段差の上に乗るとガクッと動くのが気になる。
- これ、どうやればいいんでしょうね? たぶん、対処を入れると、斜め床絡みでバグが出そうな予感…。「こういう地形は作らない」というルール適用が一番安直だけど…。
- 動く足場を作りたい。
- 動く足場のアタリ範囲と当たったら、床補正時と同じノリでプレイヤー座標を補正。ただし、動く足場の移動量をプレイヤー座標にも加える。足場側が自分の移動量を保持していて、プレイヤー側がソレをゲットして座標変更するか、あるいは、プレイヤー側が、乗ってる足場に、「お前に乗ってるよ」と知らせてあげて、足場側でプレイヤー座標を変更、等の処理になるのかなと。
◎ 参考になりそうなページ。 :
_地形判定させてみる
の、真ん中あたりにある説明図が、今回のソースの問題点をズバリ示してる、ように思います。
また、前にも書きましたが、 _2D当たり判定超入門(pdf) は、大変参考になりそうです。件のpdfは図形で地形判定してますが、タイルで地形判定する場合と共通する問題点にも触れていますので…。
また、前にも書きましたが、 _2D当たり判定超入門(pdf) は、大変参考になりそうです。件のpdfは図形で地形判定してますが、タイルで地形判定する場合と共通する問題点にも触れていますので…。
◎ 2017/03/19追記。 :
Dropboxのpublicフォルダが死んだのでファイルの置き場所を変更。
*1: や。「一人DXRuby Advent Calendar 2013」なんてする気はなかったですけど…。そもそも、ほとんどの記事は、DXRubyと関係ないですよね…。HSP、PyGame、pyglet、Processing、等々何を使ってもいいような話ばかりでしたし。
[ ツッコむ ]
以上です。