2013/12/31(火) [n年前の日記]
#1 [dxruby] DXRubyのSpriteを勉強中
Spriteクラスの衝突判定について簡単なサンプルを書きながら勉強中。とりあえず、Sprite.check(攻撃側Spriteの配列、守備側Spriteの配列) を呼べば、Spriteを継承したクラスの、shot()、hit() が呼ばれるらしいと分かったり。その中に、当たった時の処理を書けばどうにかなるらしい。
スプライトの基準座標が左上座標に固定されてるあたりがしっくりこなかったのだけど。DXRuby開発版なら、self.offset_sync = true を設定してやることで、画像の拡大縮小回転の中心位置を基準座標として扱えることを今頃知ったり。コレ、正式公開版に反映されたら嬉しいのだけど…。とりあえず、DXRuby 1.4.0 に該当機能は無いので、手元のサンプルでは基準座標+オフセット値を表示座標としてわざわざ設定したり。…そういや、開発版のソレって、アタリ範囲はどうなるんだろう。
さらにDXRuby開発版には、Sprite#flush(色配列) で、フラッシュ画像を生成できるメソッドも追加されていて。先日、自前でフラッシュさせようとしてたソレを、メソッド一発でできるようになるのはありがたいなと。コレも、正式公開版に反映されたら以下略。
とりあえず以下のような感じに。
_sprite_test2.rb
実行結果。
オブジェクトについて、画面外に消えるたびに破棄したり、一定時間毎に生成してるあたりが、ちょっと気になる…。オブジェクトの生成と破棄って時間がかかるらしいから、最初に使う分を確保して、それを使い回したほうがいいのかなと…。
このあたり、双方向リストで管理すれば、実行するオブジェクトと、実行せずに溜めておく空きオブジェクトを、即座に登録・解除できるのだけど…。実は DXRuby の内部でソレに近いことをやってたりしないのかな、という疑問も。タスクマネージャでプロセスを見ていても、メモリ使用量が増えているようには見えないし…。
スプライトの基準座標が左上座標に固定されてるあたりがしっくりこなかったのだけど。DXRuby開発版なら、self.offset_sync = true を設定してやることで、画像の拡大縮小回転の中心位置を基準座標として扱えることを今頃知ったり。コレ、正式公開版に反映されたら嬉しいのだけど…。とりあえず、DXRuby 1.4.0 に該当機能は無いので、手元のサンプルでは基準座標+オフセット値を表示座標としてわざわざ設定したり。…そういや、開発版のソレって、アタリ範囲はどうなるんだろう。
さらにDXRuby開発版には、Sprite#flush(色配列) で、フラッシュ画像を生成できるメソッドも追加されていて。先日、自前でフラッシュさせようとしてたソレを、メソッド一発でできるようになるのはありがたいなと。コレも、正式公開版に反映されたら以下略。
とりあえず以下のような感じに。
_sprite_test2.rb
# スプライトの衝突判定動作テスト
require 'dxruby'
font = Font.new(12)
# 画像読み込み
base64_text = ""
DATA.each {|l| base64_text += l.chomp}
bin_data = base64_text.unpack('m')[0]
$imgs = Image.loadFromFileInMemory(bin_data).sliceTiles(8, 1)
# enemyshotimgs = [$imgs[3], $imgs[4], $imgs[5]]
# 度→ラジアン変換
def deg2rad(deg)
return deg * Math::PI / 180.0
end
# ----------------------------------------
# プレイヤーキャラ
class Player < Sprite
attr_accessor :bx, :by, :shottimer, :hit_timer, :flush_image
# 初期化処理
def initialize(x, y)
super
self.bx = x
self.by = y
self.image = $imgs[1]
self.flush_image = $imgs[7]
self.shottimer = 0
self.collision = [16, 16, 4] # アタリ範囲を設定
self.hit_timer = 0
# self.offset_sync = true # DXRuby開発版でのみ使えるプロパティ
end
def update
w, h = self.image.width, self.image.height
# マウスカーソル座標を自機座標にする
self.bx = Input.mousePosX
self.by = Input.mousePosY
xmin, ymin = 0, 0
xmax, ymax = Window.width, Window.height
self.bx = xmin if self.bx < xmin
self.by = ymin if self.by < ymin
self.bx = xmax if self.bx > xmax
self.by = ymax if self.by > ymax
if self.shottimer % 10 == 0
# 自機ショットを発射
[270, 30, 150].each do |i|
spr = Shot.new(self.bx, self.by, 16, i + self.bx / 4)
$shots.push(spr)
end
end
self.shottimer += 1
self.angle += 8
if self.hit_timer > 0
self.hit_timer -= 1
self.hit_timer = 0 if self.hit_timer <= 0
else
self.hit_timer = 0
end
# 基準座標+オフセット値を表示座標とする。
# DXRuby開発版なら、self.offset_sync = true で済んでしまうのだけど、
# 開発版は Ruby 1.8 や 1.9 に対応してないので…
self.x = self.bx - w / 2
self.y = self.by - h / 2
end
# 雑魚敵と当たった時に呼ばれる処理
def hit(o)
self.hit_timer = 4
end
def draw
super
if self.hit_timer > 0
Window.drawScale(self.x, self.y, self.flush_image, 3, 3)
end
end
end
# ----------------------------------------
# プレイヤーの弾
class Shot < Sprite
attr_accessor :bx, :by, :dx, :dy
def initialize(x, y, spd, angle)
self.bx = x
self.by = y
self.image = $imgs[0]
self.dx = spd * Math.cos(deg2rad(angle))
self.dy = spd * Math.sin(deg2rad(angle))
self.angle = angle
self.collision = [0, 13, 31, 18]
self.collision_enable = true
self.collision_sync = true
end
def update
w, h = self.image.width, self.image.height
self.bx += self.dx
self.by += self.dy
# 画面外に出たら自分を消滅させる
xmin = - w / 2
ymin = - h / 2
xmax = Window.width + w / 2
ymax = Window.height + h / 2
if self.x < xmin or self.x > xmax or self.y < ymin or self.y > ymax
self.vanish
end
self.x = self.bx - w / 2
self.y = self.by - h / 2
end
# 敵に当たった場合に呼ばれるメソッド
def shot(d)
self.vanish # 自分を消滅させる
end
end
# ----------------------------------------
# 雑魚敵
class Enemy < Sprite
attr_accessor :bx, :by, :dir, :dx, :dy
attr_accessor :hit_timer, :spd, :org_image, :flush_image
def initialize(spd)
self.org_image = $imgs[2]
self.image = self.org_image
self.flush_image = $imgs[3]
# DXRuby開発版でのみ利用可能。フラッシュ画像を作れる
# self.flush_image = self.org_image.flush(C_WHITE)
self.spd = spd
self.collision = [0, 0, 31, 31]
self.init
end
# 発生時の初期化処理
def init
self.bx = rand(Window.width)
self.by = rand(Window.height)
self.collision_enable = false
self.collision_sync = false
self.hit_timer = 0
self.alpha = 0
end
# 更新処理
def update
w, h = self.image.width, self.image.height
if self.alpha < 255
# 出現中
self.collision_enable = false
self.alpha += 5
if self.alpha >= 255
self.alpha = 255
# プレイヤーを狙った速度を決める
ply = $players[0]
self.dir = Math.atan2(ply.by - self.by, ply.bx - self.bx)
self.dx = spd * Math.cos(self.dir)
self.dy = spd * Math.sin(self.dir)
end
else
# 移動中
if self.hit_timer > 0
# 弾が当たっているなら一定時間フラッシュさせる
self.hit_timer -= 1
self.collision_enable = false
# フラッシュ時間が終わったら再発生
self.init if self.hit_timer <= 0
else
# 弾は当たってない
self.hit_timer = 0
self.collision_enable = true
# 移動
self.bx += self.dx
self.by += self.dy
# 画面外に出たら再発生
xmin = - w / 2
ymin = - h / 2
xmax = Window.width + w / 2
ymax = Window.height + h / 2
if self.x < xmin or self.x > xmax or self.y < ymin or self.y > ymax
self.init
end
end
end
self.image = (self.hit_timer <= 0)? self.org_image : self.flush_image
self.x = self.bx - w / 2
self.y = self.by - h / 2
end
# プレイヤーの弾と当たった時に呼ばれるメソッド
def hit(o)
self.hit_timer = 4
end
# プレイヤーと当たった時に呼ばれるメソッド
def shot(d)
end
end
# ----------------------------------------
# メイン
# Input.mouseEnable = false # マウスカーソル非表示
srand(0)
$players = []
$shots = []
$enemys = []
$players.push(Player.new(0, 0))
8.times {|i| $enemys.push(Enemy.new(2))}
in_pause = false
Window.loop do
break if Input.keyPush?(K_ESCAPE)
update_enable = false
if in_pause
# ポーズ中
# Nキー押しで1フレーム進める
update_enable = true if Input.keyPush?(K_N)
# Pキーを押したらポーズ解除
in_pause = false if Input.keyPush?(K_P)
else
# 通常処理
in_pause = true if Input.keyPush?(K_P) # Pキーを押したらポーズ
update_enable = true unless in_pause
end
if update_enable
# プレイヤーの弾と雑魚敵の衝突判定
Sprite.check($shots, $enemys)
# 雑魚敵とプレイヤーの衝突判定
Sprite.check($enemys, $players)
Sprite.update($players)
Sprite.update($shots)
Sprite.update($enemys)
Sprite.clean($shots)
Sprite.clean($enemys)
end
Sprite.draw($enemys)
Sprite.draw($players)
Sprite.draw($shots)
l = $players.length + $shots.length + $enemys.length
Window.drawFont(0, 0, "Sprs: " + ('■' * l), font)
Window.drawFont(0, 16, "PAUSE", font) if in_pause == 0
end
__END__
iVBORw0KGgoAAAANSUhEUgAAAQAAAAAgCAMAAADKd1bWAAAAwFBMVEV/AACg
AADAAADgAAD/HBz/cHD/qKj/xMT/4OAAwAAMdwBN/03/////Ziv/hk3/p3D/
x5OROADaLAAwMDBgYGCUlJSwsLDg4ODExMT///+goKSyAKwAAAAAAAAAAAAA
AAD/////ior/KyubAAD/////u4n/mSuacwDLy8vvdi7EUgCJBgD/Kyv/biv/
dCv/uSsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAACCWjOjAAAAHHRSTlP/////////////////////////////////
//8AF7Li1wAAA0tJREFUeJzlmd2SokAMhbVquNhdB91tcKW4USj1wkLe/+02
P40ESDN2iyNbnuJiTKYczjdJaLoXuYfSdAdK005wJ6UEMinMDwLfpsJKxhY+
X2ASIJAmRsa20q4xg0CW9QwPAt8ksv4J6jLwAoAIuvbB7zZtRQC6gZkAYPcV
iRnYhBcArQXArzE6AIjPBQDZv8anGHSKr4SAM4+3AADYOQDs5gIA/V/jeL0+
gtbrGBA0BN6iBfDfD/aPG/64OQICLAL88HAL5InpKukEBoZf478C+zIECCom
8HAL5H/FyG/UhmYAAOu/558IcBdMMQOaajdmScKfXC0wTgCnc1m6bwBn+OXi
zteg87kX1Pw3BCYEQPY/UIwgAECzTnEhqKxc+dqqm6f5N/APBGgSegGA/say
Towk0AJYfkQoQhACoCgOh8MIgaqC/AiBuob8kAAVgPb7XAIeAND/T1CXgAVA
/rOsT8ADAPrfjxBA//sRAuh/rxBwFIAtga8BpIYvQ/5/gIgAGMzpagFE6IcJ
BAGA+99bAioAm3cCsPkeACqAjeZsQyWgA9iw8PbShC8Q+P8FQgKgNKdrawc/
FUCnBFj3AoAC2KNcJQAFwHlHCUABcL5XAkVRndQOgB44VQoAXC+B2D/c344W
dLjWI/+rFRHAj4auvAVgW6AD4O7HYCErQAfQVoAOoK0ACQDWAGoHYA/AWmDx
m/QHhG9KnzGJCPAdwtCjCwQAViAEQMOQLv6u2wgUAOTfGvVuAYgZoAIQM0AF
IGbAqwFEYQBuTwHwrwG4PQUqJV/X7VOgLj0A9KPeLWAXgbAGuPnPIgSgbYi4
KZSFkGLwUgkp+XMt9AgAks8QbAA0BKABomUD4P4h+DQAvkOwr/sfgx+s0HVA
Oeof8qP+Ia/6D3wMqvpqIcQEoP55MewNoBT+NYOl8K/mhf8JF0I9AmNLYUYQ
LZdhS+GSEZS6P8o39l35xv5zlsJ3vAw1CnsZKm/S/3xYfsKXIX0/QO5/tK/D
YRsiY/aC809+HX6rDRHHrrDcAhSbIQEbIs/RdFtib78p6toWn/25wFTb4q6D
kdmfC0x1MPK/tkA+1dGY2gLdU4FBYCYApjkcVQ9Gev4HgYHd1/hHacfj/wAC
/D82nEMmSwAAAABJRU5ErkJggg==
実行結果。
オブジェクトについて、画面外に消えるたびに破棄したり、一定時間毎に生成してるあたりが、ちょっと気になる…。オブジェクトの生成と破棄って時間がかかるらしいから、最初に使う分を確保して、それを使い回したほうがいいのかなと…。
このあたり、双方向リストで管理すれば、実行するオブジェクトと、実行せずに溜めておく空きオブジェクトを、即座に登録・解除できるのだけど…。実は DXRuby の内部でソレに近いことをやってたりしないのかな、という疑問も。タスクマネージャでプロセスを見ていても、メモリ使用量が増えているようには見えないし…。
この記事へのツッコミ
- Re: DXRubyのSpriteを勉強中 by takaranotou 2017/07/10 17:17
- getyerdrgkhuykhim;
[ ツッコミを読む(1) | ツッコむ ]
以上です。
