見出し画像

pyxelでRPG風のものを作る(5)

前回までで敵への攻撃とプレイヤーへのダメージ判定が実装できました。今回は敵を動かす処理を実装して、さらにゲームらしくしていきたいと思います。前回の記事を以下に貼っておきますので、よろしければご参照ください。

敵の行動パターンは複雑な方がゲームとしては面白そうですが、最初から無理はせずなるべく簡単に作っていきたいと思います。今回の敵の動きとしては「一定範囲内にプレイヤーが近づいた場合に追いかけていく」ものとします

  def update(self):
     if pyxel.btnp(pyxel.KEY_S):
       self.game_start = True
     if pyxel.btnp(pyxel.KEY_R):
        if self.game_over == True:
           self.Retry()
     if pyxel.btnp(pyxel.KEY_Q):
         pyxel.quit()
      
     #Player attack           
     if pyxel.btnp(pyxel.KEY_SPACE):
         self.atc_flug = True
         
     #Player controll
     self.Player_ctr()
     #Enemy controll
     self.Enemy_ctr()
     #Enemy Hit-check
     self.Hit_chk()
     #Player Damage-check
     self.Dmg_chk()
     
     #Enemy creation
     if self.map_move == 1:
          self.enemys.clear()
          enemy_x_1 = self.enemy_pos_x
          enemy_y_1 = self.enemy_pos_y
          enemy_kazu = len(enemy_x_1)
          for i in range(enemy_kazu):
              new_enemy = Enemy1(enemy_x_1[i]*8, enemy_y_1[i]*8)
              self.enemys.append(new_enemy)
          self.map_move = 0     

update関数に今回新規作成するEnemy_ctr関数を呼び出す処理を追加します。敵の動作はこの関数内で制御します。
加えて、ゲームオーバーになった際にリトライできるようにRキーにリトライ用のRetry関数を呼び出す動作を追加します。

  def draw(self):
     pyxel.cls(0)
     
     #Draw tilemap
     pyxel.bltm(0,0,0,0 + self.map_x,0 + self.map_y,16,16)
 
     #Draw player
     if self.atc_flug == True:
         if self.Player.player_m == 0:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,0,16,8,8,14)
             pyxel.blt(self.Player.player_x+8,self.Player.player_y,
                           0,0,24,8,8,14)
         elif self.Player.player_m == 1:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,8,16,8,8,14)
             pyxel.blt(self.Player.player_x-8,self.Player.player_y,
                           0,8,24,8,8,14)
         elif self.Player.player_m == 2:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,16,16,8,8,14)
             pyxel.blt(self.Player.player_x,self.Player.player_y-8,
                           0,16,24,8,8,14)
         elif self.Player.player_m == 3:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,24,16,8,8,14)  
             pyxel.blt(self.Player.player_x,self.Player.player_y+8,
                           0,24,24,8,8,14)
     else:
         if self.Player.player_m == 0:
                 pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,0,0+self.Player.player_m2*8,8,8,14)
         elif self.Player.player_m == 1:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,8,0+self.Player.player_m2*8,8,8,14)
         elif self.Player.player_m == 2:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,16,0+self.Player.player_m2*8,8,8,14)
         elif self.Player.player_m == 3:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,24,0+self.Player.player_m2*8,8,8,14)
          
     #Draw Enemys
     enemy_count = len(self.enemys)
     for e in range(enemy_count):
         if self.enemys[e].enemy_m == 0:
             pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
                       1,
                       8,0,
                       8,8,14)
         else:
             pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
                       1,
                       8,8,
                       8,8,14)
         if self.enemys[e].enemy_d == 1:
             pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
                       0,40,16,8,8,14)
     #Draw damage
     if self.Player.player_d == 1:
          pyxel.blt(self.Player.player_x,self.Player.player_y,0,32,16,8,8,14)      
          
     #Draw title text
     if self.game_start == False:
        pyxel.cls(0)
        pyxel.text(35, 40, "PYXEL KNIGHTS", 7)
        pyxel.text(45, 70, "S = START ", 7)
        pyxel.text(45, 80, "Q = QUIT ", 7)
     else: #Draw player hp
        pyxel.text(2, 122, "HP="+ str(self.Player.player_h),7)
         
     #Draw gameover text
     if self.game_over == True:
        pyxel.cls(0)
        pyxel.text(20, 30, "GAME OVER!", 7)
        pyxel.text(80, 70, "R = RETRY ", 7)
        pyxel.text(80, 80, "Q = QUIT ", 7)
        

