<   2011年 05月 ( 32 )   > この月の画像一覧

部品を壁でバウンドさせる。
このページを参考。
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
だんだん描き方がみえてきた。
rubyのリファレンスを読みながら、
使ったことのない便利なメソッドなんか試してる。
こうなると、おもしろくてしかたない。

#!usr/bin/env ruby

require 'cairo'
require 'matrix'

mtrx = Cairo::Matrix.rotate(-0.5 * Math::PI)
a= []
(0 .. 359).step(360 / 5) do |d|
r= d * Math::PI / 180
a << Vector.elements(mtrx.transform_point(Math::cos(r), Math::sin(r))) * 80
end
star = []
(a * 2).inject(true) do |b, v|
star << v if b
b = !b
end
image = Cairo::ImageSurface.new(200,200)
context = Cairo::Context.new(image)
context.matrix = Cairo::Matrix.translate(image.width / 2, image.height / 2)
context.set_source_color(Cairo::Color::ORANGE)
context.set_line_width(10)
star.inject(true) do |b, v|
x, y = v.to_a
if b
context.move_to(x, y)
else
context.line_to(x, y)
end
b = false
end
context.close_path
context.stroke
image.write_to_png("/tmp/image")
`display /tmp/image`
[PR]
by gaziya | 2011-05-16 19:00
rcairoのリファレンスを読んでいたら、
Cairo::Context#rel_move_toとかCairo::Context#rel_line_toが、あった。
相対座標を使えるみたい。
これを使って位置管理を、した方が位置管理が直感的かな。
しばらく、この方向で煮詰めてみます。
部品のクラスは、絶対座標(x, y)を持つ。
width, heightのかわりに
x_range, y_range = (-10..10), (-10..10) と使うか、
絶対座標からの半径をエリア(area = 10) みたいにして使ってみるか。
後、形が持つ点は、絶対座標からのベクトル(相対座標)にする。
こうしておくと、Cairo::Matrixの扱いが直感的に扱える。
四角を書くにしても、円を書くにしても、所詮、点と点を結ぶだけだもん。
三角関数は多用するけど、気にしない。
他の部品との関係(干渉)とかは、
Math::sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2)
と書くよりも
Cairo::Point#distanceがピンと来た。
Cairo::Point.new(x0, y0).distance(Cairo::Point.new(x1, y1))
これで部品同士の中心の距離を導く。
あと、Rangeクラスも使いたい。
今までは
50 < x && x < 100
とか使ってたけど
Rangeクラスを使うと
(51 .. 99).include?(x)
(51 ...100)include?(x)
Range.new(51, 99).include?(x)
とか、スッキリ書ける。
後、テキストの扱いも追い込まないとね。
Cairo::Glyphとか、今から理解します。
今回は、プログラムは無い。
関係ないが、Rangeクラスを調べてたら
stepメソッドがあった。
0.step(359, 10) { |d| puts d}

(0...360).step(10) {|d| puts d}
と書ける。
後者の方がいいな。
[PR]
by gaziya | 2011-05-12 22:35
ぐるぐる回転しているのを見て閃いた。
Cairo::Matrix.rotateする時に、
ImageSurefaseの(0,0)と重なるポイントが、回転軸になる。
判りづらい行列を書かないでCairo::Matrix.rotateを使える。
変換するのにプロセスが必要と言うことだな。
イメージを移動して軸をきめ回転して移動。
こんな感じだ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

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
c.set_source_color(Cairo::Color::GREEN)
c.move_to(0, @h / 2)
c.line_to(@w, @h / 2)
c.stroke
c.move_to(@w / 2, 0)
c.line_to(@w / 2, @h)
c.stroke
end
end

class Panel
attr_writer :matrix
attr_reader :w, :h

def initialize
@w, @h = 100, 100
@image = Cairo::ImageSurface.new(@w, @h)
context = Cairo::Context.new(@image)
context.set_source_color(Cairo::Color::ORANGE)
context.rectangle(0, 0, @w, @h)
context.fill
@matrix = Cairo::Matrix.identity
end

def update(c)
c.matrix = @matrix
c.set_source(@image, 0, 0)
c.paint
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
@deg = 0
end

