import pygame
import random
import os
# 解决图片旋转不顺畅问题
# 采用随机图片
# 得分
# 加入音效
# 加入盾牌
# 加入爆炸效果
# 加入玩家爆炸效果
# 加入几条命
# Game Over
WIDTH = 480
HEIGHT = 560
FPS = 60
# 定义颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# 图片名称
enemy_imgs = ["meteorBrown_big1.png",
"meteorBrown_big2.png",
"meteorBrown_med1.png",
"meteorBrown_med2.png",
"meteorBrown_small1.png",
"meteorBrown_small2.png",
"meteorBrown_tiny1.png"]
enemy_pics = []
# 初始化
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space War")
clock = pygame.time.Clock()
# 图片文件路径,注意别写死,应该用对应函数去取
# img_path = os.path.join(os.path.dirname(__file__), "img")
# 加载图片
background = pygame.image.load("starfield.png").convert()
background_rect = background.get_rect()
print(background_rect[0])
player_img = pygame.image.load("playerShip1_orange.png")
# 用于展示几条命的小图
player_mini_img = pygame.transform.scale(player_img, (25, 19))
# player_mini_img.set_colorkey(BLACK)
bullet_img = pygame.image.load("laserRed16.png")
# med_img = pygame.image.load("meteorBrown_med1.png"))
# 加载敌军图片,放到一个列表
for img in enemy_imgs:
enemy_pics.append(pygame.image.load(img))
# 音效文件
# snd_path = os.path.join(os.path.dirname(__file__), "snd")
shoot_sound = pygame.mixer.Sound("pew.wav")
# 爆炸声音
explore_snds = []
for snd in ["expl3.wav", "expl6.wav"]:
explore_snds.append(pygame.mixer.Sound(snd))
# 背景音乐
# pygame.mixer.music.load('Summer.mp3') # 'tgfcoder-FrozenJam-SeamlessLoop.ogg'))
# pygame.mixer.music.set_volume(0.4)
# 爆炸效果
exp_file_name = ['regularExplosion00.png', 'regularExplosion01.png',
'regularExplosion02.png', 'regularExplosion03.png',
'regularExplosion04.png', 'regularExplosion05.png',
'regularExplosion06.png', 'regularExplosion07.png',
'regularExplosion08.png']
exp_imgs = []
for i in exp_file_name:
img = pygame.image.load(i)
exp_imgs.append(img)
# Player爆炸效果
player_exp_file_name = ['sonicExplosion00.png', 'sonicExplosion01.png',
'sonicExplosion02.png', 'sonicExplosion03.png',
'sonicExplosion04.png', 'sonicExplosion05.png',
'sonicExplosion06.png', 'sonicExplosion07.png',
'sonicExplosion08.png']
player_exp_imgs = []
for i in player_exp_file_name:
img = pygame.image.load(i)
player_exp_imgs.append(img)
# 爆炸效果Sprite
class Explosion(pygame.sprite.Sprite):
def __init__(self, center, imgs):
pygame.sprite.Sprite.__init__(self)
self.imgs = imgs
self.image = self.imgs[0]
self.rect = self.image.get_rect()
self.rect.center = center
self.frame = 0
self.last_update = pygame.time.get_ticks()
self.frame_rate = 50
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(self.imgs):
self.kill()
else:
center = self.rect.center
self.image = self.imgs[self.frame]
self.rect = self.image.get_rect()
self.rect.center = center
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# self.image = pygame.Surface((50, 40))
# self.image.fill(GREEN)
self.image = player_img
self.rect = self.image.get_rect()
self.radius = 30
# 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 = 1000
# 加入几条命
self.lives = 3
self.hidden = False
self.hide_timer = pygame.time.get_ticks()
def hide(self):
self.hidden = True
self.hide_timer = pygame.time.get_ticks()
self.rect.center = (WIDTH / 2, HEIGHT + 200) # 隐藏到屏幕外
def update(self):
if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
self.hidden = False
self.rect.center = (WIDTH / 2, 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
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):
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
# 播放声音
shoot_sound.play()
# 敌军
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
# self.image_orig = med_img
# 改成随机选择一张图片
self.image_orig = random.choice(enemy_pics)
self.image = self.image_orig.copy()
self.rect = self.image.get_rect()
# self.radius = 15
# 半径改成不写死,而是图片矩形宽度的80%(再除以2是半径)
self.radius = int(self.rect.width * 0.8 / 2)
# pygame.draw.circle(self.image, RED, self.rect.center, self.radius)
self.rect.x = random.randrange(WIDTH - self.rect.width)
self.rect.y = random.randrange(-100, -40)
self.speedy = random.randrange(1, 8)
self.speedx = random.randrange(-3, 3)
# Rotate
self.rot = 0
self.rotate_speed = random.randint(-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.rotate_speed) % 360
# self.image = pygame.transform.rotate(self.image,self.rotate_speed)
# self.image = pygame.transform.rotate(self.image_orig, self.rot) #改成下面的方式
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 < -25 or self.rect.right > WIDTH + 20:
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 = pygame.Surface((10, 20))
# self.image.fill(YELLOW)
self.image = bullet_img
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.speedy = -15
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()
# 找一个最匹配的字体
font_name = pygame.font.match_font('arial')
# 绘制几条命
def draw_lives(surf, x, y, lives, pimg):
for i in range(lives):
img_rect = pimg.get_rect()
img_rect.x = x + 30 * i
img_rect.y = y
surf.blit(pimg, img_rect)
# 绘制文字
def draw_text(surf, text, size, x, y):
# 得到字体,中文显示,需要明确指明字体位置
# font = pygame.font.Font("/Library/Fonts/Microsoft/Kaiti.ttf", size)
font = pygame.font.Font("/System/Library/Fonts/PingFang.ttc", size)
# 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)
# 绘制生命值
BAR_LENGTH = 100
BAR_HEIGHT = 10
def draw_shield_bar(surf, x, y, pct):
if pct < 0:
pct = 0
fill = (pct / 1000) * 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)
# ################Game Over###############
def show_go_screen():
screen.blit(background, background_rect)
draw_text(screen, "Space War", 64, WIDTH / 2, HEIGHT / 4)
draw_text(screen, u"左右箭头移动飞船,空格键发射子弹", 22,
WIDTH / 2, HEIGHT / 2)
draw_text(screen, u"按任意键开始游戏", 18, WIDTH / 2, HEIGHT * 3 / 4)
pygame.display.flip()
waiting = True
while waiting:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP:
waiting = False
########################################
# 播放背景音乐
# pygame.mixer.music.play(-1)
game_over = True
# Game loop
running = True
while running:
if game_over:
show_go_screen()
game_over = False
# 下面就是原来初始化游戏的代码
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
m = Enemy()
all_sprites.add(m)
enemies.add(m)
score = 0
clock.tick(FPS)
# 按键事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE: # 空格
player.shoot()
# 更新状态
all_sprites.update()
# 监测子弹是否集中了敌军,击中,则子弹和敌军均消失
hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
for hit in hits: # 补充敌军到列表
m = Enemy()
all_sprites.add(m)
enemies.add(m)
score += (50 - hit.radius)
# 随机选择一个爆炸声播放
random.choice(explore_snds).play()
# 加入爆炸效果
exp = Explosion(hit.rect.center, exp_imgs)
all_sprites.add(exp)
# 监测敌军是否撞上Player
hits = pygame.sprite.spritecollide(player, enemies, True, pygame.sprite.collide_circle)
# if hits:
for hit in hits:
# running = False #game over
# pass
e = Enemy()
all_sprites.add(e)
enemies.add(e)
# 每次降低一定的生命值
player.shield -= hit.radius
if player.shield <= 0:
# running = False
# player.kill() #改成kill(),不退出游戏
# 爆炸
death_exp = Explosion(player.rect.center, player_exp_imgs)
all_sprites.add(death_exp)
player.hide()
player.lives -= 1
player.shield = 100
# 绘制
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)
# 输出到屏幕
pygame.display.flip()
# 如果生命只剩0条,则把player 杀死
if player.lives == 0:
player.kill()
# 退出游戏
if not player.alive() and not death_exp.alive():
# running = False
game_over = True
pygame.quit()