迷路の中を歩く(Ruby)

ひとつ前の記事で迷路を生成したので、その中を歩いてみるプログラムを書きました。OpenGL を使っています。Ruby 2.3.3, Linux Mint 18.3 で動作確認。


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

require_relative 'miniopengl'
require_relative 'maze'

module WalkMaze
  def self.start(width, height, yokokabe, tatekabe)
    MiniOpenGL.app width: 400, height: 400, depth_buffer: :on, title: "maze" do
      px, pz = width - 1, 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).times do |z|
          width.times do |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
        end
        (width + 1).times do |x|
          height.times do |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
        end
        
        color(1, 0, 0)
        draw_vertex(GL_QUADS, 3, [0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1])    #ゴールの床
        
        display
      end
      
      set_eye = ->{
        init_modelview
        x = px + 0.5
        z = pz + 0.5
        look_at(x, 0.5, z, x + dir[0], 0.5, z + dir[1], 0, 1, 0)
      }
      
      reshape do |w, h|
        viewport(0, 0, w, h)
        init_projection
        perspective(120, w / h.to_f, 0.2, 20)
        set_eye.()
      end
      
      check = ->{
        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_f = false
      
      key_in2 do |key|
        exit if end_f
        
        case key
        when GLUT_KEY_LEFT    #左
          dir = [dir[1], -dir[0]]
        when GLUT_KEY_RIGHT   #右
          dir = [-dir[1], dir[0]]
        when GLUT_KEY_UP      #前
          if check.()    #前へ進めるかどうか
            px += dir[0]
            pz += dir[1]
          end
        end
        
        set_eye.()
        redisplay
        
        if px.zero? and pz.zero?
          puts "Goal!"
          end_f = true
        end
      end
      
    end
  end
end


Width, Height = 10, 10

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

#Left, Top = 20, 20
#CellWidth = 20
#
#fork { show_maze(Width, Height, yokokabe, tatekabe) }

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

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

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


※追記
これの立体版も作ってみました。
obelisk.hatenablog.com