DTLの自作レンダラの実験

いいスクリーンショットがなかなか撮れない。のでgif動画にしてみた。

土屋つかささんのdxruby_text_layerを使って、独自レンダラを書いて、この間のmieki256さんのSTGサンプルのステージクリアの文字みたいな動きを(アルゴリズムパクって)作ってみた。それ以外のコードはDTLサンプルからパクった。パクりまくりである。
ざっくり作っただけだからもうちょい効果的な感じに調整する必要はあるのだろうけど、とりあえず動いたかなーという感じ。
現状では文字レンダラ側から描画先のサイズが取得できないところが地味に問題だけど、それはまあ、別に汎用的である必要も無いんじゃないかと思うので使う人がいたら自分で調整してください。
画面から出たときに描画する必要は無いだろうから、@stateが:endになったら描画しないようにするとちょっと無駄が無くなるかもしれない。@non_active_textから消し去りたい気もするが。
あとたぶん、元のアルゴリズムは画面の中央あたりに描画するためのモノで、画面の任意の位置に描画する場合はちょっと考え直す必要があるのだと思う。

require 'dxruby'
require './dxruby_text_layer'

class HogeCharRenderer < Char_renderer_base
  def initialize( x, 
                  y, 
                  char, 
                  font, 
                  font_config, 
                  is_skip, 
                  mode, 
                  options = {})

    @width, @height, offset_x, offset_y = normalize_image(char, font, font_config)

    @ex = x - offset_x + @width / 2
    @ey = y - offset_y + @height / 2

    rad = Math.atan2(240 - @ey, 320 - @ex)
    @x = @ex + Math.cos(rad) * 800
    @y = @ey + Math.sin(rad) * 800
    @dx = -Math.cos(rad) * 4
    @dy = -Math.sin(rad) * 4

    @scale = 8.0

    @image = Image.new(@width, @height) 
    @image.draw_font_ex(offset_x, offset_y, char, font, font_config)

    @state = :start
  end

  def update
    case @state
    when :start
      d = 0.2
      @x += (@ex - @x) * d
      @y += (@ey - @y) * d
      @scale += (1.0 - @scale) * 0.2
      if (@ex - @x).abs < 1.0 and (@ey - @y).abs < 1.0
        @x = @ex
        @y = @ey
        @scale = 1
        @state = :active
      end

    when :active

    when :non_active
      @x += @dx
      @y += @dy
      @dx *= 1.15
      @dy *= 1.15
      @scale *= 0.98

      if @x < -100 or @x > 740 or @y < -200 or @y > 580
        @state = :end
      end

    when :end
    end
  end

  def draw(rt)
    rt.draw_scale(@x - @width / 2, @y - @height / 2, @image, @scale, @scale)
  end

  def start_non_active
    @state = :non_active
  end
end



#テキストレイヤ生成
layer = Dxruby_text_layer.new(640, 480, :char_renderer=>HogeCharRenderer)

commands = [
[:line_feed, nil],
[:line_feed, nil],
[:text, :text =>"自作文字レンダラテスト"],
[:line_feed, nil],
[:text, :text =>"こんな感じに動く■"],
[:stop, nil],
[:clear_active_text, nil],
[:line_feed, nil],
[:text, :text =>"ちょっと思ってたのと違うけど"],
[:line_feed, nil],
[:text, :text =>"まあいいか■"],
[:stop, nil],
[:clear_active_text, nil],
[:line_feed, nil],
[:text, :text =>"かなり無理矢理感があるぞ"],
[:line_feed, nil],
[:text, :text =>"でも動いたからOKOK"],
[:stop, nil],
[:clear_active_text, nil],
]

#ゲームループ
Window.loop do

  #テキストレイヤが処理を停止していて、かつスペースキーが入力された場合。
  if layer.stop? and Input.key_push?(K_SPACE)
    #コマンドの処理
    loop do
      #コマンド配列が空ならループを抜ける
      break if commands.empty?

      #コマンドを取り出す
      command = commands.shift
      case command[0]
      when :stop
        #シナリオの読み取りを一時停止し、描画終了まで待機状態に入る。
        break
      when :text 
        #文字列を分解してcharコマンドに変換する
        command[1][:text].each_char do |ch|
          #コマンドをスタックする
          layer.stack_command(:char, {:char => ch})
        end
      else
        #他のコマンドはテキストレイヤが処理するとしてコマンドをスタックする
        layer.stack_command(command[0],command[1])
      end
    end 
  end

  #テキストレイヤ処理
  layer.update

  #テキストレイヤ描画
  Window.draw(0, 0, layer.image)
end