mieki256's diary



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

#3 [dxruby][game] DXRubyで地形アタリを取りながらプレイヤーキャラの移動その3ひとまず完結編

今日も、DXRubyを使って、プレイヤーキャラを動かしてみますよ。

_昨日の時点 では、壁にめり込まなくなったものの、穴に落ちるとそこから脱出できなくなったので、今日はジャンプ処理を追加してみようかと。

下のようなソースになりました。

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
これで、穴に落ちても脱出できるかなと。

動作画面
ホントは、床の上に居る時だけジャンプ可能にすべきかもしれませんが。なんだかこのほうが面白かったので、そのままにしておきました。…きっと、彼の背中には翼がついてて、ジャンプボタンを押してる間は翼がバタバタ動いてるんです。心の目で見ればそう見える。ということにしておこう。

途中で、空中床(?)にも飛び乗れてますが…。どうやっているのかと言うと…。 たったこれだけです。BGアタリの種類を色々用意していけば、こんな風に、できることが増えていくのかなと。…でも、アタリ種類がどんどん増えていくので、これもこれでどうなんだろうという気もしますけど。もっとスマートなやり方はないのかな。まあ、そこは今後の課題ってことで。

ちなみに、マップの一番右のほうに、怪しいことが起きそうな地形を、いくつか置いておきました。個人的には、小さい段差で「ガクッ」と補正されるあたりが、気になりますなあ…。

とりあえず、ここまでのソースも画像も、zipファイルにまとめて、Dropboxに置いときますね。exeファイル以外は Public Domain ってことで。(exeファイルだけは、MIT License の tmxライブラリを含んでるので、ライセンスがよく分からず…。再配布するぐらいなら問題ないと思ってるんですが、どうなんだろう?)

_dxruby_map_disp_20131225.zip
他にも実装したい部分はありますが…。 まあ、ここまでやってきたことを参考にすれば、作り込みはできると思いますので…。

今回は、というか今年の DXRuby関係の記事は、これで最後にしたいと思います。どうにか、「一人DXRuby Advent Calendar 201」 も、そこそこやり遂げられたような気もしますし…! *1

課題のヒント。 :

床の上に立っている時だけジャンプさせたい。
床の上に立っている時だけ、ジャンプボタンが押されたかチェック。
空中床から真下に飛び降りたい。
飛び降り始めてから一定距離は、床アタリを無視。ただし、空中床の上に居ると分かってる時だけ、飛び降り操作を受け付ける。
崖(?)のギリギリ端っこにも立ちたい。
床補正時に見る位置を、足元の一点だけではなく、両脇にも増やす。
崖から落ちるときにガクッと動くのが気になる。
崖のギリギリ端っこに立てるようになれば、気にならないかも。
天井にぶら下がりたい。
床アタリに対してやってることを、上下逆にして、頭のあたりの座標を使って行う。
壁をよじ登りたい。
床アタリに対してやってることを(以下略
ぶら下がり棒に、ぶら下がりたい。
床アタリに対してやってることを、頭のあたりの座標を使って行う。ただし、ぶら下がり棒のBGアタリ番号以外は無視。
壁を蹴って三角飛びしたい。
ジャンプ中、かつ、壁補正された時に、ジャンプボタンを受け付ける。
斜め床の上では移動速度を変えたい。平らな床と同じ速度で動くのは気になる。
BGアタリ種類と、速度もしくは角度の対応表を作っておく。足元のBGアタリ番号を見て速度を決定。
小さい段差の上に乗るとガクッと動くのが気になる。
これ、どうやればいいんでしょうね? たぶん、対処を入れると、斜め床絡みでバグが出そうな予感…。「こういう地形は作らない」というルール適用が一番安直だけど…。
動く足場を作りたい。
動く足場のアタリ範囲と当たったら、床補正時と同じノリでプレイヤー座標を補正。ただし、動く足場の移動量をプレイヤー座標にも加える。足場側が自分の移動量を保持していて、プレイヤー側がソレをゲットして座標変更するか、あるいは、プレイヤー側が、乗ってる足場に、「お前に乗ってるよ」と知らせてあげて、足場側でプレイヤー座標を変更、等の処理になるのかなと。

参考になりそうなページ。 :

_地形判定させてみる の、真ん中あたりにある説明図が、今回のソースの問題点をズバリ示してる、ように思います。

また、前にも書きましたが、 _2D当たり判定超入門(pdf) は、大変参考になりそうです。件のpdfは図形で地形判定してますが、タイルで地形判定する場合と共通する問題点にも触れていますので…。

2017/03/19追記。 :

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

*1: や。「一人DXRuby Advent Calendar 2013」なんてする気はなかったですけど…。そもそも、ほとんどの記事は、DXRubyと関係ないですよね…。HSP、PyGame、pyglet、Processing、等々何を使ってもいいような話ばかりでしたし。

以上です。

過去ログ表示

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