def update
@deg += 15
@deg = 0 if @deg > 359
rd = @deg * Math::PI / 180
tr_mtrx1 = Cairo::Matrix.translate(-@panel.w / 2, -@panel.h / 2)
ro_mtrx = Cairo::Matrix.rotate(rd)
tr_mtrx2 = Cairo::Matrix.translate(@w / 2, @h / 2)
@panel.matrix = tr_mtrx1 * ro_mtrx * tr_mtrx2
context = Cairo::Context.new(@image)
@bg.update(context)
@panel.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(100)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(300, 300, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-11 00:00
Cairo::Matrixを使い、Cairo::Context#set_sourceで読み込んだイメージを
中心を軸に回転させる。
http://cairographics.org/matrix_transform/
このページを参考にした。
ちょっと、扱い方が、やっかいだ。
回転行列に移動行列を掛ける。
逆だと、ダメだ。
テストしたプログラムはこれだ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

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
c.set_source_color(Cairo::Color::GREEN)
c.move_to(0, @h / 2)
c.line_to(@w, @h / 2)
c.stroke
(1..3).each do |i|
c.move_to(@w / 4 * i, 0)
c.line_to(@w / 4 * i, @h)
c.stroke
end
end
end

class Panel
attr_writer :matrix
attr_reader :w, :h

def initialize(x, y)
@x, @y = x, y
@w, @h = 100, 100
@image = Cairo::ImageSurface.new(@w, @h)
context = Cairo::Context.new(@image)
context.set_source_color(Cairo::Color::ORANGE)
context.rectangle(0, 0, @w, @h)
context.fill
@matrix = Cairo::Matrix.identity
end

def update(c)
c.matrix = @matrix
c.set_source(@image, @x, @y)
c.paint
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)
@panel0 = Panel.new(0, 0)
@panel1 = Panel.new(@w / 4, @h / 2)
@panel2 = Panel.new(0, 0)
@panel3 = Panel.new(0, 0)
@deg = 0
end

def update
@deg += 15
@deg = 0 if @deg > 359
rd = @deg * Math::PI / 180
sin = Math.sin(rd)
cos = Math.cos(rd)
x, y = @panel1.w / 2, @panel1.h / 2
ro_mtrx = Cairo::Matrix.new(cos, sin, -sin, cos, x - cos * x + sin * y, y - sin * x - cos * y)
@panel0.matrix = ro_mtrx
@panel1.matrix = ro_mtrx
tr_mtrx = Cairo::Matrix.translate(@w / 4 * 2, @h / 2)
@panel2.matrix = tr_mtrx * ro_mtrx
tr_mtrx = Cairo::Matrix.translate(@w / 4 * 3, @h / 2)
@panel3.matrix = ro_mtrx * tr_mtrx
context = Cairo::Context.new(@image)
@bg.update(context)
@panel0.update(context)
@panel1.update(context)
@panel2.update(context)
@panel3.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(100)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(600, 300, SDL::Screen.info.bpp, SDL::SWSURFACE)
Phase.new(@screen).run
[PR]
by gaziya | 2011-05-10 22:38
Cairo::MatrixをrubyのMatrixとVectorに置き換えてみた。
rubyのMatrixほうが、行列っぽく書ける。
これで、Cairo::Matrixのニュアンスが判った。

#!usr/bin/env ruby

require 'cairo'
require 'matrix'

matrix = Cairo::Matrix.rotate(0.5) * Cairo::Matrix.scale(2, 3)
x, y = 35, 65

xx, yx, xy, yy, x0, y0 = matrix.to_a
c_matrix = Cairo::Matrix.new(xx, yx, xy, yy, x0, y0)
r_matrix = Matrix[
[xx, xy, x0],
[yx, yy, y0],
[ 0, 0, 1]]

cx, cy = c_matrix.transform_point(x, y)
rx, ry = (r_matrix * Vector[x, y, 1]).to_a
puts "+++---------------------------------------------+++"
puts "cx : #{cx} | cy : #{cy}"
puts "rx : #{rx} | ry : #{ry}"

