部品をバウンドさせる

部品を壁でバウンドさせる。
このページを参考。
http://ldt.kobe-shinwa.ac.jp/masa/classes/2005fmm/chapter3.html
反転(鏡映)の行列をつかった。
動きの変化をベクトルにしてmatrixのクラスを使って反転。
部品のクラスは、中心点とその中心点が動ける範囲(Rangeクラス)を持たして
壁での反転をした。
他も使い勝手のテストしている。
どう落ち着くのか、まだ不明。

<追記>
書き直しました。
http://blog.livedoor.jp/gaziya/archives/52150882.html
ここ

#!usr/bin/env ruby

require 'sdl'
require 'cairo'
require 'matrix'

class BackGround
def initialize(w, h)
@w, @h = w, h
end

def update(c)
c.set_source_color(Cairo::Color::BLACK)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Item
def initialize(w, h)
@exist_range_x = Range.new(0, w)
@exist_range_y = Range.new(0, h)
@pos = Vector[w / 2, h / 2]
@reverse_x_axis = Matrix[[1, 0], [0, -1]]
@reverse_y_axis = Matrix[[-1, 0], [0, 1]]
@mv = Vector[rand(5) + 2, rand(5) + 2]
@mv = @reverse_x_axis * @mv if rand(9) < 5
@mv = @reverse_y_axis * @mv if rand(9) < 5
@init_mtrx = Cairo::Matrix.identity
@convert_mtrx = Cairo::Matrix.identity
@pos_mtrx = Cairo::Matrix.identity
end

def move
x, y = (@pos + @mv).to_a
@mv = @reverse_y_axis * @mv if !@exist_range_x.include?(x)
@mv = @reverse_x_axis * @mv if !@exist_range_y.include?(y)
@pos += @mv
x, y = @pos.to_a
@pos_mtrx = Cairo::Matrix.translate(x, y)
end

def matrix
@init_mtrx * @convert_mtrx * @pos_mtrx
end
end

class Panel < Item
def initialize(w, h)
super
@image = Cairo::ImageSurface.new(20, 20)
context = Cairo::Context.new(@image)
context.set_source_color(Cairo::Color::ORANGE)
context.rectangle(0, 0, @image.width, @image.height)
context.fill
cx, cy = @image.width / 2, @image.height / 2
@init_mtrx = Cairo::Matrix.translate(-cx, -cy)
@convert_mtrx = Cairo::Matrix.identity
@exist_range_x = cx .. w - cx
@exist_range_y = cy .. h - cy
end

def update(c)
self.move
c.matrix = self.matrix
c.set_source(@image, 0, 0)
c.paint
end
end

class Ball < Item
def initialize(w, h)
super
@r = 10
@color = Cairo::Color::ORANGE
@exist_range_x = @r .. w - @r
@exist_range_y = @r .. h - @r
end

def update(c)
self.move
c.matrix = self.matrix
c.set_source_color(@color)
c.circle(0, 0, @r)
c.fill
end
end

class Phase
def initialize(screen)
@screen = screen
@w, @h = @screen.w, @screen.h
@image = Cairo::ImageSurface.new(@w, @h)
@bg = BackGround.new(@w, @h)
@panel = Panel.new(@w, @h)
@ball = Ball.new(@w, @h)
end

def update
context = Cairo::Context.new(@image)
@bg.update(context)
@panel.update(context)
@ball.update(context)
surface = SDL::Surface.new_from(@image.data, @image.width, @image.height, 32, @image.stride, 0, 0, 0, 0)
@screen.put(surface, 0, 0)
end

def run
loop do
while e=SDL::Event.poll
exit if e.kind_of?(SDL::Event::Quit) || (e.kind_of?(SDL::Event::KeyDown) && e.sym == SDL::Key::ESCAPE)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(350, 250, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-16 20:01