-
-
Save mirichi/2b25b0a58e93bf780df6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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