Reputation: 117
By the title, I'm hoping that my the player would have a health bar attached to their head. If they move, the health bar also moves. Say sprite is my player. Hey sprite! He has a health bar on top of his head and yeah thats it. To be honest, I don't really know where to start, so help would be appreciated. Thanks!
P.S. A big thanks to Rabbid76 for his help! Also to Ann Zen! Code:
import pygame
import os
import random
import math
import winsound
# winsound.PlaySound("explosion.wav", winsound.SND_ALIAS)
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (0, 30)
wn = pygame.display.set_mode((1920, 1020))
clock = pygame.time.Clock()
icon = pygame.image.load('Icon.png')
pygame.image.load('Sprite0.png')
pygame.image.load('Sprite0.png')
pygame.display.set_icon(icon)
pygame.display.set_caption('DeMass.io')
vel = 5
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
z = random.randint(0, 101)
if z <= 51:
self.original_image = pygame.image.load('Sprite0.png')
else:
self.original_image = pygame.image.load('Sprite3.png')
if z == 41:
self.original_image = pygame.image.load('Sprite5.png')
self.image = self.original_image
self.rect = self.image.get_rect(center=(x, y))
self.direction = pygame.math.Vector2((0, -1))
self.velocity = 5
self.position = pygame.math.Vector2(x, y)
self.x = pygame.math.Vector2(x)
self.y = pygame.math.Vector2(y)
self.health = 10
self.visible = True
def point_at(self, x, y):
self.direction = pygame.math.Vector2(x, y) - self.rect.center
if self.direction.length() > 0:
self.direction = self.direction.normalize()
angle = self.direction.angle_to((0, -1))
self.image = pygame.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect(center=self.rect.center)
def move(self, x, y):
self.position -= self.direction * y * self.velocity
self.position += pygame.math.Vector2(-self.direction.y, self.direction.x) * x * self.velocity
self.rect.center = round(self.position.x), round(self.position.y)
def reflect(self, NV):
self.direction = self.direction.reflect(pygame.math.Vector2(NV))
def update(self):
self.position += self.direction * self.velocity
self.rect.center = round(self.position.x), round(self.position.y)
def hit(self, player):
if self.health > 0:
self.health -= 1
else:
self.visible = False
distance = math.sqrt(math.pow(player.x - player.x(), 2) + math.pow(player.y - player.y(), 2))
if distance < 20:
return True
else:
return False
def move(self, x, y, clamp_rect):
self.position -= self.direction * y * self.velocity
self.position += pygame.math.Vector2(-self.direction.y, self.direction.x) * x * self.velocity
self.rect.center = round(self.position.x), round(self.position.y)
if self.rect.left < clamp_rect.left:
self.rect.left = clamp_rect.left
self.position.x = self.rect.centerx
if self.rect.right > clamp_rect.right:
self.rect.right = clamp_rect.right
self.position.x = self.rect.centerx
if self.rect.top < clamp_rect.top:
self.rect.top = clamp_rect.top
self.position.y = self.rect.centery
if self.rect.bottom > clamp_rect.bottom:
self.rect.bottom = clamp_rect.bottom
self.position.y = self.rect.centery
class Projectile(object):
def __init__(self, x, y, radius, color, facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.vel = 8 * facing
def draw(self, win):
pygame.draw.circle(win, self.color, (self.x, self.y), self.radius)
player = Player(200, 200)
all_sprites = pygame.sprite.Group(player)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEMOTION:
player.point_at(*event.pos)
pygame.draw.rect(wn, (0, 0, 0), (50, 50, 10000, 100000))
keys = pygame.key.get_pressed()
if keys[pygame.K_w] or keys[pygame.K_UP]:
player.move(0, -1, wn.get_rect())
wn.fill((255, 255, 255))
all_sprites.draw(wn)
pygame.display.update()
Upvotes: 3
Views: 2491
Reputation: 210978
See haw to draw a bar in How can I display a smooth loading bar in pygame?. Create a function that draws a health bar:
def draw_health_bar(surf, pos, size, borderC, backC, healthC, progress):
pygame.draw.rect(surf, backC, (*pos, *size))
pygame.draw.rect(surf, borderC, (*pos, *size), 1)
innerPos = (pos[0]+1, pos[1]+1)
innerSize = ((size[0]-2) * progress, size[1]-2)
rect = (round(innerPos[0]), round(innerPos[1]), round(innerSize[0]), round(innerSize[1]))
pygame.draw.rect(surf, healthC, rect)
Add a method draw_health
to the class Player
and use the function draw_health_bar
:
class Player(pygame.sprite.Sprite):
# [...]
def draw_health(self, surf):
health_rect = pygame.Rect(0, 0, self.original_image.get_width(), 7)
health_rect.midbottom = self.rect.centerx, self.rect.top
max_health = 10
draw_health_bar(surf, health_rect.topleft, health_rect.size,
(0, 0, 0), (255, 0, 0), (0, 255, 0), self.health/max_health)
Call the method in the main application loop:
while run:
# [...]
wn.fill((255, 255, 255))
all_sprites.draw(wn)
player.draw_health(wn) # <---
pygame.display.update()
See also Sprite.
Minimal example:
repl.it/@Rabbid76/PyGame-HealthBar
import pygame
import math
def draw_health_bar(surf, pos, size, borderC, backC, healthC, progress):
pygame.draw.rect(surf, backC, (*pos, *size))
pygame.draw.rect(surf, borderC, (*pos, *size), 1)
innerPos = (pos[0]+1, pos[1]+1)
innerSize = ((size[0]-2) * progress, size[1]-2)
rect = (round(innerPos[0]), round(innerPos[1]), round(innerSize[0]), round(innerSize[1]))
pygame.draw.rect(surf, healthC, rect)
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.original_image = pygame.image.load('CarBlue64.png')
self.original_image = pygame.transform.rotate(self.original_image, 90)
self.image = self.original_image
self.rect = self.image.get_rect(center=(x, y))
self.direction = pygame.math.Vector2((0, -1))
self.velocity = 5
self.position = pygame.math.Vector2(x, y)
self.health = 10
def point_at(self, x, y):
self.direction = pygame.math.Vector2(x, y) - self.rect.center
if self.direction.length() > 0:
self.direction = self.direction.normalize()
angle = self.direction.angle_to((0, -1))
self.image = pygame.transform.rotate(self.original_image, angle)
self.rect = self.image.get_rect(center=self.rect.center)
def move(self, x, y, clamp_rect):
self.position -= self.direction * y * self.velocity
self.position += pygame.math.Vector2(-self.direction.y, self.direction.x) * x * self.velocity
self.rect.center = round(self.position.x), round(self.position.y)
test_rect = self.rect.clamp(clamp_rect)
if test_rect.x != self.rect.x:
self.rect.x = test_rect.x
self.position.x = self.rect.centerx
self.health = max(0, self.health - 1)
if test_rect.y != self.rect.y:
self.rect.y = test_rect.y
self.position.y = self.rect.centery
self.health = max(0, self.health - 1)
def draw_health(self, surf):
health_rect = pygame.Rect(0, 0, self.original_image.get_width(), 7)
health_rect.midbottom = self.rect.centerx, self.rect.top
max_health = 10
draw_health_bar(surf, health_rect.topleft, health_rect.size,
(0, 0, 0), (255, 0, 0), (0, 255, 0), self.health/max_health)
window = pygame.display.set_mode((250, 250))
clock = pygame.time.Clock()
player = Player(200, 200)
all_sprites = pygame.sprite.Group(player)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEMOTION:
player.point_at(*event.pos)
keys = pygame.key.get_pressed()
mouse_buttons = pygame.mouse.get_pressed()
if any(keys) or any(mouse_buttons):
player.move(0, -1, window.get_rect())
window.fill((127, 127, 127))
pygame.draw.rect(window, (255, 0, 0), window.get_rect(), 3)
all_sprites.draw(window)
player.draw_health(window)
pygame.display.update()
pygame.quit()
exit()
Upvotes: 2
Reputation: 31
Rabbid's answer worked for me, however I am using Python 3.8.2 and continually got deprication errors as well as compilation errors when trying to output an .exe. The progress
variable is a float and results in this error:
pygame.draw.rect(surf, healthC, (*innerPos, *innerSize))
DeprecationWarning: an integer is required (got type float). Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
Multiplication by the variable progress
in the function draw_health_bar
needs to be raised to an int
to get away from that. It doesn't seem to affect the visual appearance of the health bar at all. This is the culprit line updated with the int
.
innerSize = (int((size[0]-2) * progress), size[1]-2)
Full updated code below. I prefer complete names for things so as not to confuse myself what variables mean, so I've done that, but everything else is the same except for the int
I added.
def draw_health_bar(surface, position, size, color_border, color_background, color_health, progress):
pygame.draw.rect(surface, color_background, (*position, *size))
pygame.draw.rect(surface, color_border, (*position, *size), 1)
innerPos = (position[0]+1, position[1]+1)
innerSize = (int((size[0]-2) * progress), size[1]-2)
pygame.draw.rect(surface, color_health, (*innerPos, *innerSize))
Sorry if this posting this breaks StackOverflow's rules. First time posting and I thought this was helpful info to newbs like me who try this code out.
Upvotes: 3