見出し画像

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

前回に引き続き、要素を追加していきます。今回は敵を追加して攻撃できるところまでを目標にします。とりあえず敵は一種類でシンプルな形から始めまてみます。以下に前回の記事を貼っておきます。

# -*- 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)

まず、init部分に敵を出現させるための変数やリストを作成します。enemys はリスト型でここに敵のオブジェクトを格納します。enemy_moveは移動制御用、enemy_pos_xとenemy_pos_yは敵の座標です。座標はタイルマップのマス目で指定します。とりあえず今回は1体だけ、(8,10)の位置に出現させてみます。

  def update(self):
      if pyxel.btnp(pyxel.KEY_S):
        self.game_start = True
      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 Hit-check
      self.Hit_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の部分にはまずプレイヤーの攻撃と敵との当たり判定を処理するHit_chk関数を呼び出す処理を追加します。Hit_chk関数については後ほど作成します。
また、map_move == 1の場合、つまりマップ移動時に敵を生成する処理も追加します。self.enemys.clear()で敵をいったん削除し、enemy_x_1とenemy_y_1にそれぞれ値を代入します。その後、len(enemy_x_1)で得られた敵の数だけfor文で処理を回します。今回は1体だけ作成です。Enemy1のクラスを使ってnew_enemy = Enemy1(enemy_x_1[i]*8, enemy_y_1[i]*8)でnew_enemyを作成、self.enemys.append(new_enemy)でenemysの中に格納します。Enemy1クラスについては後で作成しますが、第一引数がx座標、第二引数がy座標です。タイルマップのマス目に8を掛けることで実際の座標に変換します。敵の生成が終わったら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 Enemy   
      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,
                        8,
                        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 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部分にも敵の描画を追加します。len(self.enemys)で敵が何体いるかを取得してforを使って描画しています。enemy_mの値は敵のアニメーション用に作っていますが、現段階では機能していません。

   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

新規作成したHit_chk関数です。プレイヤーの攻撃座標であるself.p_atc_xとself.p_atc_yが敵に当たっているかを判定します。今回追加する敵のサイズは8*8なので判定もそれを反映した形にします。当たった判定がされた場合は敵の体力を1減らし、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()

クラス部分です。今回追加したのはclass Enemy1です。x座標、y座標、体力、ダメージフラグ、移動フラグを保持します。

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

# -*- 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_Q):
          pyxel.quit()
       
      #Player attack           
      if pyxel.btnp(pyxel.KEY_SPACE):
          self.atc_flug = True
          
      #Player controll
      self.Player_ctr()
      #Enemy Hit-check
      self.Hit_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,
                        8,
                        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 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 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
      
  
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

次回はプレイヤーのダメージ判定を追加します。
ここまで読んでいただき、ありがとうございました。

今回使ったイメージソースファイルです。よろしければご利用ください。↓


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