Jewel-mmo開発日記

RubyでMMORPGを作る過程を記録する日記。 Yokohama.rb 発起人。
2005-01-10

[アイデア]Easy Rocket インターフェース案 (2)

よく考えたら Easy Rocket インターフェースはサーバーへの接続とその操作だ。

requre 'er'
er = ER.new 'localhost', port
screen = ER::Screen.New er, nil, 640, 400
prim = ER::PrimImage.new er
prim.position = 100, 100, 0
screen.add_obj prim 

prim.delete
screen.delete
er.close

それともこうだろうか。

requre 'er'
er = ER.new 'localhost', port
screen = er.createScreen nil, 640, 400
prim = er.createPrimImage
prim.position = 100, 100, 0
screen.add_obj prim 

prim.delete
screen.delete
er.close

後者のほうがいい気がする。違うかな。うーむ、これ考えてどうなる問題でないな。

一瞬、プリミティブはコネクションを使わずに生成してもいいかと思ったが、それはどっちの意味でもなさそうだ。

ループ

ループ部分を含めるとこんな感じだろうか。それと、今後は A.b の書き方を使うことにする。

requre 'er'
er = ER.new 'localhost', port
screen = ER.Screen.New er, nil, 640, 400
prim = ER.PrimImage.new er
prim.position = 100, 100, 0
screen.add_obj prim 

vx = 1
vy = -10
ay = 1
while true
  prim.x += vx
  prim.y += vy
  vy += ay

  er.flush
  ER.sync 0
end

prim.delete
screen.delete
er.close

er.flush でサーバーに対して命令がまとめて送信される。

描画処理はサーバーで行われているので、別プロセスであるクライアントとの間でうまく同期を取らないと微妙におかしくなりそうだが、その辺の考察はとりあえず置いておく。内部的に解決できそうな気もする。

物理シミュレーション

Easy Rocket では簡単な物理シミュレーション機能でオブジェクトの座標を操作したいと思っている。今までは上記のように毎フレーム座標を設定し続けていたのだが、今になって考えてみると、こうした方がクライアントの実装がシンプルになる気がする。

例えば格闘ゲームの停止、歩く、停止というアクションの場合、方向キーが入力されている間だけ座標を加算するという実装が普通だ。この場合、キーが押されたタイミングと離されたタイミングの間では等速直線運動になっているので、キーが押されたタイミングで加速するという実装にすればもっとシンプルになるのではないかというアイデア。

上記のループ部分は次のようになる。

prim.speed 1, -10, 0
prim.acceleration 0, 1, 0
while true

  er.flush
  ER.sync 0
end

キャラの X 方向の移動は次のようになる。

while true
  if 右が押された?
    prim.speed.x = 1
  elsif 右が離された?
    prim.speed.x = 0
  end

  er.flush
  ER.sync 0
end

衝突判定

3D のモデリングの衝突はおいて置いて、ここでは格闘ゲームで「方向キー上」が押されたときにジャンプする処理を考えたい。 例えばこんな感じか。

prim.acceleration 0, 1, 0 # 重力加速度の設定
jump = false
while true
  # 地面とキャラの衝突判定
  if jump && prim.y <= 0
    prim.speed.y = 0
    if 右が押されている?
      prim.speed.x = 1
    elsif 右が離されている?
      prim.speed.x = 0
    end
    jump = false
  end
  # アクション開始判定
  if prim.y == 0
    if 右が押された?
      prim.speed.x = 1
    elsif 右が離された?
      prim.speed.x = 0
    end
    if 右が押された?
      prim.speed.y = -10
      jump = true
    end
  end

  er.flush
  ER.sync 0
end

着地時の加速度設定が余分な気もするが、実際のゲームだと着地時にアニメーションの変更などのイベントが入るだろうからこれはいいか。で、この着地判定を自動処理にしたかったのだけど、イベントが入るからこの例がよくないな。ボールで考えてみよう。

むずかしい。とりあえず思いつくままに書いてみる。あれ、 vx メソッドと speed は同じものか。 velocity で統一しよう。

e = 0.8 # 跳ね返り係数
ball.acceleration 0, 1, 0 # 重力加速度の設定
ground = ClashObj.new "y=0"
ball.add_clash_obj ground, e
while true
  if key_on?
    ball.velocity.y += -10
  end
  er.flush
  ER.sync 0
end

イメージとしてはこんな感じか。"y=0" とかかなり適当だけどこんなことできるだろうか。

座標クラス

オブジェクト指向的にというか Ruby 的にというか次のような書き方できるだろうか。

ball.position = x, y, z
ball.position.x = x
ball.position.x += dx
ball.position += dpos
pos = ball.position
x, y, z = ball.position

試してみよう。

position の型は何なのかという話か。 Vector クラスというのがあったが遅い模様。ここで使うのはそもそも間違っているのかも知れない。

Vector3D というクラスを自作したほうが速度以外の意味でも正解かも。

class Vector3D < Array
   def x ; self[0] ; end
   def x=v ; self[0] = v ; end
   def +dpos
     self[0] += dpos[0]
     self[1] += dpos[1]
     self[2] += dpos[2]
     self
   end
end

次のようなコードが動いた。

ball = Ball.new
x = y = z = 100
dx = 10
dpos = Vector3D[1, 2, 3]

ball.position = Vector3D[x, y, z]
ball.position.x = x
ball.position.x += dx
ball.position += dpos
pos = ball.position
x, y, z = ball.position

p pos
p x,y,z