Ruby/SDL でゲームパッドを使う

20181011133328
ゲームパッドで四角が動き回ります。Aボタンでビームの発射、Bボタンで一時停止、selectボタンで終了。

sdl_sample7.rb

require 'sdl'

Width, Height = 300, 300
SDL.init(SDL::INIT_VIDEO | SDL::INIT_JOYSTICK | SDL::INIT_AUDIO)
screen = SDL::Screen.open(Width, Height, 16, SDL::SWSURFACE)
SDL::WM::set_caption("SDL", "")

SDL::Mixer.open(22050, SDL::Mixer::DEFAULT_FORMAT, 2, 512)
wave = SDL::Mixer::Wave.load("shot.wav")
wave.set_volume(10)

L = 20
joy = SDL::Joystick.open(0)
black  = [0,   0, 0]
rcolor = [0, 255, 0]
x, y = (Width - L) / 2, (Height - L) / 2
dir = [1, 0]
f = true
beam = nil

# 正方形
rect = Fiber.new do
  loop do
    screen.fill_rect(x, y , L, L, rcolor)
    
    x += dir[0]
    y += dir[1]
    x = Width  - L if x < 0
    y = Height - L if y < 0
    x = 0 if x > Width  - L
    y = 0 if y > Height - L
    
    Fiber.yield
  end
end

# ビーム
class Beam
  LB = 40
  Step = 10
  def initialize(rx, ry, dir1, screen)
    @x1 = @x2 = rx
    @y1 = @y2 = ry
    @dir = dir1
    @s = screen
    @l = 0
  end
  attr_writer :color
  
  def draw
    @s.draw_line(@x1, @y1, @x2, @y2, @color)
  end
  
  def next
    @x1 += @dir[0] * Step
    @y1 += @dir[1] * Step
    @l += Step
    if @l > LB
      @x2 += @dir[0] * Step
      @y2 += @dir[1] * Step
      @l = LB
    end 
    
    @x2 < 0 or @x2 > Width or @y2 < 0 or @y2 > Height 
  end
end

generate = lambda do
  Fiber.new do
    beams = [[1, 0], [0, -1], [-1, 0], [0, 1]].map do |dir1|
      Beam.new(x + L / 2, y + L / 2, dir1, screen)
    end
    loop do
      color = [rand(256), rand(256), rand(256)]
      break if beams.map do |b|
        b.color = color
        b.draw
        b.next
      end.all?
      Fiber.yield(false)
    end
    true
  end
end


## mainloop
loop do
  while event = SDL::Event.poll
    case event
    when SDL::Event::Quit then exit
    end
  end
  
  screen.fill_rect(0, 0 , Width, Height, black)
  SDL::Joystick.update_all
  
  # 十字キーの処理
  jh, jv = joy.axis(0) / 32768.0, joy.axis(1) / 32768.0
  dir = [jh.round, jv.round] if jh.nonzero? or jv.nonzero?
  
  # Aボタンでビームの発射
  if joy.button(0) and f
    f = false
    beam = generate.call
    rcolor = [rand(256), rand(256), rand(256)]
    SDL::Mixer.play_channel(0, wave, 0)
  end
  f = beam.resume unless f
  
  # 正方形の処理
  rect.resume

  # Bボタンを押しているあいだ静止  
  SDL::Joystick.update_all while joy.button(1)

  # selectボタンで終了
  exit if joy.button(6)
  
  screen.update_rect(0, 0, 0, 0)
  sleep(0.01)
end

なるたけ Fiber を使ってみました。発射音の shot.wav ファイルが必要です(ここからダウンロードできます)。
音源はここから頂きました。ありがとうございます。

 
marginalia.hatenablog.com