メインコンテンツへスキップ
見出し画像

【pyxel 1.5】pyxelで3D迷路を作ってみる(3)

    前回は迷路データをPyxel Editorのタイルマップから取り込めるようにしてみました。ただまだ見た目的にはさみしいし、同じ風景ばかりで自分がどこにいるかわかりません。今回は見た目部分の改修と、マップに印を付けられる機能を追加してみたいと思います。

    前回までの進行具合は以下のnoteをご参照ください。

    画像

    ▲スペースキーで自分のいるマスに印をつけることができます。

    画像

    ▲数マス前から印が見えています。この機能で、一度通った道を把握できます。今のところは無制限に使えます。

    画像

    ▲見た目がさみしいので泡のエフェクトを追加してみました。gifにするのがうまくいかず、ちょっと画像サイズが小さいですが…。海底遺跡のような水系のダンジョンのイメージです。

    それではコードの内容に移っていこうと思います。

      def __init__(self):
          pyxel.init(256, 256, title = "pyxel")
          pyxel.load('assets/assets.pyxres')
                 
          #Maze set
          self.data = []
          self.maze = []
          
          for i in range(32):
              self.data = []
              for i2 in range(32):
                  self.data.append(pyxel.tilemap(0).pget(i2,i))
              self.maze.append(self.data)
          
          #Player position
          self.pos = [1, 1]
          #Move permission tile list      
          self.move_permit = [(0, 0), (0, 1)]
          
          #Angle P=Player
          #    ^
          #    1
          #<4  P   2>
          #    3
          #    v
          #     
          self.pos_angle = 3
          
          #Wall set
          self.wall = [[0, 0],
                       [0, 0],
                       [0, 0],
                       [0, 0],]
          
          for i1 in range(5):
              x1 = self.pos[1] - (1 * i1)
              if self.maze[x1][self.pos[0]] == 1:
                  self.dead_end = i1      
          self.dead_end = 0
          
          #Floor
          self.floor = [0, 0, 0, 0]
          
          #Bubble
          self.bubbles = [] 
          #Bubble color list
          self.bub_c = (1, 5, 6, 12)
          
          
          pyxel.run(self.update, self.draw)

    ▲init部分です。床の印を格納するfloorと泡の描写に関するbubbles、bub_cの変数を追加しました。bub_cは泡の色を決定するカラーコードのリストです。

      def update(self): 
          #Bubble generate test---------------------------------------------------
          if pyxel.btnp(pyxel.KEY_B):
              c = choice(self.bub_c)
              x = randint(0, 256)
              y = randint(160, 220)
              v = randint(0, 2)
              s1 = randint(1, 2)
              s2 = randint(1, 9) / 10
              s = s1 + s2
              new_bubble = Bubble(x, y, v, c, s)
              self.bubbles.append(new_bubble)
          #-----------------------------------------------------------------------
          
          #Bubble update----------------------------------------------------------    
          for b in self.bubbles:
              b.update()
              if b.bub_y < 0:
                  del b
          
          #New bubble create
          if pyxel.frame_count % 300 == 0:
              b_num = randint(2, 10)
              for bn in range(b_num):
                  c = choice(self.bub_c)
                  x = randint(30, 220)
                  y = randint(160, 220)
                  v = randint(0, 2)
                  s1 = randint(1, 2)
                  s2 = randint(1, 9) / 10
                  s = s1 + s2
                  new_bubble = Bubble(x, y, v, c, s)
                  self.bubbles.append(new_bubble)
           #----------------------------------------------------------------------
              
          
          #Wall reset
          self.wall = [[0, 0],
                       [0, 0],
                       [0, 0],
                       [0, 0],]      
          self.floor = [0, 0, 0, 0]
                  
          #Player Controll--------------------------------------------------------
          #Go ahead
          if pyxel.btnp(pyxel.KEY_UP):
     
              self.dead_end = 0
              if self.pos_angle == 1:
                  if self.maze[self.pos[1] - 1][self.pos[0]] in self.move_permit:
                      self.pos[1] = self.pos[1] - 1
                      self.pos_angle = 1
              elif self.pos_angle == 2:
                  if self.maze[self.pos[1]][self.pos[0] + 1] in self.move_permit:
                      self.pos[0] = self.pos[0] + 1
                      self.pos_angle = 2
              elif self.pos_angle == 3:
                  if self.maze[self.pos[1] + 1][self.pos[0]] in self.move_permit:
                      self.pos[1] = self.pos[1] + 1
                      self.pos_angle = 3
              elif self.pos_angle == 4:
                  if self.maze[self.pos[1]][self.pos[0] - 1] in self.move_permit:
                      self.pos[0] = self.pos[0] - 1     
                      self.pos_angle = 4
                      
    
          #Turn to the back
          if pyxel.btnp(pyxel.KEY_DOWN):
              self.dead_end = 0
              if self.pos_angle == 1:
                  self.pos_angle = 3
              elif self.pos_angle == 2:
                  self.pos_angle = 4
              elif self.pos_angle == 3:
                  self.pos_angle = 1
              elif self.pos_angle == 4:
                  self.pos_angle = 2
              
          #Turn to the right
          if pyxel.btnp(pyxel.KEY_RIGHT):
              self.dead_end = 0
              if self.pos_angle == 1:
                  self.pos_angle = 2
              elif self.pos_angle == 2:              
                  self.pos_angle = 3
              elif self.pos_angle == 3:              
                  self.pos_angle = 4
              elif self.pos_angle == 4:              
                  self.pos_angle = 1
              
          #Turn to the left
          if pyxel.btnp(pyxel.KEY_LEFT):
              self.dead_end = 0
              if self.pos_angle == 1:
                  self.pos_angle = 4
              elif self.pos_angle == 2:             
                  self.pos_angle = 1
              elif self.pos_angle == 3:              
                  self.pos_angle = 2
              elif self.pos_angle == 4:
                  self.pos_angle = 3    
          #-----------------------------------------------------------------------
      
          #Wall-Floor set---------------------------------------------------------      
          if self.pos_angle == 1:
              for i1 in range(4):
                  if self.pos[1] - i1 < 0:
                      break           
                  for i2 in range(2):
                      p1 = self.pos[1] - (1 * i1)
                      p2 = self.pos[0] - 1 + (2 * i2) 
                  
                      self.wall[i1][i2] = self.maze[p1][p2]
                                   
                      if self.maze[p1][self.pos[0]] == (1, 0):
                          if self.dead_end == 0:
                              self.dead_end = i1
                          if self.dead_end > i1:
                              self.dead_end = i1
                      elif self.maze[p1][self.pos[0]] == (0, 1):
                          self.floor[i1] = 1
    
                            
          elif self.pos_angle == 3:
              for i1 in range(4):
                  if self.pos[1] + i1 > 31:
                      break
                  for i2 in range(2):
                      p1 = self.pos[1] + (1 * i1)
                      p2 = self.pos[0] + 1 - (2 * i2) 
                  
                      self.wall[i1][i2] = self.maze[p1][p2]
                  
                      if self.maze[p1][self.pos[0]] == (1, 0):
                          if self.dead_end == 0:
                              self.dead_end = i1
                          if self.dead_end > i1:
                              self.dead_end = i1
                      elif self.maze[p1][self.pos[0]] == (0, 1):
                          self.floor[i1] = 1                          
                          
          elif self.pos_angle == 2:
              for i1 in range(4):
                  if self.pos[0] + i1 > 31:
                      break
                  for i2 in range(2):
                      p1 = self.pos[1] - 1 + (2 * i2) 
                      p2 = self.pos[0] + (1 * i1)
                  
                      self.wall[i1][i2] = self.maze[p1][p2]
                  
                      if self.maze[self.pos[1]][p2] == (1, 0):
                          if self.dead_end == 0:
                              self.dead_end = i1
                          if self.dead_end > i1:
                              self.dead_end = i1             
                      elif self.maze[self.pos[1]][p2] == (0, 1):
                          self.floor[i1] = 1                          
                              
          elif self.pos_angle == 4:
              for i1 in range(4):
                  if self.pos[0] - i1 < 0:
                      break
                  for i2 in range(2):
                      p1 = self.pos[1] + 1 - (2 * i2) 
                      p2 = self.pos[0] - (1 * i1)
                  
                      self.wall[i1][i2] = self.maze[p1][p2]
                  
                      if self.maze[self.pos[1]][p2] == (1, 0):
                          if self.dead_end == 0:
                              self.dead_end = i1
                          if self.dead_end > i1:
                              self.dead_end = i1        
                      elif self.maze[self.pos[1]][p2] == (0, 1):
                          self.floor[i1] = 1                          
          #-----------------------------------------------------------------------
          
          #Paint floor action-----------------------------------------------------
          if pyxel.btnp(pyxel.KEY_SPACE):
              self.maze[self.pos[1]][self.pos[0]] = (0, 1)                        
          #-----------------------------------------------------------------------
    

    ▲update部分です。泡エフェクトの生成、アップデート、床に印を付けるアクションを追加しています。各部分ごとに書いていきます。

          #Bubble generate test---------------------------------------------------
          if pyxel.btnp(pyxel.KEY_B):
              c = choice(self.bub_c)
              x = randint(0, 256)
              y = randint(160, 220)
              v = randint(0, 2)
              s1 = randint(1, 2)
              s2 = randint(1, 9) / 10
              s = s1 + s2
              new_bubble = Bubble(x, y, v, c, s)
              self.bubbles.append(new_bubble)
          #-----------------------------------------------------------------------
          
          #New bubble create------------------------------------------------------
          if pyxel.frame_count % 300 == 0:
              b_num = randint(2, 10)
              for bn in range(b_num):
                  c = choice(self.bub_c)
                  x = randint(30, 220)
                  y = randint(160, 220)
                  v = randint(0, 2)
                  s1 = randint(1, 2)
                  s2 = randint(1, 9) / 10
                  s = s1 + s2
                  new_bubble = Bubble(x, y, v, c, s)
                  self.bubbles.append(new_bubble)
                  
          #Bubble update----------------------------------------------------------    
          for b in self.bubbles:
              b.update()
              if b.bub_y < 0:
                  del b              
           #----------------------------------------------------------------------

    ▲まずは泡のエフェクトに関する部分です。
    泡は新しく作ったBubbleクラスから作成したオブジェクトとして保持します。クラス部分は後ほど記載します。引数としてはBubble(初期x座標, 初期y座標, 種類, 色, スピード)となっています。今回はテストのためBキーを押すと泡が作成されます。
    それとは別に時間経過でも泡が発生するようにしておきます。
    if pyxel.frame_count % 300 == 0: のIF文で一定のフレーム経過で泡の発生ロジックが走ります。発生個数は2から10までのランダムです。色についてはinit部分で定義したbub_cの中からchoiceでランダムに選択しています。

          #Paint floor action-----------------------------------------------------
          if pyxel.btnp(pyxel.KEY_SPACE):
              self.maze[self.pos[1]][self.pos[0]] = (0, 1)                        
          #-----------------------------------------------------------------------

    ▲続いて床に印を付けるアクションです。スペースキーが押された際に、自分のいるマス目を(0, 1)に変えます。

      def draw(self):
          pyxel.cls(0)      
          
    #Draw wall 1------------------------------------------------------------------      
          if self.wall[0][0] == (1, 0):
              pyxel.line(0, 0, 50, 29, 6)
              pyxel.line(0, 0, 0, 150, 6)
              pyxel.line(0, 150, 50, 121, 6)
              pyxel.line(50, 29, 50, 121, 6)
          else:
              pyxel.line(0, 29, 50, 29, 6)
              pyxel.line(0, 121, 50, 121, 6)
          if self.wall[0][1] == (1, 0):       
              pyxel.line(256, 0, 205, 29, 6)
              pyxel.line(256, 150, 205, 121, 6)      
              pyxel.line(255, 0, 255, 150, 6)
              pyxel.line(205, 29, 205, 121, 6)
          else:
              pyxel.line(256, 29, 205, 29, 6)
              pyxel.line(256, 121, 205, 121, 6)
    #-----------------------------------------------------------------------------          
    
    #Draw wall 2------------------------------------------------------------------                    
          if self.wall[1][0] == (1, 0):       
              pyxel.line(50, 29, 80, 45, 12)
              pyxel.line(50, 121, 80, 105, 12)
              pyxel.line(50, 29, 50, 121, 12)
              pyxel.line(80, 45, 80, 105, 12)
          else:          
              pyxel.line(79, 45, 51, 45, 12)
              pyxel.line(79, 105, 51, 105, 12)
          if self.wall[1][1] == (1, 0):       
             pyxel.line(205, 29, 175, 45, 12)
             pyxel.line(205, 121, 175, 105, 12)
             pyxel.line(205, 29, 205, 121, 12)
             pyxel.line(175, 45, 175, 105, 12)
          else:          
              pyxel.line(176, 45, 204, 45, 12)
              pyxel.line(176, 105, 204, 105, 12)      
    #----------------------------------------------------------------------------          
          
    #Draw wall 3-----------------------------------------------------------------                  
          if self.wall[2][0] == (1, 0):       
              pyxel.line(80, 45, 97, 55, 5)
              pyxel.line(80, 105, 97, 95, 5)
              pyxel.line(80, 45, 80, 105, 5)
              pyxel.line(97, 55, 97, 95, 5)
          else:
              pyxel.line(97, 55, 81, 55, 5)
              pyxel.line(97, 95, 81, 95, 5)
          if self.wall[2][1] == (1, 0):       
              pyxel.line(175, 45, 158, 55, 5)
              pyxel.line(175, 105, 158, 95, 5)
              pyxel.line(175, 45, 175, 105, 5)
              pyxel.line(158, 55, 158, 95, 5)
          else:
              pyxel.line(158, 55, 174, 55, 5)
              pyxel.line(158, 95, 174, 95, 5)
    #----------------------------------------------------------------------------
    
    #Draw wall 4-----------------------------------------------------------------                  
          if self.wall[3][0] == (1, 0):       
              pyxel.line(97, 55, 108, 60, 1)
              pyxel.line(97, 95, 108, 90, 1)
              pyxel.line(97, 55, 97, 95, 1)
              pyxel.line(108, 60, 108, 90, 1)    
          if self.wall[3][1] == (1, 0):       
             pyxel.line(158, 55, 148, 60, 1)
             pyxel.line(158, 95, 148, 90, 1)  
             pyxel.line(158, 55, 158, 95, 1)
             pyxel.line(148, 60, 148, 90, 1)      
    #-----------------------------------------------------------------------------      
        
    #Draw Floor paint-------------------------------------------------------------
          if self.floor[0] == 1:
              pyxel.line(67, 145, 178, 130, 8)
              pyxel.line(70, 130, 178, 145, 8)
          if self.floor[1] == 1:
              pyxel.line(95, 117, 155, 107, 8)
              pyxel.line(95, 107, 155, 117, 8)
          if self.floor[2] == 1:
              pyxel.line(110, 104, 140, 97, 1)
              pyxel.line(110, 97, 140, 104, 1)        
          if self.floor[3] == 1:
              pyxel.line(115, 92, 135, 95, 1)
              pyxel.line(115, 95, 135, 92, 1)    
          
    #-----------------------------------------------------------------------------        
    
    #Draw Dead-End----------------------------------------------------------------
          if self.dead_end == 0:
              pass
          elif self.dead_end == 1:
              pyxel.rect(50, 29, 156, 93, 0)
              pyxel.rectb(50, 29, 156, 93, 6)
          elif self.dead_end == 2:
              pyxel.rect(80, 45, 96, 61, 0)
              pyxel.rectb(80, 45, 96, 61, 12)
          elif self.dead_end == 3:
              pyxel.rect(97, 55, 62, 41, 0)
              pyxel.rectb(97, 55, 62, 41, 5)
          elif self.dead_end == 4:
              pyxel.rect(108, 60, 41, 30, 0)
              pyxel.rectb(108, 60, 41, 30, 1)
    #-----------------------------------------------------------------------------     
    
              
          
    #Bubble draw test--------------------------------------------------------------     
          for b in self.bubbles :
              bx = b.bub_x
              by = b.bub_y
              bc = b.bub_c
              bv = b.bub_v
              
              if bv == 0:
                  pyxel.circb(bx, by, 10, bc)
                  pyxel.circb(bx - 5, by - 5, 3, bc)
                  pyxel.circb(bx - 6, by - 6, 1, 7)
              elif bv == 1:     
                  pyxel.circb(bx, by, 7, 6)
                  pyxel.circb(bx - 3, by - 3, 2, bc)
                  pyxel.circb(bx - 4, by - 4, 1, bc)      
              elif bv == 2:
                  pyxel.circb(bx, by, 5, 6)
                  pyxel.circb(bx - 3, by - 1, 1, bc)
                  pyxel.circb(bx - 4, by - 2, 1, bc)      
          
    #------------------------------------------------------------------------------      
    
    #Draw Compass-----------------------------------------------------------------
          pyxel.rect(0, 150, 256, 106, 0)
          pyxel.rectb(0, 150, 256, 106, 1)
          pyxel.rectb(14, 164, 55, 45, 13)   
            
          for d0 in range(5):
              if (self.pos[1]-1 < 0 or 
                  self.pos[0]-2+d0 < 0 or self.pos[0]-2+d0 > 31):
                  pyxel.rect(17+10*d0, 167, 9, 9, 7)
              elif self.maze[self.pos[1]-1][self.pos[0]-2+d0] == (1, 0):
                  pyxel.rect(17+10*d0, 167, 9, 9, 7)
              elif self.maze[self.pos[1]-1][self.pos[0]-2+d0] == (2, 0):
                  pyxel.rect(17+10*d0, 167, 9, 9, 3)              
              elif self.maze[self.pos[1]-1][self.pos[0]-2+d0] == (0, 1):
                  pyxel.rectb(17+10*d0, 167, 9, 9, 8)              
          for d1 in range(5):
              if self.pos[0]-2+d1 < 0 or self.pos[0]-2+d1 > 31:
                  pyxel.rect(17+10*d1, 177, 9, 9, 7)
              elif self.maze[self.pos[1]][self.pos[0]-2+d1] == (1, 0):
                  pyxel.rect(17+10*d1, 177, 9, 9, 7)
              elif self.maze[self.pos[1]][self.pos[0]-2+d1] == (2, 0):
                  pyxel.rect(17+10*d1, 177, 9, 9, 3)              
              elif self.maze[self.pos[1]][self.pos[0]-2+d1] == (0, 1):
                  pyxel.rectb(17+10*d1, 177, 9, 9, 8)              
          for d2 in range(5):
              if (self.pos[1]+1 > 31 or
                  self.pos[0]-2+d2 < 0 or self.pos[0]-2+d2 > 31):
                  pyxel.rect(17+10*d2, 187, 9, 9, 7)
              elif self.maze[self.pos[1]+1][self.pos[0]-2+d2] == (1, 0):
                  pyxel.rect(17+10*d2, 187, 9, 9, 7)
              elif self.maze[self.pos[1]+1][self.pos[0]-2+d2] == (2, 0):
                  pyxel.rect(17+10*d2, 187, 9, 9, 3)              
              elif self.maze[self.pos[1]+1][self.pos[0]-2+d2] == (0, 1):
                  pyxel.rectb(17+10*d2, 187, 9, 9, 8)              
          for d3 in range(5):
              if (self.pos[1]+2 > 31 or
                  self.pos[0]-2+d3 < 0 or self.pos[0]-2+d3 > 31):
                  pyxel.rect(17+10*d3, 197, 9, 9, 7)      
              elif self.maze[self.pos[1]+2][self.pos[0]-2+d3] == (1, 0):
                  pyxel.rect(17+10*d3, 197, 9, 9, 7)              
              elif self.maze[self.pos[1]+2][self.pos[0]-2+d3] == (2, 0):
                  pyxel.rect(17+10*d3, 197, 9, 9, 3)                            
              elif self.maze[self.pos[1]+2][self.pos[0]-2+d3] == (0, 1):
                  pyxel.rectb(17+10*d3, 197, 9, 9, 8)                            
    
                
          if self.pos_angle == 1:
              pyxel.tri(41, 178, 37, 185, 45, 185, 1)
          elif self.pos_angle == 2:
              pyxel.tri(45, 181, 37, 178, 37, 185, 1)
          elif self.pos_angle == 3:
              pyxel.tri(41, 185, 37, 178, 45, 178, 1)
          elif self.pos_angle == 4:
              pyxel.tri(37, 183, 45, 178, 45, 186, 1)
    #-----------------------------------------------------------------------------      

    ▲draw部分です。ここでも泡と床の印について追加しています。

    #Bubble draw test--------------------------------------------------------------     
          for b in self.bubbles :
              bx = b.bub_x
              by = b.bub_y
              bc = b.bub_c
              bv = b.bub_v
              
              if bv == 0:
                  pyxel.circb(bx, by, 10, bc)
                  pyxel.circb(bx - 5, by - 5, 3, bc)
                  pyxel.circb(bx - 6, by - 6, 1, 7)
              elif bv == 1:     
                  pyxel.circb(bx, by, 7, 6)
                  pyxel.circb(bx - 3, by - 3, 2, bc)
                  pyxel.circb(bx - 4, by - 4, 1, bc)      
              elif bv == 2:
                  pyxel.circb(bx, by, 5, 6)
                  pyxel.circb(bx - 3, by - 1, 1, bc)
                  pyxel.circb(bx - 4, by - 2, 1, bc)      
          
    #------------------------------------------------------------------------------    

    ▲泡の描画についてです。bvの値によって大きさを変えています。

    #Draw Floor paint-------------------------------------------------------------
          if self.floor[0] == 1:
              pyxel.line(67, 145, 178, 130, 8)
              pyxel.line(70, 130, 178, 145, 8)
          if self.floor[1] == 1:
              pyxel.line(95, 117, 155, 107, 8)
              pyxel.line(95, 107, 155, 117, 8)
          if self.floor[2] == 1:
              pyxel.line(110, 104, 140, 97, 1)
              pyxel.line(110, 97, 140, 104, 1)        
          if self.floor[3] == 1:
              pyxel.line(115, 92, 135, 95, 1)
              pyxel.line(115, 95, 135, 92, 1)    
          
    #-----------------------------------------------------------------------------      

    ▲床の印部分です。距離によって大きさと色を変えています。

    class Bubble:
      def __init__(self, x, y, v, c, s):
          self.bub_x = x
          self.bub_y = y
          self.bub_v = v
          self.bub_c = c      
          self.bub_s = s
      def update(self):
          self.bub_y -= self.bub_s

    ▲新たに作成したBubbleクラスです。プロパティを設定するコンストラクタとy座標を変更するupdate関数があります。update関数は呼び出されるたびに泡のy座標をbub_sの値だけ引きます。pyxelのy軸は上が0なので、これで泡が上へあがっていく動きを実現します。

    ちょっと見た目が豪華になってきました。次回はスタートとゴールの概念を取り入れてみようと思います。

    コードやpyxresファイル、モジュールファイルはGitHubの方に置いてあります。

    今回はここまで。
    読んでいただきありがとうございました。

    この記事が参加している募集

     
     
    出版社のしがない社内SE。 ここでは主に趣味のプログラミングやゲーム制作について書いています。作ったゲームは https://koidemizu.github.io/ で公開しているのでよかったら遊んでください。 ゲーム大好きインドア派。

    あなたへのおすすめ