当前位置:网站首页>Space shooting lesson 14: player life
Space shooting lesson 14: player life
2022-07-28 20:50:00 【acktomas】
Space shooting No 14 course : Player life
This is us. “Shmup” Project No 11 part . If you haven't read through the previous section , Please from The first 1 part Start . In this lesson , We will add multiple health points to players , And add a beautiful explosion when the player dies .
video
You can watch the video of this course here :
Player explosion
We will use different explosion animations to represent the death of players , From the same Kenny Game Art package , be called “ Sonic explosion ”.
Click here Download the compressed package of these images .
We just need to load these frameworks , Just like we did for other explosions . We just need to add another one named 'player' Explosion type and load it into the same loop , Because it has the same number of frames as the other explosions we are loading . Now our loading code will be as follows :
explosion_anim = {
}
explosion_anim['lg'] = []
explosion_anim['sm'] = []
explosion_anim['player'] = []
for i in range(9):
filename = 'regularExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
img_lg = pygame.transform.scale(img, (75, 75))
explosion_anim['lg'].append(img_lg)
img_sm = pygame.transform.scale(img, (32, 32))
explosion_anim['sm'].append(img_sm)
filename = 'sonicExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
explosion_anim['player'].append(img)
We don't need to be in Explosion Change anything in the sprite class , So we just need to create a player blast when the player's shield runs out . We can add this to the game loop , In this cycle , We will check the collision between players and meteors :
# check to see if a mob hit the player
hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)
for hit in hits:
player.shield -= hit.radius * 2
expl = Explosion(hit.rect.center, 'sm')
all_sprites.add(expl)
newmob()
if player.shield <= 0:
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
running = False
however , If you run the program , You will find that we have a problem now : When the player dies , We set up running by False Game over , Then we have a chance to see our beautiful explosion !
To solve this problem , We need not to end the game until the explosion is over . therefore , We delete players , But it will not be set before the explosion disappears running:
if player.shield <= 0:
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
player.kill()
# if the player died and the explosion has finished playing
if not player.alive() and not death_explosion.alive():
running = False
alive() Function only returns whether a particular sub picture is active . Because when it finishes the game kill() The explosion , We can now end the game when the explosion is complete .
life
Now we want to give players multiple lives . We can use variables to track it , But we also hope to display it on the screen . Instead of just displaying a number , It's better to use the smaller image of the player's ship to indicate how many lives are left , This will look better . First , We will create smaller images :
player_img = pygame.image.load(path.join(img_dir, "playerShip1_orange.png")).convert()
player_mini_img = pygame.transform.scale(player_img, (25, 19))
player_mini_img.set_colorkey(BLACK)
Now? , We will report to the Player Class to add some new parameters ,__init__(): A life counter , A sign ( It can be True or False The variable of ) To hide / Show players , And a timer to control how long we keep players hidden :
self.lives = 3
self.hidden = False
self.hide_timer = pygame.time.get_ticks()
Now? , When the player dies , We will hide players from Subtract from 1, Instead of using kill() . We will lives reduce 1, Reset the shield for new life :
if player.shield <= 0:
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
player.hide()
player.lives -= 1
player.shield = 100
# if the player died and the explosion has finished playing
if player.lives == 0 and not death_explosion.alive():
running = False
Next , We need to define how to hide players . go back to Player() class , We will add a hidden method , This method marks hidden Set to True And start the timer . We also need to make sure that when players hide , It won't be hit by meteors . We have several ways to do this , But one does not need to be added from the Group / The simple way to delete and so on is to temporarily move the player out of the bottom of the screen :
def hide(self):
# hide the player temporarily
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.rect.center = (WIDTH / 2, HEIGHT + 200)
In the player's update() In the method , We need enough time to unhide ( We are now using 1 second ):
def update(self):
# unhide if hidden
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
self.hidden = False
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 10
The life counter shows
To show life , We will create one similar to ours draw_shield_bar() function , It will allow us to place the life counter in a given location :
def draw_lives(surf, x, y, lives, img):
for i in range(lives):
img_rect = img.get_rect()
img_rect.x = x + 30 * i
img_rect.y = y
surf.blit(img, img_rect)
We just cycle ' Number of lives ' Time , Then interval each image 30 Pixels (player_mini_img Width is 25 Pixels , Therefore, a small space will be left between them ).
then , In the game cycle draw Partially add calls to this function :
draw_lives(screen, WIDTH - 100, 5, player.lives,
player_mini_img)
Now we can see the final result :[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-VTtA1UTt-1658991354598)(http://kidscancode.org/blog/img/shmup_part11_1.gif)]
In the next lesson , We will add some props to the game .
The complete code of this part
# KidsCanCode - Game Development with Pygame video series
# Shmup game - part 11
# Video link: https://www.youtube.com/watch?v=G5-4nV6LxgU
# Explosions
# Frozen Jam by tgfcoder <https://twitter.com/tgfcoder> licensed under CC-BY-3
# Art from Kenney.nl
import pygame
import random
from os import path
img_dir = path.join(path.dirname(__file__), 'img')
snd_dir = path.join(path.dirname(__file__), 'snd')
WIDTH = 480
HEIGHT = 600
FPS = 60
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# initialize pygame and create window
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shmup!")
clock = pygame.time.Clock()
font_name = pygame.font.match_font('arial')
def draw_text(surf, text, size, x, y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, WHITE)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
def newmob():
m = Mob()
all_sprites.add(m)
mobs.add(m)
def draw_shield_bar(surf, x, y, pct):
if pct < 0:
pct = 0
BAR_LENGTH = 100
BAR_HEIGHT = 10
fill = (pct / 100) * BAR_LENGTH
outline_rect = pygame.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
fill_rect = pygame.Rect(x, y, fill, BAR_HEIGHT)
pygame.draw.rect(surf, GREEN, fill_rect)
pygame.draw.rect(surf, WHITE, outline_rect, 2)
def draw_lives(surf, x, y, lives, img):
for i in range(lives):
img_rect = img.get_rect()
img_rect.x = x + 30 * i
img_rect.y = y
surf.blit(img, img_rect)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.transform.scale(player_img, (50, 38))
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.radius = 20
# pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
self.shield = 100
self.shoot_delay = 250
self.last_shot = pygame.time.get_ticks()
self.lives = 3
self.hidden = False
self.hide_timer = pygame.time.get_ticks()
def update(self):
# unhide if hidden
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
self.hidden = False
self.rect.centerx = WIDTH / 2
self.rect.bottom = HEIGHT - 10
self.speedx = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speedx = -8
if keystate[pygame.K_RIGHT]:
self.speedx = 8
if keystate[pygame.K_SPACE]:
self.shoot()
self.rect.x += self.speedx
if self.rect.right > WIDTH:
self.rect.right = WIDTH
if self.rect.left < 0:
self.rect.left = 0
def shoot(self):
now = pygame.time.get_ticks()
if now - self.last_shot > self.shoot_delay:
self.last_shot = now
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
shoot_sound.play()
def hide(self):
# hide the player temporarily
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.rect.center = (WIDTH / 2, HEIGHT + 200)
class Mob(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image_orig = random.choice(meteor_images)
self.image_orig.set_colorkey(BLACK)
self.image = self.image_orig.copy()
self.rect = self.image.get_rect()
self.radius = int(self.rect.width * .85 / 2)
# pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.bottom = random.randrange(-80, -20)
self.speedy = random.randrange(1, 8)
self.speedx = random.randrange(-3, 3)
self.rot = 0
self.rot_speed = random.randrange(-8, 8)
self.last_update = pygame.time.get_ticks()
def rotate(self):
now = pygame.time.get_ticks()
if now - self.last_update > 50:
self.last_update = now
self.rot = (self.rot + self.rot_speed) % 360
new_image = pygame.transform.rotate(self.image_orig, self.rot)
old_center = self.rect.center
self.image = new_image
self.rect = self.image.get_rect()
self.rect.center = old_center
def update(self):
self.rotate()
self.rect.x += self.speedx
self.rect.y += self.speedy
if self.rect.top > HEIGHT + 10 or self.rect.left < -100 or self.rect.right > WIDTH + 100:
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = bullet_img
self.image.set_colorkey(BLACK)
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -10
def update(self):
self.rect.y += self.speedy
# kill if it moves off the top of the screen
if self.rect.bottom < 0:
self.kill()
class Explosion(pygame.sprite.Sprite):
def __init__(self, center, size):
pygame.sprite.Sprite.__init__(self)
self.size = size
self.image = explosion_anim[self.size][0]
self.rect = self.image.get_rect()
self.rect.center = center
self.frame = 0
self.last_update = pygame.time.get_ticks()
self.frame_rate = 75
def update(self):
now = pygame.time.get_ticks()
if now - self.last_update > self.frame_rate:
self.last_update = now
self.frame += 1
if self.frame == len(explosion_anim[self.size]):
self.kill()
else:
center = self.rect.center
self.image = explosion_anim[self.size][self.frame]
self.rect = self.image.get_rect()
self.rect.center = center
# Load all game graphics
background = pygame.image.load(path.join(img_dir, "starfield.png")).convert()
background_rect = background.get_rect()
player_img = pygame.image.load(path.join(img_dir, "playerShip1_orange.png")).convert()
player_mini_img = pygame.transform.scale(player_img, (25, 19))
player_mini_img.set_colorkey(BLACK)
bullet_img = pygame.image.load(path.join(img_dir, "laserRed16.png")).convert()
meteor_images = []
meteor_list = ['meteorBrown_big1.png', 'meteorBrown_med1.png', 'meteorBrown_med1.png',
'meteorBrown_med3.png', 'meteorBrown_small1.png', 'meteorBrown_small2.png',
'meteorBrown_tiny1.png']
for img in meteor_list:
meteor_images.append(pygame.image.load(path.join(img_dir, img)).convert())
explosion_anim = {}
explosion_anim['lg'] = []
explosion_anim['sm'] = []
explosion_anim['player'] = []
for i in range(9):
filename = 'regularExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
img_lg = pygame.transform.scale(img, (75, 75))
explosion_anim['lg'].append(img_lg)
img_sm = pygame.transform.scale(img, (32, 32))
explosion_anim['sm'].append(img_sm)
filename = 'sonicExplosion0{}.png'.format(i)
img = pygame.image.load(path.join(img_dir, filename)).convert()
img.set_colorkey(BLACK)
explosion_anim['player'].append(img)
# Load all game sounds
shoot_sound = pygame.mixer.Sound(path.join(snd_dir, 'pew.wav'))
expl_sounds = []
for snd in ['expl3.wav', 'expl6.wav']:
expl_sounds.append(pygame.mixer.Sound(path.join(snd_dir, snd)))
player_die_sound = pygame.mixer.Sound(path.join(snd_dir, 'rumble1.ogg'))
pygame.mixer.music.load(path.join(snd_dir, 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
pygame.mixer.music.set_volume(0.4)
all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
bullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
newmob()
score = 0
pygame.mixer.music.play(loops=-1)
# Game loop
running = True
while running:
# keep loop running at the right speed
clock.tick(FPS)
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
# Update
all_sprites.update()
# check to see if a bullet hit a mob
hits = pygame.sprite.groupcollide(mobs, bullets, True, True)
for hit in hits:
score += 50 - hit.radius
random.choice(expl_sounds).play()
expl = Explosion(hit.rect.center, 'lg')
all_sprites.add(expl)
newmob()
# check to see if a mob hit the player
hits = pygame.sprite.spritecollide(player, mobs, True, pygame.sprite.collide_circle)
for hit in hits:
player.shield -= hit.radius * 2
expl = Explosion(hit.rect.center, 'sm')
all_sprites.add(expl)
newmob()
if player.shield <= 0:
player_die_sound.play()
death_explosion = Explosion(player.rect.center, 'player')
all_sprites.add(death_explosion)
player.hide()
player.lives -= 1
player.shield = 100
# if the player died and the explosion has finished playing
if player.lives == 0 and not death_explosion.alive():
running = False
# Draw / render
screen.fill(BLACK)
screen.blit(background, background_rect)
all_sprites.draw(screen)
draw_text(screen, str(score), 18, WIDTH / 2, 10)
draw_shield_bar(screen, 5, 5, player.shield)
draw_lives(screen, WIDTH - 100, 5, player.lives, player_mini_img)
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()
The first 12 part : Electrify
边栏推荐
- Voice controlled robot based on ROS (II): implementation of upper computer
- 全链路灰度在数据库上我们是怎么做的?
- Integrating database Ecology: using eventbridge to build CDC applications
- Redis入门一:Redis实战读书笔记
- Establishment of flask static file service
- JS drag and drop alert pop-up plug-in
- Unity performance optimization
- Mysql报错:Specified key was too long; max key length is 767 bytes
- UE4.25 Slate源码解读
- 卡通js射击小游戏源码
猜你喜欢

DHCP.DNS.NFS

GIS数据漫谈(六)— 投影坐标系统

"When you are no longer a programmer, many things will get out of control" -- talk to SUSE CTO, the world's largest independent open source company

Want to draw a picture that belongs to you? AI painting, you can also

Raspberry pie 4B uses MNN to deploy yolov5 Lite

Clock distribution of jesd204 IP core (ultrascale Series)

Use of DDR3 (axi4) in Xilinx vivado (1) create an IP core

Redis入门一:Redis实战读书笔记

How can enterprises successfully complete cloud migration?

Unity package exe to read and write excel table files
随机推荐
How bad can a programmer be? Nima, they are all talents
C reads the data in the CSV file and displays it after importing the DataTable
Unity makes prefabricated bodies with one key and modifies prefabricated bodies with one key
Redis的三种删除策略以及逐出算法
UE4 3dui widget translucent rendering blur and ghosting problems
LVM logical volume
企业如何成功完成云迁移?
JS fly into JS special effect pop-up login box
超大模型工程化实践打磨,百度智能云发布云原生AI 2.0方案
【1331. 数组序号转换】
类与对象(中)
C# 委托 delegate 的理解
Algorithm interview high frequency problem solving guide [1]
Record an error in runtime. Getruntime().Exec ("command")
js图表散点图例子
作业 ce
MySQL batch update data
Why on earth is it not recommended to use select *?
The engineering practice of super large model was polished, and Baidu AI Cloud released the cloud native AI 2.0 solution
Prize essay solicitation | 2022 cloud native programming challenge draft activity opens