Draw関数です。敵の向きに合わせて、描画を変えるように変更しました。敵の向きはenemy_mで判別しています。

  def Retry(self):
     #Player status
     self.Player = Player(8, 56)
     self.player_move = 0    
     self.atc_flug = False   
     self.atc_count = 0      
     self.p_atc_x = 0        
     self.p_atc_y = 0        
     
     #Map status
     self.stage_flug = 1     
     self.map_count_x = 1    
     self.map_count_y = 1    
     self.map_x = 0
     self.map_y = 0
     self.map_move = 0
     
     #Enemy status
     self.enemys = []
     self.enemy_move = 0
     
     #System status
     self.game_start = False 
     self.game_over = False 

Retry関数です。ゲームリトライのために変数を初期化しています。ゲームオーバー時にRキーで呼び出されます。

  def Enemy_ctr(self):        
     self.enemy_move = self.enemy_move + 1
     enemy_count = len(self.enemys)
     if self.enemy_move > 40:
         for e in range(enemy_count):
             enemy_pos_x = int(self.enemys[e].enemy_x / 8 + self.map_x)
             enemy_pos_y = int(self.enemys[e].enemy_y / 8 + self.map_y)
             enemy_pos_x2 = self.Player.player_x - self.enemys[e].enemy_x
             enemy_pos_y2 = self.Player.player_y - self.enemys[e].enemy_y
             #Check tilemap
             if (abs(enemy_pos_x2) < 35 and abs(enemy_pos_y2) < 35):
                 if abs(enemy_pos_x2) > abs(enemy_pos_y2):
                     #Move right
                     if enemy_pos_x2 > 0:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x+1, 
                                  enemy_pos_y)) < 32):
                             self.enemys[e].enemy_x=self.enemys[e].enemy_x+8
                             self.enemys[e].enemy_m = 1
                     #Move left
                     else:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x-1, 
                                  enemy_pos_y)) < 32):
                             self.enemys[e].enemy_x=self.enemys[e].enemy_x-8
                             self.enemys[e].enemy_m = 0           
                 else:
                     #Move down
                     if enemy_pos_y2 > 0:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x, 
                                  enemy_pos_y+1)) < 32):
                             self.enemys[e].enemy_y=self.enemys[e].enemy_y+8
                     #Move up
                     else:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x, 
                                  enemy_pos_y-1)) < 32):
                             self.enemys[e].enemy_y=self.enemys[e].enemy_y-8
         self.enemy_move = 0

Enemy_ctr関数です。敵の動作を制御します。enemy_moveを毎フレームごとにカウントアップしていって40に達したら敵を動かします。
enemy_pos_xとenemy_pos_yにタイルマップで敵自身が今どのマスにいるのかの情報を入れます。これは、敵が移動不可のタイルに入らないようにするために使います。
enemy_pos_x2とenemy_pos_y2は敵とプレイヤーとの座標の差を入れる変数です。これを使って敵を上下に動かすか左右に動かすか判断させます。
if (abs(enemy_pos_x2) < 35 and abs(enemy_pos_y2) < 35):の条件文は敵とプレイヤーの距離が35以下の場合にTrueになります。この距離が敵の認知距離になります。敵がプレイヤーを認知した場合はenemy_pos_x2とenemy_pos_y2の値を比較して上下か左右に移動方向を決めます。その後は上下の場合はenemy_pos_y2が正の値なら下、負の値なら上に、左右の場合はenemy_pos_x2が正の値なら右、負の値なら左に移動させます。移動の向きによってenemy_mの値を変化させて描画時に参照するようにします。

全てつなげたソースは以下の通りです。

# -*- coding: utf-8 -*-

import pyxel

