見出し画像

【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と泡の描写に関するbubblesbub_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の方に置いてあります。

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

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

ここまで読んでいただきありがとうございます!