RPGやシューティングなど、どんなタイプのゲームにも使用することができるHPバーを作成します。
基本的なHPバー
複数のRectを重ねて、バーを作成します。
白い四角形に、一回り小さい黒い四角形を重ねることで、枠を表現します。
そこに青色のバーを重ね、HPバーの見た目を表すことができますね。
ソースコードは、以下のようになります。
import pygame
from pygame.locals import *
class HealthBar():
def __init__(self, x, y, width, max):
self.x = x
self.y = y
self.width = width
self.max = max # 最大HP
self.hp = max # HP
self.mark = int((self.width - 4) / self.max) # HPバーの1目盛り
self.font = pygame.font.SysFont(None, 28)
self.label = self.font.render("HP", True, (255, 255, 255))
self.frame = Rect(self.x + 2 + self.label.get_width(), self.y, self.width, self.label.get_height())
self.bar = Rect(self.x + 4 + self.label.get_width(), self.y + 2, self.width - 4, self.label.get_height() - 4)
self.value = Rect(self.x + 4 + self.label.get_width(), self.y + 2, self.width - 4, self.label.get_height() - 4)
def update(self):
self.value.width = self.hp * self.mark
def draw(self, screen):
pygame.draw.rect(screen, (255, 255, 255), self.frame)
pygame.draw.rect(screen, (0, 0, 0), self.bar)
pygame.draw.rect(screen, (0, 0, 255), self.value)
screen.blit(self.label, (self.x, self.y))
コンストラクタで、それぞれのRectを作成します。
ついでに「HP」というラベルも作成し、そのレベルの高さと同じ高さのフレームを作成します。
バーの長さは、コンストラクタの引数として渡すwidthと同じ長さになるようにしています(「HP」ラベルの長さは含まず)。
maxは、最大HPの値です。
動きのあるHPバー
このままでも最低限の機能はありますが、もう少し動きがあるとだいぶそれっぽくなります。
HPバーの残り具合によって、バーの色も変えるようにします。
import pygame
from pygame.locals import *
class HealthBar():
def __init__(self, x, y, width, max):
self.x = x
self.y = y
self.width = width
self.max = max # 最大HP
self.hp = max # HP
self.mark = int((self.width - 4) / self.max) # HPバーの1目盛り
self.font = pygame.font.SysFont(None, 28)
self.label = self.font.render("HP", True, (255, 255, 255))
self.frame = Rect(self.x + 2 + self.label.get_width(), self.y, self.width, self.label.get_height())
self.bar = Rect(self.x + 4 + self.label.get_width(), self.y + 2, self.width - 4, self.label.get_height() - 4)
self.value = Rect(self.x + 4 + self.label.get_width(), self.y + 2, self.width - 4, self.label.get_height() - 4)
# effect_barを追加
self.effect_bar = Rect(self.x + 4 + self.label.get_width(), self.y + 2, self.width - 4, self.label.get_height() - 4)
self.effect_color = (0, 255, 255)
def update(self):
if self.hp >= self.max:
self.hp = self.max
if self.effect_bar.width > self.mark * self.hp:
self.value.width = self.mark * self.hp
if self.effect_bar.width >= self.value.width:
self.effect_bar.inflate_ip(-1, 0)
elif self.value.width < self.mark * self.hp:
self.effect_bar.width = self.mark * self.hp
self.value.inflate_ip(1, 0)
# effect_barの色を変える
if self.effect_bar.width <= self.bar.width / 6:
self.effect_color = (255, 255, 0)
elif self.effect_bar.width <= self.bar.width / 2:
self.effect_color = (255, 255, 0)
else:
self.effect_color = (0, 255, 0)
def draw(self, screen):
pygame.draw.rect(screen, (255, 255, 255), self.frame)
pygame.draw.rect(screen, (0, 0, 0), self.bar)
pygame.draw.rect(screen, self.effect_color, self.effect_bar)
pygame.draw.rect(screen, (0, 0, 255), self.value)
screen.blit(self.label, (self.x, self.y))
update()内でinflate_ip()を使うことで、徐々に減ったり増えたりさせることができます。
さらに、HPが半分以下になるとバーは黄色になり、6分の1以下になると赤になります。
これで、HPバーとしては十分なものになりました。
HPバーの使い方
HPバーはMainクラス内でインスタンス化して使用します。
collision_detection()内でプレイヤーと敵の当たり判定を行い、衝突があればhpを-1します。
def __init__(self);
# HPバーのインスタンス化
self.hp = bar.HealthBar(32, 32, 100, 12) # maxの値はwidth-4を割り切れる数にする
(省略)
def collision_detection(self):
enemy_collided = pygame.sprite.spritecollide(self.player, self.enemies, False)
if enemy_collided:
# プレイヤーが無敵でないなら、HPを-1する
if self.player.invincible == False:
self.hp.hp -= 1
self.player.invincible = True
self.player.invincibleという見慣れない属性がありますが、これはプレイヤークラスに新しく追加した属性になります。
これを追加しないと、当たり判定はupdate()のたびに呼び出されるので、あっという間にhpがゼロになってしまいます。
当たりを検出してダメージを受けたら、一定時間無敵時間を設けるようにします。
class Player(pygame.sprite.Sprite):
speed = 5
frame = 0
animecycle = 24
# 無敵時間の設定
invincible_time = 64
def __init__(self, pos):
(省略)
# 無敵かどうか
self.invincible = False
def update(self):
(省略)
# 無敵状態なら無敵時間を減らす
if self.invincible == True:
if self.invincible_time == 0:
self.invincible = False
self.invincible_time = Player.invincible_time
else:
self.invincible_time -= 1
プレイヤークラスに無敵状態かどうかを判定するself.invincibleを定義し、Trueであれば無敵時間を減らすという処理を書いています。
これで、連続で当たり判定が呼び出されてしまうことを防ぎます。
HPが減る一方だと味気ないので、Mainクラスのkey_handler()でスペースキーを押すとHPが回復するようにします。
def key_handler(self):
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN and event.key == K_SPACE:
self.hp.hp += 1
もはやこれだけでもシューティングゲームといっていいくらいのクオリティになってきましたね!