class App:
 def __init__(self):
     
     #Player status
     self.Player = Player(8, 56)
     self.player_move = 0    
     self.atc_flug = False   
     self.atc_count = 0      
     self.p_atc_x = 0        
     self.p_atc_y = 0        
     
     #Map status
     self.stage_flug = 1     
     self.map_count_x = 1    
     self.map_count_y = 1    
     self.map_x = 0
     self.map_y = 0
     self.map_move = 0
     
     #Enemy status
     self.enemys = []
     self.enemy_move = 0
     self.enemy_pos_x = [8]
     self.enemy_pos_y = [10]
     
     #System status
     self.game_start = False 
     self.game_over = False 
     
     pyxel.init(128,128)

     #Image read
     pyxel.load('C:/pyxel/image/pknights.pyxres')
     
     pyxel.run(self.update, self.draw)
     
 def update(self):
     if pyxel.btnp(pyxel.KEY_S):
       self.game_start = True
     if pyxel.btnp(pyxel.KEY_R):
       self.Retry()
     if pyxel.btnp(pyxel.KEY_Q):
         pyxel.quit()
      
     #Player attack           
     if pyxel.btnp(pyxel.KEY_SPACE):
         self.atc_flug = True
         
     #Player controll
     self.Player_ctr()
     #Enemy controll
     self.Enemy_ctr()
     #Enemy Hit-check
     self.Hit_chk()
     #Player Damage-check
     self.Dmg_chk()
     
     #Enemy creation
     if self.map_move == 1:
          self.enemys.clear()
          enemy_x_1 = self.enemy_pos_x
          enemy_y_1 = self.enemy_pos_y
          enemy_kazu = len(enemy_x_1)
          for i in range(enemy_kazu):
              new_enemy = Enemy1(enemy_x_1[i]*8, enemy_y_1[i]*8)
              self.enemys.append(new_enemy)
          self.map_move = 0     
      
 def draw(self):
     pyxel.cls(0)
     
     #Draw tilemap
     pyxel.bltm(0,0,0,0 + self.map_x,0 + self.map_y,16,16)
 
     #Draw player
     if self.atc_flug == True:
         if self.Player.player_m == 0:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,0,16,8,8,14)
             pyxel.blt(self.Player.player_x+8,self.Player.player_y,
                           0,0,24,8,8,14)
         elif self.Player.player_m == 1:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,8,16,8,8,14)
             pyxel.blt(self.Player.player_x-8,self.Player.player_y,
                           0,8,24,8,8,14)
         elif self.Player.player_m == 2:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,16,16,8,8,14)
             pyxel.blt(self.Player.player_x,self.Player.player_y-8,
                           0,16,24,8,8,14)
         elif self.Player.player_m == 3:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,24,16,8,8,14)  
             pyxel.blt(self.Player.player_x,self.Player.player_y+8,
                           0,24,24,8,8,14)
     else:
         if self.Player.player_m == 0:
                 pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,0,0+self.Player.player_m2*8,8,8,14)
         elif self.Player.player_m == 1:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,8,0+self.Player.player_m2*8,8,8,14)
         elif self.Player.player_m == 2:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,16,0+self.Player.player_m2*8,8,8,14)
         elif self.Player.player_m == 3:
             pyxel.blt(self.Player.player_x,self.Player.player_y,
                           0,24,0+self.Player.player_m2*8,8,8,14)
          
     #Draw Enemys
     enemy_count = len(self.enemys)
     for e in range(enemy_count):
         if self.enemys[e].enemy_m == 0:
             pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
                       1,
                       8,0,
                       8,8,14)
         else:
             pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
                       1,
                       8,8,
                       8,8,14)
         if self.enemys[e].enemy_d == 1:
             pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
                       0,40,16,8,8,14)
     #Draw damage
     if self.Player.player_d == 1:
          pyxel.blt(self.Player.player_x,self.Player.player_y,0,32,16,8,8,14)      
          
     #Draw title text
     if self.game_start == False:
        pyxel.cls(0)
        pyxel.text(35, 40, "PYXEL KNIGHTS", 7)
        pyxel.text(45, 70, "S = START ", 7)
        pyxel.text(45, 80, "Q = QUIT ", 7)
     else: #Draw player hp
        pyxel.text(2, 122, "HP="+ str(self.Player.player_h),7)
         
     #Draw gameover text
     if self.game_over == True:
        pyxel.cls(0)
        pyxel.text(20, 30, "GAME OVER!", 7)
        pyxel.text(80, 70, "R = RETRY ", 7)
        pyxel.text(80, 80, "Q = QUIT ", 7)
        

 
 def Player_ctr(self):
     
     #Get map coordinate
     x = 16*(self.map_count_x-1)
     y = 16*(self.map_count_y-1)

     #Get player coordinate        
     move_map_x = int(self.Player.player_x / 8 + x)
     move_map_y = int(self.Player.player_y / 8 + y)
     
     #Plyer move
     self.player_move = self.player_move + 1
     if self.player_move > 6:
     
         if pyxel.tilemap(0).get(move_map_x, move_map_y-1) < 32:
             #Up
             if pyxel.btnp(pyxel.KEY_UP):
                 self.Player.player_y = self.Player.player_y - 8
                 self.player_move = 0
                 self.Player.player_m = 2
                 if self.Player.player_m2 == 0: #Move animation
                     self.Player.player_m2 = 1
                 else:
                     self.Player.player_m2 = 0      
                 if (self.Player.player_y - 8) < 0: #When map change
                     self.map_y = self.map_y - 16
                     self.Player.update(56, 120)
                     self.map_count_y = self.map_count_y - 1
                     self.map_move = 1
     
         if pyxel.tilemap(0).get(move_map_x, move_map_y+1) < 32:
             #Down
             if pyxel.btnp(pyxel.KEY_DOWN):
                 self.Player.player_y = self.Player.player_y + 8
                 self.player_move = 0
                 self.Player.player_m = 3     
                 if self.Player.player_m2 == 0: #Move animation
                     self.Player.player_m2 = 1
                 else:
                     self.Player.player_m2 = 0      
                 if (self.Player.player_y + 8) > 128: #When map change
                     self.map_y = self.map_y + 16
                     self.Player.update(56, 8)
                     self.map_count_y = self.map_count_y + 1
                     self.map_move = 1
             
         if pyxel.tilemap(0).get(move_map_x+1, move_map_y) < 32: 
             #Right
             if pyxel.btnp(pyxel.KEY_RIGHT):
                 self.Player.player_x = self.Player.player_x + 8
                 self.player_move = 0
                 self.Player.player_m = 0
                 if self.Player.player_m2 == 0: #Move animation
                     self.Player.player_m2 = 1
                 else:
                     self.Player.player_m2 = 0      
                 if (self.Player.player_x + 8) > 128: #When map change
                     self.map_x = self.map_x + 16
                     self.Player.update(8, 56)
                     self.map_count_x = self.map_count_x + 1
                     self.map_move = 1
     
         if pyxel.tilemap(0).get(move_map_x-1, move_map_y) < 32: 
             #Left
             if pyxel.btnp(pyxel.KEY_LEFT):
                 self.Player.player_x = self.Player.player_x - 8
                 self.player_move = 0
                 if self.Player.player_m2 == 0: #Move animation
                     self.Player.player_m2 = 1
                 else:
                     self.Player.player_m2 = 0      
                 self.Player.player_m = 1
                 if (self.Player.player_x - 8) < 0: #When map change
                     self.map_x = self.map_x - 16
                     self.Player.update(120, 56)
                     self.map_count_x = self.map_count_x - 1
                     self.map_move = 1
            
     #Attack action
     if self.atc_flug == True:
         self.atc_count = self.atc_count + 1
         if self.atc_count > 8:
             self.atc_count = 0
             self.p_atc_x = 0
             self.p_atc_y = 0
             self.atc_flug = False
         else:
             if self.Player.player_m == 0:
                 self.p_atc_x = self.Player.player_x + 8
                 self.p_atc_y = self.Player.player_y
             elif self.Player.player_m == 1:
                 self.p_atc_x = self.Player.player_x - 8
                 self.p_atc_y = self.Player.player_y
             elif self.Player.player_m == 2:
                 self.p_atc_x = self.Player.player_x
                 self.p_atc_y = self.Player.player_y - 8
             elif self.Player.player_m == 3:
                 self.p_atc_x = self.Player.player_x
                 self.p_atc_y = self.Player.player_y + 8
       
 def Retry(self):
     #Player status
     self.Player = Player(8, 56)
     self.player_move = 0    
     self.atc_flug = False   
     self.atc_count = 0      
     self.p_atc_x = 0        
     self.p_atc_y = 0        
     
     #Map status
     self.stage_flug = 1     
     self.map_count_x = 1    
     self.map_count_y = 1    
     self.map_x = 0
     self.map_y = 0
     self.map_move = 0
     
     #Enemy status
     self.enemys = []
     self.enemy_move = 0
     
     #System status
     self.game_start = False 
     self.game_over = False 
             
 def Hit_chk(self):
     enemy_count = len(self.enemys)
     for e in range(enemy_count):
         self.enemys[e].enemy_d = 0
         enemy_pos_x = self.enemys[e].enemy_x
         enemy_pos_y = self.enemys[e].enemy_y
         if ((enemy_pos_x <= self.p_atc_x < enemy_pos_x + 8) and
             (enemy_pos_y <= self.p_atc_y < enemy_pos_y + 8)):
             self.enemys[e].enemy_d = 1
             self.enemys[e].enemy_h = self.enemys[e].enemy_h -1
             #Enemy delete
             if self.enemys[e].enemy_h < 0:
                 del self.enemys[e]
                 break
     
 def Dmg_chk(self):     
      self.Player.player_d = 0
      enemy_count = len(self.enemys)  
      player_pos_x = self.Player.player_x
      player_pos_y = self.Player.player_y
      for e in range(enemy_count):
          enemy_pos_x = self.enemys[e].enemy_x
          enemy_pos_y = self.enemys[e].enemy_y
          if ((enemy_pos_x <= player_pos_x < enemy_pos_x + 8) and
             (enemy_pos_y <= player_pos_y < enemy_pos_y + 8)):
              self.Player.player_h = self.Player.player_h - 1
              self.Player.player_d = 1
              if self.Player.player_h <= 0:
                  self.game_over = True     
     

 def Enemy_ctr(self):        
     self.enemy_move = self.enemy_move + 1
     enemy_count = len(self.enemys)
     if self.enemy_move > 40:
         for e in range(enemy_count):
             enemy_pos_x = int(self.enemys[e].enemy_x / 8 + self.map_x)
             enemy_pos_y = int(self.enemys[e].enemy_y / 8 + self.map_y)
             enemy_pos_x2 = self.Player.player_x - self.enemys[e].enemy_x
             enemy_pos_y2 = self.Player.player_y - self.enemys[e].enemy_y
             #Check tilemap
             if (abs(enemy_pos_x2) < 35 and abs(enemy_pos_y2) < 35):
                 if abs(enemy_pos_x2) > abs(enemy_pos_y2):
                     #Move right
                     if enemy_pos_x2 > 0:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x+1, 
                                  enemy_pos_y)) < 32):
                             self.enemys[e].enemy_x=self.enemys[e].enemy_x+8
                             self.enemys[e].enemy_m = 1
                     #Move left
                     else:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x-1, 
                                  enemy_pos_y)) < 32):
                             self.enemys[e].enemy_x=self.enemys[e].enemy_x-8
                             self.enemys[e].enemy_m = 0           
                 else:
                     #Move down
                     if enemy_pos_y2 > 0:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x, 
                                  enemy_pos_y+1)) < 32):
                             self.enemys[e].enemy_y=self.enemys[e].enemy_y+8
                     #Move up
                     else:
                         if (40> (pyxel.tilemap(0).get(enemy_pos_x, 
                                  enemy_pos_y-1)) < 32):
                             self.enemys[e].enemy_y=self.enemys[e].enemy_y-8
         self.enemy_move = 0
           
class Player:
 def __init__(self, x, y):
     self.player_x = x
     self.player_y = y
     self.player_h = 100
     self.player_d = 0
     self.player_m = 0
     self.player_m2 = 0
 def update(self, x, y):
     self.player_x = x
     self.player_y = y
     
class Enemy1:
  def __init__(self, x, y):
      self.enemy_x = x
      self.enemy_y = y
      self.enemy_h = 15
      self.enemy_d = 0
      self.enemy_m = 0
  def update(self, x, y):
      self.enemy_x = x
      self.enemy_y = y
     
 
App()

敵も動くようになって結構ゲームらしくなってきた気がします。ただ、今のところ敵の出現位置が1パターンしかないので、次回はタイルマップごとに敵を場所を調整できるようにしていきたいと思います。

画像1


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