サイログ。

~雑多な記事置き場~

遷移図を描く様に、ってどんなの?

遷移図クラスにノードとアロー(ノード間の有向グラフと考えていただければ・・・)を追加していきます。

こういうふうに書きます。


リストのうち、DiagramProcessorクラスが、遷移図の操作クラスです。

PreMesNode1〜3などが遷移図のノードとなります。
PreMesNode1では、画像を一定間隔で透明にしていきます。
PreMesNode2では、画像を変更せずに4秒間表示します。
PreMesNode3では、画像を一定間隔で不透明にしていきます。

PreMesTriggerクラスは、ノードの実行条件を設定するクラスです。
サンプルでは、0.1秒ごとに処理を実行するようになっています。

これらのクラスのインスタンスを、:trans_0_0〜:trans_1_2として登録して、
それぞれのインスタンスのメソッドを順に実行するように設定しています。
最後に、処理を終了する場合は移動先を nil に設定します。

ちなみに、開始は :trans_0_0 で登録したインスタンス

class PreMesNode1
  include DiagramNodeBase

  attr_reader :finished
  
  def initialize(base, sprite)
    @base = base
    @sprite = sprite
    @finished = false
  end
  
  def start
    @base.show
    @sprite.show
  end
  
  def update
    @base.alpha -= 5
    if @base.alpha <= 0
      @base.alpha = 0
      @finished = true
    end
  end
end

class PreMesNode2
  include DiagramNodeBase

  attr_reader :finished
  
  def initialize(base, sprite)
    @base = base
    @sprite = sprite
    @timer = WaitCounter.new(4.0)
    @finished = false
  end
  
  def start
    @timer.start
  end
  
  def stop
    @timer.stop
  end
  
  def update
    @finished = @timer.finish?
  end
end

class PreMesNode3
  include DiagramNodeBase

  attr_reader :finished
  
  def initialize(base, sprite)
    @base = base
    @sprite = sprite
    @finished = false
  end
  
  def update
    @base.alpha += 5
    if @base.alpha >= 255
      @base.alpha = 255
      @finished = true
    end
  end
  
  def stop
    @sprite.hide
    @base.hide
  end
end

class PreMesTrigger
  include NodeTriggerBase
  
  def initialize(wait)
    @counter = WaitCounter.new(wait)
  end
  
  def pre_process
    @counter.start
  end
  
  def post_process
    @counter.stop
  end

  def update?
    return @counter.finish?
  end
  
  def post_update
    @counter.start
  end
end

class PreMessage
  include Story::Scene

  def self.scene_type
    return :scene
  end

  def init
    @info = Shape.text(:font=>Font.serif){ text "Press Any Key to Skip" }.center.bottom{|b| 5.percent(b) }
    @info.dp = 2

    @base = Sprite.new(:size=>[Screen.w, Screen.h], :type=>:as).centering
    @base.fill([0,0,0])
    @base.alpha = 255
    @base.dp = 1

    @images = ["image/pre1.png", "image/pre2.png"].inject([]) {|images, img_fname|
      images << Sprite.new(:file=>img_fname, :type=>:ac).property{|o| o.dp = 0 }.centering
    }

    @processor = DiagramProcessor.new{|dia|
      @images.each_with_index{|img, idx|
        dia.add "trans_#{idx}_0".to_sym, PreMesNode1.new(@base, img), PreMesTrigger.new(0.05)
        dia.add "trans_#{idx}_1".to_sym, PreMesNode2.new(@base, img)
        dia.add "trans_#{idx}_2".to_sym, PreMesNode3.new(@base, img), PreMesTrigger.new(0.05)
      }
      dia.add_arrow(:trans_0_0, :trans_0_1){|obj| obj.finished }
      dia.add_arrow(:trans_0_1, :trans_0_2){|obj| obj.finished }
      dia.add_arrow(:trans_0_2, :trans_1_0){|obj| obj.finished }
      dia.add_arrow(:trans_1_0, :trans_1_1){|obj| obj.finished }
      dia.add_arrow(:trans_1_1, :trans_1_2){|obj| obj.finished }
      dia.add_arrow(:trans_1_2, nil){|obj| obj.finished }
    }
  end

  def setup
    @info.show
    @processor.start
  end
  
  def update
    return Prologue if Input.pushed_any? # 何かキーが押されたらメッセージ表示をスキップ
    return Prologue if @processor.finish? # 注意メッセージが終了したら次のシーンへ
    return @now
  end

  def final
    @processor.stop
    @info.hide
    @images.each{|img| img.hide }
    @base.hide
  end

  def dispose
    @base.dispose
    @images.each{|img| img.dispose }
    @info.dispose
  end
end

次のサンプルは、移動条件による移動先ノードを変更するサンプルです。
(ちなみに、開始は :first で登録したインスタンス

thirdで登録したインスタンスからの移動先を、条件によって
firstかnil(つまり終了)

に振り分けています。

class Node1
  include DiagramNodeBase

  attr_reader :v

  def initialize
    @v = 0
  end

  def update
    puts "1"
    @v = (@v == 0 ? 1 : 0)
  end

  def render
    puts "render 1"
  end
end

class Node2
  include DiagramNodeBase

  def update
    puts "2"
  end

  def render
    puts "render 2"
  end
end

class Node3
  include DiagramNodeBase

  attr_reader :v

  def initialize
    @v = 0
  end

  def update
    puts "3 : #{@v}"
    @v += 1
  end

  def render
    puts "render 3"
  end
end

class Trigger2
  include NodeTriggerBase

  def update?
    sleep(1)
    return true
  end
end

if __FILE__ == $0
  # TODO Generated stub
  pr = DiagramProcessor.new{|dia|
    dia.add :first,  Node1.new
    dia.add :second, Node2.new, Trigger2.new
    dia.add :third,  Node3.new
    dia.add_arrow(:first, :third ){|node| node.v == 1 }
    dia.add_arrow(:first, :second )
    dia.add_arrow(:second, :third )
    dia.add_arrow(:third, nil ){|node| node.v > 10 }
    dia.add_arrow(:third, :first )
  }
  rr = pr.renderer
  pr.start
  until pr.finish? do
    rr.render
  end
  pr.stop
end

たぶん、このままではわかりにくいとは思いますので、時間があれば説明していきたいと思います。