a1, a2, a3, a4, a5, a6 = matrix.to_a
c_matrix = Cairo::Matrix.new(a1, a2, a3, a4, a5, a6)
r_matrix = Matrix[
[a1, a3, a5],
[a2, a4, a6],
[ 0, 0, 1]]

cx, cy = c_matrix.transform_point(x, y)
rx, ry = (r_matrix * Vector[x, y, 1]).to_a
puts "+++---------------------------------------------+++"
puts "cx : #{cx} | cy : #{cy}"
puts "rx : #{rx} | ry : #{ry}"
[PR]
by gaziya | 2011-05-10 18:00
二次元図形の座標変換について調べてみた。
http://ldt.kobe-shinwa.ac.jp/masa/classes/2005fmm/chapter3.html
ここだ。
最初ruby のMatrixクラスを使って座標変換をしようとしたが、
座標変換が理解できるようになったら
Cairo::Matrixで、変換したほうが、手っ取り早い事に気づいた。
それで、これ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(w, h)
@w,@h = w, h
@color = Cairo::Color::BLACK
end

def update(c)
c.set_source_color(@color)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Core
def initialize(x,y)
@x, @y = x, y
@r = 5
@color = Cairo::Color::ORANGE
end

def update(c)
c.set_source_color(@color)
c.circle(@x, @y, @r)
c.fill
end
end

class Diagram
attr_accessor :matrix

def initialize(x,y)
@x,@y = x,y
@r = 50
@color = Cairo::Color::GREEN
@line_width = 5
angle_size = 4
step = 360 / angle_size
@vector = []
0.step(359, step) do |dg|
rd= dg * Math::PI / 180
@vector << [@r * Math::cos(rd), @r * Math::sin(rd)]
end
@matrix = Cairo::Matrix.identity
end

def update(c)
c.set_source_color(@color)
c.set_line_width(@line_width)
flag =true
@vector.each do |x0,y0|
x, y = @matrix.transform_point(x0, y0)
if flag
c.move_to(x + @x, y + @y)
else
c.line_to(x + @x, y + @y)
end
flag = false
end
c.close_path
c.stroke
end
end

class Phase
def initialize(w,h)
@image = Cairo::ImageSurface.new(w, h)
@bg = BackGround.new(w, h)
bx = 0
@core = []
@dia = []
4.times do |i|
bx += 100
@core << Core.new(bx, 150)
@dia << Diagram.new(bx, 150)
end
@deg = 0
@angle = 15
end

def update
@deg += @angle
@deg = 0 if @deg > 359
rd = @deg * Math::PI / 180
# 回転
@dia[1].matrix = Cairo::Matrix.rotate(rd)
# せん断
@dia[2].matrix = Cairo::Matrix.new( Math.sin(rd), 1, 1, Math.cos(rd), 0, 0)
# 行列の積 Cairo::Matrix#multiplyと同じ
@dia[3].matrix = @dia[1].matrix * @dia[2].matrix
context = Cairo::Context.new(@image)
@bg.update(context)
@core.each {|obj| obj.update(context)}
@dia.each {|obj| obj.update(context)}
@image
end
end

class Game
def initialize(screen)
@screen = screen
@phase = Phase.new(@screen.w, @screen.h)
end

