You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

281 lines
11 KiB

import random
import sys
import pygame.time
from bullet import Bullet
from cloud import Cloud
from dinosaur import Dinosaur
from settings import *
pygame.init() # 初始化pygame
pygame.display.set_caption('谷歌小游戏(小恐龙快跑)') # 设置标题
class Barrier: # 定义一个障碍物基类, 后面的各个障碍物都是Barrier的子类
def __init__(self, image, type):
self.image = image
self.type = type
self.rect = self.image[self.type].get_rect()
self.rect.x = SCREEN_WIDTH # 先把障碍物放到地图的右下角,然后出来
self.game_speed = game_speed
self.hp = 100 # 血量
def update(self):
self.rect.x -= self.game_speed # x坐标向左移动即障碍物向左移动
if self.rect.x < -self.rect.width or self.hp <= 0: # 还需要判断障碍物是否移出了边界,如果越界的话我们要把该障碍物释放掉
barriers.pop()
def draw(self, SCREEN):
SCREEN.blit(self.image[self.type], self.rect)
# 头顶显示血量
def showHp(self):
font = pygame.font.SysFont(['方正粗黑宋简体', 'microsoftsansserif'], 30)
text = font.render("Hp: " + str(self.hp), True, (0, 0, 0))
SCREEN.blit(text, (self.rect.x, self.rect.y - 20))
def showHit(self):
font = pygame.font.SysFont(['方正粗黑宋简体', 'microsoftsansserif'], 30)
text = font.render("┗|`O'|┛", True, (0, 0, 0))
SCREEN.blit(text, (self.rect.x, self.rect.y - 70))
# barriers的子类
class SmallCactus(Barrier):
def __init__(self, image):
self.type = random.randint(0, 2) # 随机生成0-2下标即随机生成3种小仙人掌中的一个
super().__init__(image, self.type) # super调用父类对象的方法
self.rect.y = 325
class LargeCactus(Barrier):
def __init__(self, image):
self.type = random.randint(0, 2)
super().__init__(image, self.type)
self.rect.y = 300
class Bird(Barrier):
def __init__(self, image):
self.type = 0
super().__init__(image, self.type)
self.rect.y = 250
self.index = 0
self.ori_vy = 5
self.vy = self.ori_vy
def draw(self, SCREEN):
if self.index >= 9:
self.index = 0
SCREEN.blit(self.image[self.index // 5], self.rect)
self.index += 1
def update(self): # 多态实现鸟的上下移动
self.rect.x -= self.game_speed
if self.rect.x < -self.rect.width or self.hp <= 0: # 还需要判断障碍物是否移出了边界,如果越界的话我们要把该障碍物释放掉
barriers.pop()
self.rect.y -= self.vy * 3
self.vy -= 0.5
if self.rect.y <= 0:
self.vy = self.ori_vy
self.vy = -self.vy
elif self.rect.y >= SCREEN_HEIGHT - 250:
self.vy = 10
def menu(death_cnt):
global points, max_score # 引入points, max_score全局变量
run = True
while run:
SCREEN.fill((255, 255, 255)) # 背景色设置为白色
font = pygame.font.SysFont('microsoftyahei', 50) # 微软雅黑
if death_cnt == 0:
text = font.render("按任意键开始", True, (0, 0, 0))
elif death_cnt > 0:
text = font.render("按任意键重新启动", True, (0, 0, 0))
score = font.render("你的分数: " + str(points), True, (0, 0, 0)) # 分数
if death_cnt == 1:
max_score = points
else:
max_score = max(max_score, points)
maxScore = font.render("最高分: " + str(max_score), True, (0, 0, 0)) # 最高分
scoreRect = score.get_rect()
scoreRect.center = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 50) # 将分数显示在游戏屏幕中间
SCREEN.blit(GAMEOVER, (SCREEN_WIDTH // 2 - 200, SCREEN_HEIGHT // 2 - 200)) # 显示GAMEOVER图片
SCREEN.blit(score, scoreRect) # 显示分数
SCREEN.blit(maxScore, (SCREEN_WIDTH // 2 - 170, SCREEN_HEIGHT // 2 + 70)) # 显示最高分数
textRect = text.get_rect()
textRect.center = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)
SCREEN.blit(text, textRect)
SCREEN.blit(RUNNING[0], (SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2 - 140)) # 把恐龙的图片显示在菜单界面
# 添加作者信息
author_font = pygame.font.SysFont('microsoftyahei', 30) # 创建一个字体对象,使用 'microsoftyahei' 字体,字号大小为 30
author_text = author_font.render("作者: 袁恒", True,
(0, 0, 0)) # render 方法的参数依次是文本内容是否开启抗锯齿True 开启),文本颜色(黑色)
author_text_rect = author_text.get_rect()
author_text_rect.center = (SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 150) # 设置文本矩形的中心位置
SCREEN.blit(author_text, author_text_rect) # 使用 blit 方法将渲染后的文本表面绘制到屏幕上
pygame.display.update() # 更新画面
# 判断各个事件, 开始游戏
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
run = False
if event.type == pygame.KEYUP:
main()
def main():
global game_speed, x_ori_bg, y_ori_bg, points, barriers, death_cnt, barrier, clock_cnt
run = True
clock = pygame.time.Clock()
game_speed = 5 # 游戏的速度
player = Dinosaur(game_speed) # 实例化对象
cloud = Cloud(game_speed)
# 设置背景图片的初始位置
x_ori_bg = 0
y_ori_bg = 380
points = 0
font = pygame.font.SysFont(['方正粗黑宋简体', 'microsoftsansserif'], 20) # 分数的字体
# 设置障碍物列表
barriers = []
# 设置子弹列表
bullets = []
def score():
global points, game_speed
points += 1
if points % 150 == 0: # 分数每过150速度加1时间越长速度越快
game_speed += 1
text = font.render("score: " + str(points), True, (0, 0, 0)) # render内容是否抗锯齿字体颜色字体背景颜色
textRect = text.get_rect()
textRect.center = (550, 40)
SCREEN.blit(text, textRect)
def background():
global x_ori_bg, y_ori_bg
image_width = BG.get_width()
SCREEN.blit(BG, (x_ori_bg, y_ori_bg))
SCREEN.blit(BG, (image_width + x_ori_bg, y_ori_bg)) # 保证图片连续
if x_ori_bg <= -image_width: # 越界
SCREEN.blit(BG, (image_width + x_ori_bg, y_ori_bg))
x_ori_bg = 0
x_ori_bg -= game_speed # 背景图片每帧往左移game_speed个单位
flag_hit = 0 # 标记恐龙是否被击中过
death_cnt = 0 # 记录死亡次数death_cnt = 0显示开始界面大于0的就会显示重开界面
last_timestamp = 0 # 记录时钟记录的上一个时刻
last_timestamp_hit = 0 # 记录恐龙受到伤害时钟记录的上一个时刻
last_timestamp_barr_hit = 0 # 记录障碍物受到伤害时钟记录的上一个时刻
flag_barr_hit = 0 # 记录障碍物有没有受得伤害
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
SCREEN.fill((255, 255, 255)) # 背景填充为白色
userInput = pygame.key.get_pressed() # 从键盘读入按键
# 3s内显示血量的简单逻辑
if flag_hit == 1:
if pygame.time.get_ticks() - last_timestamp_hit <= 3000:
player.showHit()
if pygame.time.get_ticks() - last_timestamp_hit > 3000:
flag_hit = 0
background() # 画出背景
cloud.draw(SCREEN) # 画出云的图像
cloud.update() # 更新云的位置
score() # 显示分数
clock.tick(60) # 60fps
# 如果还没有障碍物,那么生成一个障碍物
if len(barriers) <= 1:
# 防止障碍物为0的情况下恐龙闪烁
player.draw(SCREEN) # 渲染恐龙画面
player.update(userInput) # 调用dinosaur的update函数每次渲染都判断一次是否按下相应的键位
player.showHp()
# 随机等可能生成障碍物
if random.randint(0, 2) == 0:
barriers.append(SmallCactus(SMALL_CACTUS)) # 向列表添加障碍物元素
elif random.randint(0, 2) == 1:
barriers.append(LargeCactus(LARGE_CACTUS))
elif random.randint(0, 2) == 2:
barriers.append(Bird(BIRD))
for barrier in barriers:
barrier.draw(SCREEN) # 调用barrier类的draw函数渲染画面
barrier.update()
barrier.showHp() # 显示血量
if flag_barr_hit == 1:
if barrier.hp < 100 and pygame.time.get_ticks() - last_timestamp_barr_hit <= 3000:
barrier.showHit()
if pygame.time.get_ticks() - last_timestamp_barr_hit > 3000:
flag_barr_hit = 0
if player.dino_rect.colliderect(barrier.rect): # pygame的一个方法colliderect检测两个物体是否碰撞
last_timestamp_hit = pygame.time.get_ticks()
player.hp -= 1 # 被击中生命值减1
flag_hit = 1
if not len(barriers) == 0:
barriers.remove(barrier)
else:
player.draw(SCREEN) # 渲染恐龙画面
player.update(userInput) # 调用dinosaur的update函数每次渲染都判断一次是否按下相应的键位
player.showHp()
if player.hp == 0: # 血量为0时
player.showDead()
player.draw_death(SCREEN)
pygame.display.update() # 显示死亡动画
pygame.time.delay(1000)
death_cnt += 1
menu(death_cnt) # 调出死亡界面
# 子弹击中障碍物部分
for bullet in bullets:
bullet.draw(SCREEN)
bullet.update()
if bullet.rect.x > SCREEN_WIDTH:
if not len(bullets):
bullets.remove(bullet)
if bullet.rect.colliderect(barrier.rect):
last_timestamp_barr_hit = pygame.time.get_ticks()
barrier.hp -= 50
flag_barr_hit = 1
bullets.remove(bullet)
if not len(barriers) == 0 and barrier.hp <= 0:
points += 50
barriers.remove(barrier)
# 发射子弹, 并且保证每个子弹的发射间隔小于200毫秒
if (userInput[pygame.K_SPACE] and pygame.time.get_ticks() - last_timestamp >= 200) or (
userInput[pygame.K_SPACE] and last_timestamp == 0):
last_timestamp = pygame.time.get_ticks() # 更新当前时间
bullets.append(Bullet(game_speed, player))
pygame.display.update()
if __name__ == '__main__':
menu(death_cnt=0)
main()