今まで、フレームレートには、手を出さなかった。
でも、ちょっと処理が多いプログラムだと、長く起動していると、なんか遅れていく気がする。
それで、ちょっと書いてみた。
 映画だと、1秒で60回らしい。
webで検索したら、ActionScriptは、何となく30回くらいでやってるような・・・
とりあえず、1秒30回を基本にした。
描写が、間に合わない場合は、スキップするようにいました。

#!/usr/bin/env ruby

require 'sdl'
require 'cairo'

class Sprite
  attr_accessor :x, :y, :alive, :enabled, :idx, :info
  attr_writer :draw, :matrix

  def initialize
    @x, @y = 0, 0
    @alive = true
    @enabled = true
    @idx = 0
    @info = {}
    @matrix = Cairo::Matrix.identity
  end

  def renew(cr)
    return if !@enabled
    cr.matrix = @matrix * Cairo::Matrix.translate(@x, @y)
    @draw[cr]
  end
end

class Phase
  attr_accessor :handles, :task

  def initialize(w, h, info=nil)
    @image = Cairo::ImageSurface.new(w, h)
    @info = info
    @sprites = []
    @handles = {}
  end

  def addSprite
    @sprites << Sprite.new
    yield(@sprites.last)
    @sprites.last
  end

  def renew(drawFlag=true)
    @task[] if @task
    if drawFlag
      cr = Cairo::Context.new(@image)
      @sprites.reject!{|obj| !obj.alive}
      @sprites.each {|obj| obj.renew(cr)}
      @image
    else
      nil
    end
  end

  def layerSort
    @sprites.sort!{|a, b| a.idx <=> b.idx}
  end
end

class Fps
  attr_reader :size

  def initialize(frame_size = 30)
    @size = frame_size
    @old_time = SDL.getTicks
    @wait_time = 1000 / @size
  end

  def wait
    ret = false
    while SDL.getTicks - @old_time < @wait_time
      sleep(0.001)
      ret = true
    end
    @old_time += @wait_time
    ret
  end
end

SDL.init(SDL::INIT_VIDEO)
SDL::WM.set_caption("Frame / Second","")
w, h = 350, 350
screen = SDL::Screen.open(w, h, 32, 0)
phase = Phase.new(w, h)
phase.addSprite do |obj|
  obj.draw = proc do |cr|
    cr.set_source_color(Cairo::Color::BLACK)
    cr.rectangle(0, 0, w, h)
    cr.fill
  end
end
pos = :center
text = phase.addSprite do |obj|
  obj.x, obj.y = w / 2, h / 2
  obj.info[:deg] = 0
  obj.draw = proc do |cr|
    cr.set_source_color(Cairo::Color::YELLOW)
    cr.font_size = 35
    str = "30Frame/Second"
    ext = cr.text_extents(str)
    axis ={
      :center => [(ext.x_bearing + ext.width) / -2, ext.height / 2],
      :left_top => [-ext.x_bearing, ext.height],
      :right_top => [-ext.x_bearing - ext.width, ext.height],
      :left_bottom => [-ext.x_bearing, 0],
      :right_bottom => [-ext.x_bearing - ext.width, 0]
    }
    x, y = axis[pos]
    cr.move_to(x, y)
    cr.show_text(str)
  end
end
phase.addSprite do |obj|
  font_size = 25
  obj.x, obj.y = 30, h - 35
  obj.draw = proc do |cr|
    cr.set_source_color(Cairo::Color::WHITE)
    cr.font_size = font_size
    cr.move_to(0, font_size)
    cr.show_text("Axis Point  :%s" % pos.to_s)
  end
end
phase.handles[SDL::Event::Quit] = proc{exit}
phase.handles[SDL::Event::KeyDown] = proc{|e| exit if e.sym == SDL::Key::ESCAPE}
fps = Fps.new
skep = 360 / (fps.size * 5)
idx = 0
phase.task = proc do
  text.info[:deg] += skep
  if text.info[:deg] > 359
    text.info[:deg] = 0
    idx += 1
    idx = 0 if idx > 4
    pos = [:center, :left_top, :right_top, :left_bottom, :right_bottom][idx]
  end
  text.matrix =  Cairo::Matrix::rotate(text.info[:deg] * Math::PI / 180)
end
loop do
  while e = SDL::Event.poll
    if handle = phase.handles[e.class]
      handle[e]
    end
  end
  if image = phase.renew(fps.wait)
    surface = SDL::Surface.new_from(image.data, w, h, 32, image.stride, 0, 0, 0, 0)
    screen.put(surface,0,0)
    screen.flip
  end
end