弾幕だけ

弾幕を張るのに行列使って変換と思って試していたら、
行列なしで書けた。
行列の使い道も、おいおい考えてみます。

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

#!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