Skip to content

Instantly share code, notes, and snippets.

@mirichi
Last active December 26, 2015 03:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mirichi/2b25b0a58e93bf780df6 to your computer and use it in GitHub Desktop.
Save mirichi/2b25b0a58e93bf780df6 to your computer and use it in GitHub Desktop.
require 'dxruby'
require_relative 'calc'
# Complexによる相対表現を行うSprite
# 使い方そのものは通常のSpriteとあまり変わらない
# ComplexSpriteGroupをtargetに設定するとそれが親となり親の影響を受けるようになる
# 各インスタンス変数を持ってしまうので注意
# 名前にComplexと付いているが内部実装の話であり使う側には複素数は関係ない
class ComplexSprite < Sprite
# 元のアクセサの保存
alias_method :native_x, :x
alias_method :native_x=, :x=
alias_method :native_y, :y
alias_method :native_y=, :y=
alias_method :native_z, :z
alias_method :native_z=, :z=
alias_method :native_angle, :angle
alias_method :native_angle=, :angle=
alias_method :native_scale_x, :scale_x
alias_method :native_scale_x=, :scale_x=
alias_method :native_scale_y, :scale_y
alias_method :native_scale_y=, :scale_y=
alias_method :native_alpha, :alpha
alias_method :native_alpha=, :alpha=
alias_method :native_target, :target
alias_method :native_target=, :target=
# 元のアクセサの上書き
def x;@_x;end
def x=(v);@_x = v;end
def y;@_y;end
def y=(v);@_y = v;end
def z;@_z;end
def z=(v);@_z = v;end
def angle;@_angle;end
def angle=(v);@_angle = v;end
def scale_x;@_scale_x;end
def scale_x=(v);@_scale_x = v;end
def scale_y;@_scale_y;end
def scale_y=(v);@_scale_y = v;end
def alpha;@_alpha;end
def alpha=(v);@_alpha = v;end
@@base_calc = ->x{x}
def initialize(x=nil, y=nil, image=nil)
@_x = x
@_y = y
@_z = 0
@_angle = 0
@_scale_x = 1
@_scale_y = 1
@_alpha = 255
@_target = Window
self.image = image
end
def update
# 親の影響を取得する
calc_xy = nil
calc_angle = nil
calc_scale = nil
calc_alpha = nil
if @_target.kind_of?(ComplexSpriteGroup)
calc_xy = @_target.get_calc_xy
calc_angle = @_target.get_calc_angle
calc_scale = @_target.get_calc_scale
calc_alpha = @_target.get_calc_alpha
else
calc_xy = @@base_calc
calc_angle = @@base_calc
calc_scale = @@base_calc
calc_alpha = @@base_calc
end
# 親の影響を計算して自身にセットする
tmp = calc_xy[Complex(@_x, @_y)]
self.native_x, self.native_y = tmp.real, tmp.imag
self.native_z = @_z # zの扱いは検討中
self.native_angle = calc_angle[@_angle]
self.native_scale_x = calc_scale[@_scale_x]
self.native_scale_y = calc_scale[@_scale_y]
self.native_alpha = calc_alpha[@_alpha]
self.native_target = self.get_native_target
end
# native_targetに設定すべきオブジェクトを取得する
# 親がいる場合は親のtargetとなる
# 親のimageがRenderTargetの場合、そこに描画する
def get_native_target
if @_target.kind_of?(ComplexSpriteGroup)
if @_target.image.kind_of?(RenderTarget)
@_target.image
else
@_target.get_native_target
end
else
@_target
end
end
def target
@_target
end
# targetを設定した場合、それがComplexSpriteGroupだったら子として登録する
# 元targetがComplexSpriteGroupだったら子からはずす
def target=(v)
return if @_target == v
@_target.children.delete(self) if @_target.kind_of?(ComplexSpriteGroup)
@_target = v
@_target.children << self if @_target.kind_of?(ComplexSpriteGroup)
end
def clear_calc
end
def to_sprite_ary
self
end
end
# 子ComplexSpriteを保持する機能を追加したComplexSprite
# scale_x/yは無く、かわりに縦横同時指定のscaleがある。
class ComplexSpriteGroup < ComplexSprite
undef_method :scale_x, :scale_x=, :scale_y, :scale_y=
def initialize(*)
super
@_children = []
@_scale = 1
@_calc_xy = nil
@_calc_angle = nil
@_calc_scale = nil
@_calc_alpha = nil
end
def children;@_children;end
def scale;@_scale;end
def scale=(v);@_scale=v;end
# 子ComplexSpriteを追加する。
# 自動的に子のtargetにselfが設定される。
# 子ComplexSprite側でtarget=として親を設定しても親の@childrenに追加される。
def add_child(v)
v.target = self
end
# 子のはずす
def remove_child(v)
return if v.target != self
v.target = Window
end
# targetを設定した場合、保持している計算式はクリアする
def target=(v)
super
self.clear_calc
end
# 計算式のクリア
def clear_calc
@_calc_xy = nil
@_calc_angle = nil
@_calc_scale = nil
@_calc_alpha = nil
@_children.each{|c|c.clear_calc}
end
# update時は子もupdate
def update
super
@_children.each{|c|c.update}
end
# draw時は子もdraw
def draw
# RenderTargetを保持している場合は子が先
if self.image.kind_of?(RenderTarget)
@_children.each{|c|c.draw}
super
# Imageを保持している場合は親が先
else
super
@_children.each{|c|c.draw}
end
end
# xyを補正するCalcを返す
def get_calc_xy
return @_calc_xy if @_calc_xy
return @@base_calc if self.image.kind_of?(RenderTarget)
@_calc_xy = Calc.new(->xy{
xy -= Complex(self.center_x, self.center_y) unless self.offset_sync
tmp = xy.polar
xy = Complex.polar(tmp[0], tmp[1] + Math::PI / 180 * @_angle)
xy += Complex(self.center_x, self.center_y) unless self.offset_sync
xy *= @_scale
xy += Complex(@_x, @_y)
})
# 親がいる場合は更に親の計算機を追加する
if @_target.kind_of?(ComplexSpriteGroup)
@_calc_xy = @_calc_xy + @_target.get_calc_xy
end
@_calc_xy
end
# angleを補正するCalcを返す
def get_calc_angle
return @_calc_angle if @_calc_angle
return @@base_calc if self.image.kind_of?(RenderTarget)
@_calc_angle = Calc.new(->angle{angle + @_angle})
if @_target.kind_of?(ComplexSpriteGroup)
@_calc_angle = @_calc_angle + @_target.get_calc_angle
end
@_calc_angle
end
# scaleを補正するCalcを返す
def get_calc_scale
return @_calc_scale if @_calc_scale
return @@base_calc if self.image.kind_of?(RenderTarget)
@_calc_scale = Calc.new(->scale{scale * @_scale})
# 親がいる場合は更に親の計算機を追加する
if @_target.kind_of?(ComplexSpriteGroup)
@_calc_scale = @_calc_scale + @_target.get_calc_scale
end
@_calc_scale
end
# alphaを補正するCalcを返す
def get_calc_alpha
return @_calc_alpha if @_calc_alpha
return @@base_calc if self.image.kind_of?(RenderTarget)
@_calc_alpha = Calc.new(->alpha{alpha / 255.0 * @_alpha / 255.0 * 255.0})
# 親がいる場合は更に親の計算機を追加する
if @_target.kind_of?(ComplexSpriteGroup)
@_calc_alpha = @_calc_alpha + @_target.get_calc_alpha
end
@_calc_alpha
end
def to_sprite_ary
[self] + @_children.map{|v|v.to_sprite_ary}
end
end
if __FILE__ == $0
# 白い四角のSprite
a = ComplexSpriteGroup.new(200, 200, Image.new(100, 20, C_WHITE))
a.offset_sync = true
a.center_x = 10
a.center_y = 10
# 赤い四角のSprite
# x,yが親の座標からの相対位置となる
b = ComplexSpriteGroup.new(82, 0, Image.new(80, 16, C_RED))
b.offset_sync = true
b.center_x = 8
b.center_y = 8
a.add_child(b) # 白の子とする
#b.target = a # でもよい。どっちでも同じ
# 緑の四角のSprite
c = ComplexSpriteGroup.new(66, 0, Image.new(60, 12, C_GREEN))
c.offset_sync = true
c.center_x = 6
c.center_y = 6
b.add_child(c) # 赤の子とする
# 画像の無いSprite
# 黄色の四角4個をまとめて回転させるためのジョイントとして存在する
d = ComplexSpriteGroup.new(50, 0)
d.center_x = d.center_y = 0
c.add_child(d) # 緑の子とする
# 黄色のSprite
# 4個生成する。
4.times do |i|
t = ComplexSprite.new(0, 0, Image.new(40, 8, C_YELLOW))
t.offset_sync = true
t.center_x = 4
t.center_y = 4
t.angle = i*90
d.add_child(t) # 画像の無いSpriteの子とする
end
# マウス用
s = Sprite.new
s.collision = [0, 0]
Window.loop do
a.angle += 0.5
b.angle += 1
c.angle += 2
d.angle += 3
a.update
a.draw
s.x, s.y = Input.mouse_x, Input.mouse_y
if s === a.to_sprite_ary
Window.draw_font(0, 0, "hit", Font.default)
end
break if Input.key_push?(K_ESCAPE)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment