迷路の中を歩く(Ruby)

ひとつ前の記事で迷路を生成したので、その中を歩いてみるプログラムを書きました。OpenGL を使っています。


 
 
赤い床のマスがゴールです。"v" で左回転、"b" で右回転、スペースで前進します。迷路は実行のたびに新たに生成されます。
ぐぐってみても意外とこんな単純なゲーム(?)の実装がないのですよねえ。

require './miniopengl'
require './maze'

module WalkMaze
  def self.start(width, height, yokokabe, tatekabe)
    MiniOpenGL.app width: 400, height: 400, depth_buffer: :on, title: "maze" do
      px = width - 1; pz = height - 1    #迷路のスタート位置
      dir = [0, -1]                      #最初の向きの設定
      
      draw do
        glEnable(GL_BLEND)         #混合処理を可能にします
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        self.color_alpha = 0.9 
        glEnable(GL_DEPTH_TEST)    #隠面消去
        clear
        
        color(0, 1, 1)
        (height + 1).times {|z| line3(0, 0, z, width, 0, z)}
        (width  + 1).times {|x| line3(x, 0, 0, x, 0, height)}
        
        color(0, 0.8, 0)
        [height + 1, width].nest_loop do |z, x|
          next if yokokabe[x + z * width].zero?
          vtx = [x, 0, z, x + 1, 0, z, x + 1, 1, z, x, 1, z]
          draw_vertex(GL_QUADS, 3, vtx)
        end
        [width + 1, height].nest_loop do |x, z|
          next if tatekabe[z + x * height].zero?
          vtx = [x, 0, z, x, 0, z + 1, x, 1, z + 1, x, 1, z]
          draw_vertex(GL_QUADS, 3, vtx)
        end
        
        color(1, 0, 0)
        draw_vertex(GL_QUADS, 3, [0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1])    #ゴールの床
        
        display
      end
      
      reshape do |w, h|
        viewport(0, 0, w, h)
        init_projection
        perspective(120, w / h.to_f, 0.2, 20)
        init_modelview
        look_at(x = px + 0.5, 0.5, z = pz + 0.5, x + dir[0], 0.5, z + dir[1], 0, 1, 0)
      end
      
      check = lambda do
        if dir[0].zero?
          z = (dir[1] < 0) ? pz : pz + 1
          f = yokokabe[z * width + px]
        else
          x = (dir[0] < 0) ? px : px + 1
          f = tatekabe[x * height + pz]
        end
        f.zero?
      end
      
      end_f = false
      
      key_in do |key|
        exit if end_f
        case key
        when "v"    #左
          dir = [dir[1], -dir[0]]
        when "b"    #右
          dir = [-dir[1], dir[0]]
        when " "    #前
          if check.call    #前へ進めるかどうか
            px += dir[0]
            pz += dir[1]
          end
        end
        init_modelview
        look_at(x = px + 0.5, 0.5, z = pz + 0.5, x + dir[0], 0.5, z + dir[1], 0, 1, 0)
        redisplay
        if px.zero? and pz.zero?
          puts "Goal!"
          end_f = true
        end
      end
    end
  end
end


Width = 10; Height = 10

yokokabe, tatekabe = Maze.new(Width, Height).generate

Left = 20; Top = 20
CellWidth = 20

#fork { show_maze(Width, Height, yokokabe, tatekabe) }

WalkMaze.start(Width, Height, yokokabe, tatekabe)

maze.rb はひとつ前の記事です。miniopengl.rb はこちらを参照。

なお、LinuxOpenGL についてはこちらも参照。