def update
image = @phase.update
suface = SDL::Surface.new_from(image.data, image.width, image.height, 32, image.stride, 0, 0, 0, 0)
@screen.put(suface, 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(100)
end
end
end

SDL.init(SDL::INIT_VIDEO)
@screen = SDL::Screen.open(500, 300, SDL::Screen.info.bpp, SDL::SWSURFACE)
Game.new(@screen).run
[PR]
by gaziya | 2011-05-09 19:10
弾幕のモデルを、いじっていたら、生き物っぽく見えてきた。
それで、ちょっと改造。
スクリーンセイバーになりそうな気がする。


#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class BackGround
def initialize(info)
@w,@h = info.w,info.h
@color = Cairo::Color::BLACK
end

def update(c)
c.set_source_color(@color)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Core
attr_reader :x,:y
attr_accessor :dx,:dy

def initialize(info)
@info = info
@color = Cairo::Color::ORANGE
@x = @info.w / 2
@y = @info.h / 2
@r = 6
@dx,@dy = 0,0
end

def update(c)
@x += @dx * 5
@x = @r if @x < @r
@x = @info.w - @r if @x >= @info.w - @r
@y += @dy * 5
@y = @r if @y < @r
@y = @info.h - @r if @y >= @info.h - @r
c.set_source_color(@color)
c.circle(@x, @y, @r)
c.fill
end
end

class Barrage
attr_reader :alive

def initialize(x,y,r,g,b)
@x,@y = x,y
@r,@g,@b = r,g,b
@br = 2
@pr = 8
@d = 10
angle_size = 60
step = 360 / angle_size
@vector = []
0.step(359, step) do |d|
r= d * Math::PI / 180
@vector << [Math::cos(r), Math::sin(r)]
end
@alive = true
@limit = 200
end

def update(c)
@pr += @d
return @alive = false if @pr > @limit
c.set_source_rgb(@r,@g,@b)
@vector.each do |x,y|
px,py = @pr * x + @x, @pr * y + @y
c.circle(px, py, @br)
c.fill
end
end
end

class Phase
def initialize(info)
@info = info
@surface = Cairo::ImageSurface.new(@info.w,@info.h)
@bg = BackGround.new(@info)
@core = []
3.times do
@core << Core.new(@info)
end
@barrages = []
@move_ticks = 0
end

def update
if @move_ticks % 10 == 0
@core .each do |obj|
obj.dx = [0, 1, -1][rand(30) % 3]
obj.dy = [0, 1, -1][rand(30) % 3]
end
end
@move_ticks += 1
@barrages.reject!{|obj| !obj.alive}
r,g,b = rand / 2 + 0.5, rand / 2 + 0.5, rand / 2 + 0.5
@core .each do |obj|
@barrages << Barrage.new(obj.x, obj.y, r, g, b)
end
context = Cairo::Context.new(@surface)
@bg.update(context)
@barrages.each {|obj| obj.update(context)}
@core.each {|obj| obj.update(context)}
@surface
end
end

class Game
def initialize(screen)
@screen = screen
info = Struct.new(:w,:h)
@info = info.new(@screen.w,@screen.h)
@phase = Phase.new(@info)
end

def update
cairo = @phase.update
suface = SDL::Surface.new_from(cairo.data,@info.w,@info.h,32,cairo.stride,0,0,0,0)
@screen.put(suface,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(10)
end
end
end

SDL.init(SDL::INIT_VIDEO)
w,h = 800,500
@screen = SDL::Screen.open(w,h,SDL::Screen.info.bpp,SDL::SWSURFACE)
Game.new(@screen).run
[PR]
by gaziya | 2011-05-08 22:13
弾幕を張るのに行列使って変換と思って試していたら、
行列なしで書けた。
行列の使い道も、おいおい考えてみます。

左右のキーで移動。
スペースで弾幕を張る。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class EventHandle
def initialize(handle)
@handle = handle
@type = {
SDL::Event::KeyDown => :sym,
SDL::Event::KeyUp => :sym,
SDL::Event::MouseButtonDown => :button,
SDL::Event::MouseButtonUp => :button
}
end

def handling(event)
name = event.class
if @type[name]
if callback = @handle[[name,event.method(@type[name]).call]]
return callback.call(event)
end
end
if callback = @handle[name]
return callback.call(event)
end
nil
end
end

class BackGround
def initialize(info)
@w,@h = info.w,info.h
@color = Cairo::Color::BLACK
end

def update(c)
c.set_source_color(@color)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Player
attr_accessor :dx,:dy

def initialize(info)
@info = info
@w = @h = 20
@cw = @ch = @w * Math::sqrt(2)
@cx = @cy = @cw / 2
@x = @y = @info.w / 2 - @cx
@r = 45 * Math::PI / 180
@image = Cairo::ImageSurface.new(@cw,@ch)
context = Cairo::Context.new(@image)
context.set_source_color(Cairo::Color::CYAN)
#context.transform(Cairo::Matrix.translate(@cx, 0))
context.matrix = Cairo::Matrix.translate(@cx, 0)
context.transform(Cairo::Matrix.rotate(@r))
context.rectangle(0,0,@w,@h)
context.fill
@dx,@dy = 0,0
end

def center
[@x + @cx,@y + @cy]
end

def update(c)
@x += @dx * 5
@x = 0 if @x < 0
@x = @info.w - @cw if @x >= @info.w - @cw
@y += @dy * 5
@y = 0 if @y < 0
@y = @info.h - @ch if @y >= @info.h - @ch
c.set_source(@image,@x,@y)
c.paint
end
end

class Barrage
attr_reader :alive

def initialize(center)
@x,@y = center
@color = Cairo::Color::YELLOW
@br = 3
@pr = 10
@d = 10
angle_size = 24
step = 360 / angle_size
@vector = []
0.step(359, step) do |d|
r= d * Math::PI / 180
@vector << [Math::cos(r), Math::sin(r)]
end
@alive = true
@limit = 250
end

def update(c)
@pr += @d
return @alive = false if @pr > @limit
c.set_source_color(@color)
@vector.each do |x,y|
px,py = @pr * x + @x, @pr * y + @y
c.circle(px, py, @br)
c.fill
end
end
end

class Phase
def initialize(info)
@info = info
@surface = Cairo::ImageSurface.new(@info.w,@info.h)
@bg = BackGround.new(@info)
@player = Player.new(@info)
@barrage = Barrage.new(@player.center)
@barrages = []
@fire = false
@fire_ticks = 0
@handle = EventHandle.new(
[SDL::Event::KeyDown,SDL::Key::LEFT] => proc{@player.dx -= 1},
[SDL::Event::KeyDown,SDL::Key::RIGHT] => proc{@player.dx += 1},
[SDL::Event::KeyUp,SDL::Key::LEFT] => proc{@player.dx += 1},
[SDL::Event::KeyUp,SDL::Key::RIGHT] => proc{@player.dx -= 1},
[SDL::Event::KeyDown,SDL::Key::UP] => proc{@player.dy -= 1},
[SDL::Event::KeyDown,SDL::Key::DOWN] => proc{@player.dy += 1},
[SDL::Event::KeyUp,SDL::Key::UP] => proc{@player.dy += 1},
[SDL::Event::KeyUp,SDL::Key::DOWN] => proc{@player.dy -= 1},
[SDL::Event::KeyDown,SDL::Key::SPACE] => proc{@fire = true},
[SDL::Event::KeyUp,SDL::Key::SPACE] => proc{@fire = false}
)
end

def handling(event)
@handle.handling(event)
end

def update
@barrages.reject!{|obj| !obj.alive}
if @fire
if @fire_ticks > 15
@barrages << Barrage.new(@player.center)
end
end
@fire_ticks += 1
context = Cairo::Context.new(@surface)

@bg.update(context)
@barrages.each {|obj| obj.update(context)}
@player.update(context)
@surface
end
end

class Game
def initialize(screen)
@screen = screen
info = Struct.new(:w,:h)
@info = info.new(@screen.w,@screen.h)
@phase = Phase.new(@info)
@handle = EventHandle.new(
[SDL::Event::KeyDown,SDL::Key::ESCAPE] => proc{exit},
SDL::Event::Quit => proc{exit}
)
end

def handling(event)
@handle.handling(event)
@phase.handling(event)
end

def update
cairo = @phase.update
suface = SDL::Surface.new_from(cairo.data,@info.w,@info.h,32,cairo.stride,0,0,0,0)
@screen.put(suface,0,0)
end

def run
loop do
while e=SDL::Event.poll
self.handling(e)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
SDL::WM.set_caption("Game","")
SDL::Mouse.hide
w,h = 500,500
@screen = SDL::Screen.open(w,h,SDL::Screen.info.bpp,SDL::SWSURFACE)
Game.new(@screen).run
[PR]
by gaziya | 2011-05-08 09:49
左右のキーで移動。
スペースでミサイル発射。
ミサイルは連続5発まで。
この設定でつくったよ。
ゲーム性は無い。
練習だぁ。

#!usr/bin/env ruby

require 'sdl'
require 'cairo'

class EventHandle
def initialize(handle)
@handle = handle
@type = {
SDL::Event::KeyDown => :sym,
SDL::Event::KeyUp => :sym,
SDL::Event::MouseButtonDown => :button,
SDL::Event::MouseButtonUp => :button
}
end

def handling(event)
name = event.class
if @type[name]
if callback = @handle[[name,event.method(@type[name]).call]]
return callback.call(event)
end
end
if callback = @handle[name]
return callback.call(event)
end
nil
end
end

class BackGround
def initialize(info)
@w,@h = info.w,info.h
@color = Cairo::Color::BLACK
end

def update(c)
c.set_source_color(@color)
c.rectangle(0, 0, @w, @h)
c.fill
end
end

class Player
attr_accessor :dx

def initialize(info)
@info = info
@w,@h = 35,30
@x,@y = (@info.w - @w )/ 2 ,465
@image = Cairo::ImageSurface.new(@w,@h)
context = Cairo::Context.new(@image)
context.set_source_color(Cairo::Color::CYAN)
context.triangle((@w + 1) / 2,0,0,@h,@w,@h)
context.fill
@dx = 0
end

def center_x
@x + (@w + 1) / 2
end

def update(c)
@x += @dx * 8
@x = 0 if @x < 0
@x = @info.w - @w if @x >= @info.w - @w
c.set_source(@image,@x,@y)
c.paint
end
end

class Missile
def initialize(x)
@w,@h = 5,30
@image = Cairo::ImageSurface.new(@w,@h)
@x = x - (@w + 1) / 2
@y = 450
@v = -10
context = Cairo::Context.new(@image)
context.set_source_color(Cairo::Color::YELLOW)
context.rectangle(0,0,@w,@h)
context.fill
end

def y
@y
end

def update(c)
@y += @v
c.set_source(@image,@x,@y)
c.paint
end
end

class Phase
def initialize(info)
@info = info
@surface = Cairo::ImageSurface.new(@info.w,@info.h)
@bg = BackGround.new(@info)
@player = Player.new(@info)
@missiles = []
@fire = false
@fire_ticks = 0
@handle = EventHandle.new(
[SDL::Event::KeyDown,SDL::Key::LEFT] => proc{@player.dx -= 1},
[SDL::Event::KeyDown,SDL::Key::RIGHT] => proc{@player.dx += 1},
[SDL::Event::KeyUp,SDL::Key::LEFT] => proc{@player.dx += 1},
[SDL::Event::KeyUp,SDL::Key::RIGHT] => proc{@player.dx -= 1},
[SDL::Event::KeyDown,SDL::Key::SPACE] => proc{@fire = true},
[SDL::Event::KeyUp,SDL::Key::SPACE] => proc{@fire = false}
)
end

def handling(event)
@handle.handling(event)
end

def update
@missiles.reject!{|obj| obj.y < 20}
if @fire
if @missiles.size < 5
if @fire_ticks > 3
obj = Missile.new(@player.center_x)
@missiles << obj
@fire_ticks = 0
end
end
end
@fire_ticks += 1
context = Cairo::Context.new(@surface)
@bg.update(context)
@missiles.each {|obj| obj.update(context)}
@player.update(context)
@surface
end
end

class Game
def initialize(screen)
@screen = screen
info = Struct.new(:w,:h)
@info = info.new(@screen.w,@screen.h)
@phase = Phase.new(@info)
@handle = EventHandle.new(
[SDL::Event::KeyDown,SDL::Key::ESCAPE] => proc{exit},
SDL::Event::Quit => proc{exit}
)
end

def handling(event)
@handle.handling(event)
@phase.handling(event)
end

def update
cairo = @phase.update
suface = SDL::Surface.new_from(cairo.data,@info.w,@info.h,32,cairo.stride,0,0,0,0)
@screen.put(suface,0,0)
end

def run
loop do
while e=SDL::Event.poll
self.handling(e)
end
self.update
@screen.flip
SDL.delay(20)
end
end
end

SDL.init(SDL::INIT_VIDEO)
SDL::WM.set_caption("Game","")
SDL::Mouse.hide
w,h = 500,500
@screen = SDL::Screen.open(w,h,SDL::Screen.info.bpp,SDL::SWSURFACE)
Game.new(@screen).run
[PR]
by gaziya | 2011-05-06 22:41