python大作业高分项目--射击闯关游戏
原创项目特点:
地图编辑器:玩家可以定义每个关卡的风格和难度
运行界面:玩家的移动、跳跃、发射子弹、投掷手榴弹和敌人的AL(移动,发射子弹,投掷手榴弹)。同时,游戏拥有一系列道具(生命值药盒、子弹补给、手榴弹补给)和各种动画和音乐音效,以及各种花卉和岩石装饰,以及悬崖和水漩涡的危险场所。更多的未知,你可以通过自己的经验来感受!
累计总代码1100行左右!
地图编辑器:
import pygame import sys import csv import button
pygame.init()
定义时钟
clock = pygame.time.Clock() FPS = 60
游戏窗口
SCREEN_WIDTH = 800 SCREEN_HEIGHT = 560 LOWER_MARGIN = 100 SIDE_MAGTIN = 300 screen = pygame.display.set_mode((SCREEN_WIDTH + SIDE_MAGTIN, SCREEN_HEIGHT + LOWER_MARGIN)) pygame.display.set_caption("级别编辑器")
定义游戏变量
ROWS = 16 MAX_COLS = 150 TILE_SIZE = SCREEN_HEIGHT // ROWS TILE_TYPES = 21 level = 1 current_tile = 0 scroll_left = False scroll_right = False scroll = 0 scroll_speed = 1
加载背景图像
pine1_img = pygame.image.load("img/Background/pine1.png").convert_alpha() pine2_img = pygame.image.load("img/Background/pine2.png").convert_alpha() mountain_img = pygame.image.load("img/Background/mountain.png").convert_alpha() sky_img = pygame.image.load("img/Background/sky_cloud.png").convert_alpha()
平铺平铺列表
img_list = [] for x in range(TILE_TYPES): img = pygame.image.load(f"img/tile/{x}.png") img = pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE)) img_list.append(img)
创建保存按钮
save_img = pygame.image.load("img/save_btn.png").convert_alpha() load_img = pygame.image.load("img/load_btn.png").convert_alpha()
定义颜色
GREEN = (144, 201, 120) WHITE = (255, 255, 255) RED = (200, 25, 25)
定义字体
font = pygame.font.SysFont("Futura", 30)
创建空平铺列表(2D)
world_data = [] for row in range(ROWS): r = [-1] * MAX_COLS world_data.append(r)
创建组
for tile in range(0, MAX_COLS): world_data[ROWS - 1][tile] = 0
定义文本显示功能以在屏幕上显示下一级
def draw_text(text, font, text_color, x, y): img = font.render(text, True, text_color) screen.blit(img, (x, y))
创建背景函数
def draw_bg(): screen.fill(GREEN) width = sky_img.get_width() for x in range(4): screen.blit(sky_img, ((x width) - scroll 0.5, 0)) screen.blit(mountain_img, ((x width) - scroll 0.6, SCREEN_HEIGHT - mountain_img.get_height() - 300)) screen.blit(pine1_img, ((x width) - scroll 0.7, SCREEN_HEIGHT - pine1_img.get_height() - 150)) screen.blit(pine2_img, ((x width) - scroll 0.8, SCREEN_HEIGHT - pine2_img.get_height()))
绘制格子
def draw_grid():
垂直的线
for c in range(MAX\_COLS + 1):
pygame.draw.line(screen, WHITE, (c * TILE\_SIZE - scroll, 0), (c * TILE\_SIZE - scroll, SCREEN\_HEIGHT))
# 水平的线
for c in range(ROWS + 1):
pygame.draw.line(screen, WHITE, (0, c * TILE\_SIZE), (SCREEN\_WIDTH, c * TILE\_SIZE))
在地图中绘制平铺
def draw_world(): for y, row in enumerate(world_data): for x, tile in enumerate(row): if tile >= 0: screen.blit(img_list[tile], (x TILE_SIZE - scroll, y TILE_SIZE))
创建按钮
创建保存和加载数据按钮
save_button = button.Button(SCREEN_WIDTH // 2, SCREEN_HEIGHT + LOWER_MARGIN - 50, save_img, 1) load_button = button.Button(SCREEN_WIDTH // 2 + 200, SCREEN_HEIGHT + LOWER_MARGIN - 50, load_img, 1)
制作按钮平铺列表
button_list = [] button_col = 0 button_row = 0 for i in range(len(img_list)): tile_button = button.Button(SCREEN_WIDTH + (75 button_col) + 50, 75 button_row + 50, img_list[i], 1) button_list.append(tile_button) button_col += 1 if button_col == 3: button_row += 1 button_col = 0
run = True while run: clock.tick(FPS) draw_bg() draw_grid() draw_world()
draw\_text(f"Level: {level}", font, WHITE, 10, SCREEN\_HEIGHT + LOWER\_MARGIN - 90)
draw\_text("Press up or Down to change level", font, WHITE, 10, SCREEN\_HEIGHT + LOWER\_MARGIN - 60)
# 保存和加载地图数据
if save\_button.draw(screen):
# 保存级别数据
with open(f"level{level}\_data.csv", "w", newline="") as csvfile:
writer = csv.writer(csvfile, delimiter = ",")
for row in world\_data:
writer.writerow(row)
# with open(f"level{level}\_data.csv", "wb") as pickle\_out:
# pickle.dump(world\_data, pickle\_out)
if load\_button.draw(screen):
# 加载地图级别数据
# 重置滚动scroll是起始位置0
scroll = 0
with open(f"level{level}\_data.csv", "r", newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",")
for y, row in enumerate(reader):
for x, tile in enumerate(row):
world\_data[y][x] = int(tile)
# 油漆面板和瓷砖
pygame.draw.rect(screen, GREEN, (SCREEN\_WIDTH, 0, SIDE\_MAGTIN, SCREEN\_HEIGHT))
# 选择一个磁贴以获取右侧磁贴列表的详细信息
button\_count = 0
for button\_count, i in enumerate(button\_list):
if i.draw(screen):
current\_tile = button\_count
# 高亮显示选定的平铺
pygame.draw.rect(screen, RED, button\_list[current\_tile].rect, 3)
# 滚动地图
if scroll\_left == True and scroll > 0:
scroll -= 5 * scroll\_speed
if scroll\_right == True and scroll < (MAX\_COLS * TILE\_SIZE) - SCREEN\_WIDTH: # 检测最右边的边缘
scroll += 5 * scroll\_speed
# 在窗口中添加新平铺
# 获取鼠标的位置
pos = pygame.mouse.get\_pos()
x = (pos[0] + scroll) // TILE\_SIZE
y = pos[1] // TILE\_SIZE
# 检测单击的区域并将获得的平铺放置在地图的右侧。
if pos[0] < SCREEN\_WIDTH and pos[1] < SCREEN\_HEIGHT:
# 更新平铺的值
if pygame.mouse.get\_pressed()[0] == 1:
if world\_data[y][x] != current\_tile:
world\_data[y][x] = current\_tile
# 删除选定项
if pygame.mouse.get\_pressed()[2] == 1:
world\_data[y][x] = -1
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
sys.exit()
# 键盘按键
if event.type == pygame.KEYDOWN:
if event.key == pygame.K\_UP:
level += 1
if event.key == pygame.K\_DOWN and level > 0:
level -= 1
if event.key == pygame.K\_LEFT:
scroll\_left = True
if event.key == pygame.K\_RIGHT:
scroll\_right = True
if event.key == pygame.K\_LSHIFT:
scroll\_speed = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K\_LEFT:
scroll\_left = False
if event.key == pygame.K\_RIGHT:
scroll\_right = False
if event.key == pygame.K\_LSHIFT:
scroll\_speed = 1
pygame.display.update()
游戏主要运行程序:
import pygame from pygame import mixer import sys import os import random import csv import button import math
mixer.init() pygame.init()
画布元素
SCREEN_WIDTH = 800 SCREEN_HEIGHT = int(SCREEN_WIDTH * 0.8) screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("射击游戏")
设置帧
clock = pygame.time.Clock() FPS = 60
定义游戏变量
GRAVITY = 0.75 SCROLL_THRESH = 200 ROWS = 16 COLS = 150 TILE_SIZE = SCREEN_HEIGHT // ROWS TILE_TYPES = 21 MAX_LEVELS = 3 screen_scroll = 0 bg_scroll = 0 level = 1
定义游戏状态
start_game = False
定义是否淡出游戏屏幕
start_intro = False
定义玩家状态变量
moving_left = False moving_right = False shoot = False grenade = False grenade_thrown = False
加载音乐和声音
pygame.mixer.music.load("audio/music2.mp3") pygame.mixer.music.set_volume(0.3) pygame.mixer.music.play(-1, 0.0, 3000) jump_fx = pygame.mixer.Sound("audio/jump.wav") jump_fx.set_volume(0.5) shot_fx = pygame.mixer.Sound("audio/shot.wav") shot_fx.set_volume(0.9) grenade_fx = pygame.mixer.Sound("audio/grenade.wav") grenade_fx.set_volume(0.9)
加载背景图像
pine1_img = pygame.image.load("img/Background/pine1.png").convert_alpha() pine2_img = pygame.image.load("img/Background/pine2.png").convert_alpha() mountain_img = pygame.image.load("img/Background/mountain.png").convert_alpha() sky_img = pygame.image.load("img/Background/sky_cloud.png").convert_alpha()
加载按钮图像
start_img = pygame.image.load("img/start_btn.png").convert_alpha() exit_img = pygame.image.load("img/exit_btn.png").convert_alpha() restart_img = pygame.image.load("img/restart_btn.png").convert_alpha()
加载21平铺图像列表中放置的平铺图像类型
img_list = [] for x in range(TILE_TYPES): img = pygame.image.load(f"img/Tile/{x}.png") img = pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE)) img_list.append(img)
加载子弹
bullet_img = pygame.image.load("img/icons/bullet.png").convert_alpha() grenade_img = pygame.image.load("img/icons/grenade.png").convert_alpha()
加载物品
health_box_img = pygame.image.load("img/icons/health_box.png").convert_alpha() ammo_box_img = pygame.image.load("img/icons/ammo_box.png").convert_alpha() grenade_box_img = pygame.image.load("img/icons/grenade_box.png").convert_alpha() item_boxes = { "Health": health_box_img, "Ammo": ammo_box_img, "Grenade": grenade_box_img }
定义颜色
BG = (144, 201, 120) RED = (255, 0, 0) WHITE = (255, 255, 255) GREEN = (0, 255, 0) BLACK = (0, 0, 0) PINK = (235, 65, 54)
定义字体
font = pygame.font.SysFont("Futura", 30)
定义显示玩家相关属性的显示文本函数
def draw_text(text, font, text_color, x, y): img = font.render(text, True, text_color) screen.blit(img, (x, y))
刷新背景功能,for循环重复背景,刷新不同照片的背景x实现背景动态效果的坐标
def draw_bg(): screen.fill(BG) width = sky_img.get_width() for x in range(5): screen.blit(sky_img, ((x width) - bg_scroll 0.5, 0)) screen.blit(mountain_img, ((x width) - bg_scroll 0.6, SCREEN_HEIGHT - mountain_img.get_height() - 300)) screen.blit(pine1_img, ((x width) - bg_scroll 0.7, SCREEN_HEIGHT - pine1_img.get_height() - 150)) screen.blit(pine2_img, ((x width) - bg_scroll 0.8, SCREEN_HEIGHT - pine2_img.get_height()))
重置游戏功能的定义,并在与“清除”牌碰撞时清除此级别的所有显示元素。
def reset_level(): enemy_group.empty() bullet_group.empty() grenade_group.empty() explosion_group.empty() item_box_group.empty() decoration_group.empty() water_group.empty() exit_group.empty()
创建平铺的空列表。二维列表行和列
data = [] for row in range(ROWS): r = [-1] * COLS data.append(r) return data
创建士兵类(敌人和玩家)
class Soldier(pygame.sprite.Sprite): def __init__(self, char_type, x, y, scale, speed, ammo, grenades): super().__init__() self.alive = True # 定义或死亡变量 self.char_type = char_type # 获取文件类型样式 self.speed = speed # 速度 self.ammo = ammo # 子弹 self.start_ammo = ammo self.shoot_cooldown = 0 # 冷却 self.grenades = grenades # 手雷 self.health = 100 # 生命值 self.max_health = self.health self.direction = 1 # 默认向右方向 self.vel_y = 0 # 垂直 self.jump = False # 跳跃 self.in_air = True # 是否在空气中 self.flip = False # 默认左为false self.animation_list = [] # 动画列表 self.frame_index = 0 # 索引 self.action = 0 # 选择动作变量 self.update_time = pygame.time.get_ticks() # 获取时间(毫秒)
创建AI特定变量
self.move\_counter = 0 # 移动计数,对应于来回移动的以下敌人
self.vision = pygame.Rect(0, 0, 150, 20) # 搜索视线中的玩家
self.idling = False # 空闲状态,对应于以下内容AI射击和投掷手榴弹的状态
self.idling\_counter = 0 # 闲置计数
self.grenade\_time = pygame.time.get\_ticks() # 对应以下手榴弹爆炸时间
# 加载的播放器是所有图片类型
animation\_types = ["Idle", "Run", "Jump", "Death"]
for animation in animation\_types:
# 重置临时列表
temp\_list = []
# 计算每个动画帧的数量
num\_of\_frames = len(os.listdir(f"img/{char\_type}/{animation}"))
for i in range(num\_of\_frames):
img = pygame.image.load(f"img/{char\_type}/{animation}/{i}.png").convert\_alpha()
img = pygame.transform.scale(img, (int(img.get\_width() * scale), int(img.get\_height() * scale)))
temp\_list.append(img)
self.animation\_list.append(temp\_list)
self.image = self.animation\_list[self.action][self.frame\_index]
self.rect = self.image.get\_rect()
self.rect.center = (x, y)# rect=(x,y,w,h)
self.width = self.image.get\_width()
self.height = self.image.get\_height()
def update(self): self.update_animation() self.check_alive()
更新冷却时间
if self.shoot\_cooldown > 0:
self.shoot\_cooldown -= 1
def move(self, moving_left, moving_right):
重置移动变量
screen\_scroll = 0
dx = 0
dy = 0
# 根据移动变量向左或向右移动
if moving\_left:
dx = -self.speed
self.flip = True
self.direction = -1
if moving\_right:
dx = self.speed
self.flip = False
self.direction = 1
# 跳跃
if self.jump == True and self.in\_air == False:
self.vel\_y = -11
self.jump = False
self.in\_air = True
# 利用重力让它进入y限制方向跳跃高度
self.vel\_y += GRAVITY
if self.vel\_y > 10:
self.vel\_y
dy += self.vel\_y
# 探测与地面的碰撞
for tile in world.obstacle\_list:
# 用每个地砖检测玩家x方向上的碰撞
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
dx = 0
# 正在检测是否存在ai机器人撞到墙上并返回。
if self.char\_type == "enemy":
self.direction *= -1
self.move\_counter = 0
# 带有瓷砖的汽车检查器播放器y方向上的碰撞
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
# 探测与地面底部的碰撞
if self.vel\_y < 0:
self.vel\_y = 0
dy = tile[1].bottom - self.rect.top
# 探测与地面顶部的碰撞
elif self.vel\_y >= 0:
self.vel\_y = 0
self.in\_air = False
dy = tile[1].top - self.rect.bottom
# 检测与水面的碰撞
if pygame.sprite.spritecollide(self, water\_group, False):
self.health = 0
# 检查车辆与出口标志碰撞
level\_complete = False
if pygame.sprite.spritecollide(self, exit\_group, False):
level\_complete = True
# 检测到地图上的坠落
if self.rect.bottom > SCREEN\_HEIGHT:
self.health = 0
# 检查是否已到达窗口边缘。如果你已经到了窗户的边缘,你就不能再走路了。
if self.char\_type == "player":
if self.rect.left + dx < 0 or self.rect.right + dx > SCREEN\_WIDTH:
dx = 0
# 更新矩形的位置
self.rect.x += dx
self.rect.y += dy
# 根据玩家位置更新滚动平台 rect.right 对应于矩形的左侧,依此类推
if self.char\_type == "player":
if (self.rect.right > SCREEN\_WIDTH - SCROLL\_THRESH and bg\_scroll < world.level\_length * TILE\_SIZE - SCREEN\_WIDTH)\
or (self .rect.left < SCROLL\_THRESH and bg\_scroll > abs(dx)):
self.rect.x -= dx
screen\_scroll = -dx
return screen\_scroll, level\_complete
def shoot(self): if self.shoot_cooldown == 0 and self.ammo > 0: self.shoot_cooldown = 20 bullet = Bullet(self.rect.centerx + (0.75 self.rect.size[0] self.direction), self.rect.centery, self.direction) bullet_group.add(bullet)
减少弹药
self.ammo -= 1
shot\_fx.play()
def ai(self): if self.alive and player.alive: if self.idling == False and random.randint(1, 100) == 1: self.update_action(0) # 选择空闲操作 self.idling = True
ai检测附近的士兵
if self.vision.colliderect(player.rect):
# 停止跑步,面对球员
self.update\_action(0)
# 并射击
self.shoot()
else:
# 不规则投掷手榴弹
now\_time = pygame.time.get\_ticks()
if math.sqrt(math.pow(abs(self.rect.centerx - player.rect.centerx), 2) + math.pow(
abs(self.rect.centery - player.rect.centery), 2)) < TILE\_SIZE * 5:
if self.grenades > 0:
if now\_time - self.grenade\_time > random.randint(2000, 3000):
# 停止跑步,面对球员
self.update\_action(0)
self.grenade\_time = pygame.time.get\_ticks()
grenade = Grenade(self.rect.centerx, self.rect.centery, self.direction)
grenade\_group.add(grenade)
self.grenades -= 1
if self.idling == False:
if self.direction == 1:
ai\_moving\_right = True
self.idling\_counter = 50
else:
ai\_moving\_right = False
ai\_moving\_left = not ai\_moving\_right
self.move(ai\_moving\_left, ai\_moving\_right)
self.update\_action(1) # 选择运动动作
self.move\_counter += 1
# 更新ai可视范围作为移动范围
self.vision.center = (self.rect.centerx + 75 * self.direction, self.rect.centery)
# pygame.draw.rect(screen, RED, self.vision)
if self.move\_counter > TILE\_SIZE:
self.direction *= -1
self.move\_counter *= -1
else:
self.idling\_counter -= 1
if self.idling\_counter <= 0:
self.idling = False
# 滚动
self.rect.x += screen\_scroll
def update_animation(self):
更新动画
ANIMATION\_COOLDOWN= 100
# 更新当前帧
self.image = self.animation\_list[self.action][self.frame\_index]
# 检测当前时间更新时间
if pygame.time.get\_ticks() - self.update\_time > ANIMATION\_COOLDOWN:
self.update\_time = pygame.time.get\_ticks()
self.frame\_index += 1
# 检测列表索引是否超过动画帧数
if self.frame\_index >= len(self.animation\_list[self.action]):
if self.action == 3:
self.frame\_index = len(self.animation\_list[self.action]) - 1
else:
self.frame\_index = 0
def update_action(self, new_action):
播放不同的动画以判断不同的动作
if new\_action != self.action:
self.action = new\_action
# 更新动画设置
self.frame\_index = 0
self.update\_time = pygame.time.get\_ticks()
def check_alive(self): if self.health <= 0: self.health = 0 self.speed = 0 self.alive = False self.update_action(3) def draw(self): screen.blit(pygame.transform.flip(self.image, self.flip, False), self.rect)
收集的项目
class ItemBox(pygame.sprite.Sprite): def __init__(self, item_type, x, y): super().__init__() self.item_type = item_type self.image = item_boxes.get(self.item_type) self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) def update(self):
滚动
self.rect.x += screen\_scroll
# 士兵与物体碰撞
if pygame.sprite.collide\_rect(self, player):
# 检测获取的盒子的类型
if self.item\_type == "Health":
player.health += 25
if player.health > player.max\_health:
player.health = player.max\_health
elif self.item\_type == "Ammo":
player.ammo += 15
elif self.item\_type == "Grenade":
player.grenades += 3
# 删除物品
self.kill()
创建血条类
class HealthBar(): def __init__(self, x, y, health, max_health): self.x = x self.y = y self.health = health self.max_health = max_health def draw(self, health):
更新最新的血条
self.health = health
# 计算血条的比例
ratio = self.health / self.max\_health
pygame.draw.rect(screen, BLACK, (self.x - 2, self.y - 2, 154, 24))
pygame.draw.rect(screen, RED, (self.x, self.y, 150, 20))
pygame.draw.rect(screen, GREEN, (self.x, self.y, 150 * ratio, 20))
class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): super().__init__() self.speed = 10 self.image = bullet_img self.rect = self.image.get_rect() self.rect.center = (x, y) self.direction = direction def update(self):
移动子弹
self.rect.x += (self.direction * self.speed) + screen\_scroll # 子弹发射时也必须一起移动。
# 检测子弹与地砖的碰撞
for tile in world.obstacle\_list:
if tile[1].colliderect(self.rect):
self.kill()
# 检测子弹碰撞
if pygame.sprite.spritecollide(player, bullet\_group, False):
if player.alive:
player.health -= 5
self.kill()
for enemy in enemy\_group:
if pygame.sprite.spritecollide(enemy, bullet\_group, False):
if enemy.alive:
enemy.health -= 25
self.kill()
创建手雷
class Grenade(pygame.sprite.Sprite): def __init__(self, x, y, direction): super().__init__() self.timer = 90 self.vel_y = -11 self.speed = 7 self.image = grenade_img self.rect = self.image.get_rect() self.rect.center = (x, y) self.direction = direction self.width = self.image.get_width() self.height = self.image.get_height() def update(self): self.vel_y += GRAVITY dx = self.direction * self.speed dy = self.vel_y
# 检测手榴弹与每个瓦片的碰撞
for tile in world.obstacle\_list:
# 检测与瓷砖墙的碰撞
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
self.direction *= -1
dx = self.direction * self.speed
# 检测与y方向上的碰撞
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
self.speed = 0
# 探测与地面底部的碰撞向下反弹
if self.vel\_y < 0:
self.vel\_y = 0
dy = tile[1].bottom - self.rect.top
# 探测与地面顶部的碰撞
elif self.vel\_y >= 0:
self.vel\_y = 0
self.in\_air = False
dy = tile[1].top - self.rect.bottom
# 更新参与地点
self.rect.x += dx + screen\_scroll # 辉光投掷还需要增加滚动量
self.rect.y += dy
# 辉光爆炸冷却时间
self.timer -= 1
if self.timer <= 0:
self.kill()
grenade\_fx.play()
explosion = Explosion(self.rect.x, self.rect.y, 0.8)
explosion\_group.add(explosion)
# 爆炸后,一定范围内的任何人都会受到伤害。
if abs(self.rect.centerx - player.rect.centerx) < TILE\_SIZE * 2 and \
abs(self.rect.centery - player.rect.centery) < TILE\_SIZE * 2:
player.health -= 10
for enemy in enemy\_group:
# if abs(self.rect.centerx - enemy.rect.centerx) < TILE\_SIZE and \
# abs(self.rect.centery - enemy.rect.centery) < TILE\_SIZE:
# enemy.health -= 100
if abs(self.rect.centerx - enemy.rect.centerx) < TILE\_SIZE * 2 and \
abs(self.rect.centery - enemy.rect.centery) < TILE\_SIZE * 2:
enemy.health -= 50
为地图创建类
class World(): def __init__(self): self.obstacle_list = [] # 障碍列表 def process_data(self, data1): self.level_length = len(data1[0])
循环加载数据的每个值
for y, row in enumerate(data1):
for x, tile in enumerate(row):
if tile >= 0:
img = img\_list[tile]
img\_rect = img.get\_rect()
img\_rect.x = x * TILE\_SIZE
img\_rect.y = y * TILE\_SIZE
tile\_data = (img, img\_rect)
if tile >= 0 and tile <= 8: # 地面泥块
self.obstacle\_list.append(tile\_data)
elif tile >= 9 and tile <= 10: # 水
water = Water(img, x * TILE\_SIZE, y * TILE\_SIZE)
water\_group.add(water)
elif tile >= 11 and tile <= 14: # 装饰性类型
decoration = Decoration(img, x * TILE\_SIZE, y * TILE\_SIZE)
decoration\_group.add(decoration)
elif tile == 15: # 创建自己的球员。
player = Soldier("player", x * TILE\_SIZE, y * TILE\_SIZE, 1.65, 5, 30, 10)
health\_bar = HealthBar(10, 10, player.health, player.health)
elif tile == 16: # 创建敌人
enemy = Soldier("enemy", x * TILE\_SIZE, y * TILE\_SIZE, 1.65, 2, 20, 5)
enemy\_group.add(enemy)
elif tile == 17:
# 收集弹药
item\_box = ItemBox("Ammo", x * TILE\_SIZE, y * TILE\_SIZE)
item\_box\_group.add(item\_box)
elif tile == 18:
# 收集手雷
item\_box = ItemBox("Grenade", x * TILE\_SIZE, y * TILE\_SIZE)
item\_box\_group.add(item\_box)
elif tile == 19:
# 收集医药
item\_box = ItemBox("Health", x * TILE\_SIZE, y * TILE\_SIZE)
item\_box\_group.add(item\_box)
elif tile == 20: # 出口
exit = Exit(img, x * TILE\_SIZE, y * TILE\_SIZE)
exit\_group.add(exit)
return player, health\_bar
def draw(self): for tile in self.obstacle_list: tile[1][0] += screen_scroll screen.blit(tile[0], tile[1])
装饰品类
class Decoration(pygame.sprite.Sprite): def __init__(self, img, x, y): super().__init__() self.image = img self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) def update(self): self.rect.x += screen_scroll
创建水类
class Water(pygame.sprite.Sprite): def __init__(self, img, x, y): super().__init__() self.image = img self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) def update(self): self.rect.x += screen_scroll
创建出口
class Exit(pygame.sprite.Sprite): def __init__(self, img, x, y): super().__init__() self.image = img self.rect = self.image.get_rect() self.rect.midtop = (x + TILE_SIZE // 2, y + (TILE_SIZE - self.image.get_height())) def update(self): self.rect.x += screen_scroll
创建爆炸类
class Explosion(pygame.sprite.Sprite): def __init__(self, x, y, scale): super().__init__() self.images = [] for num in range(1, 6): img = pygame.image.load(f"img/explosion/exp{num}.png").convert_alpha() img = pygame.transform.scale(img, (int(img.get_width() scale), int(img.get_height() scale))) self.images.append(img) self.frame_index = 0 self.image = self.images[self.frame_index] self.rect = self.image.get_rect() self.rect.center = (x, y) self.counter = 0
def update(self):
爆炸加滚动
self.rect.x += screen\_scroll
EXPLOSION\_SPEED = 4
# 更新爆炸动画
self.counter += 1
if self.counter >= EXPLOSION\_SPEED:
self.counter = 0
self.frame\_index += 1
# 检测爆炸后删除爆炸
if self.frame\_index >= len(self.images):
self.kill()
else:
self.image = self.images[self.frame\_index]
class ScreenFade(): def __init__(self, direction, color, speed): self.direction = direction self.color = color self.speed = speed self.fade_counter = 0
def fade(self): fade_complete = False # 定义以确定是否完成覆盖 self.fade_counter += self.speed if self.direction == 1: #所有类型的褪色 pygame.draw.rect(screen, self.color, (0 - self.fade_counter, 0, SCREEN_WIDTH // 2, SCREEN_HEIGHT)) # 向左开球 pygame.draw.rect(screen, self.color, (SCREEN_WIDTH // 2 + self.fade_counter, 0, SCREEN_WIDTH, SCREEN_HEIGHT)) # 向右。 pygame.draw.rect(screen, self.color, (0, 0 - self.fade_counter, SCREEN_WIDTH, SCREEN_HEIGHT // 2)) pygame.draw.rect(screen, self.color, (0, SCREEN_HEIGHT // 2 + self.fade_counter, SCREEN_WIDTH, SCREEN_HEIGHT)) if self.direction == 2: # 垂直向下淡入 pygame.draw.rect(screen, self.color, (0, 0, SCREEN_WIDTH, 0 + self.fade_counter)) if self.fade_counter >= SCREEN_WIDTH: fade_complete = True return fade_complete
创建淡入淡出
intro_fade = ScreenFade(1, BLACK, 4) death_fade = ScreenFade(2, PINK, 4)
创建开始、退出和重置菜单按钮
start_button = button.Button(SCREEN_WIDTH // 2 - 130, SCREEN_HEIGHT // 2 - 150, start_img, 1) exit_button = button.Button(SCREEN_WIDTH // 2 - 110, SCREEN_HEIGHT // 2 + 50, exit_img, 1) restart_button = button.Button(SCREEN_WIDTH // 2 - 70, SCREEN_HEIGHT // 2 - 50, restart_img, 1)
创建群组
enemy_group = pygame.sprite.Group() bullet_group = pygame.sprite.Group() grenade_group = pygame.sprite.Group() explosion_group = pygame.sprite.Group() item_box_group = pygame.sprite.Group() decoration_group = pygame.sprite.Group() water_group = pygame.sprite.Group() exit_group = pygame.sprite.Group()
创建空平铺列表
world_data = [] for row in range(ROWS): r = [-1] * COLS world_data.append(r)
负荷水平数据创建图
with open(f"level{level}_data.csv", newline="") as csvfile: reader = csv.reader(csvfile, delimiter=",") for y, row in enumerate(reader): for x, tile in enumerate(row): world_data[y][x] = int(tile) world = World() player, health_bar = world.process_data(world_data) run = True while run: clock.tick(FPS) if start_game == False:
显示主菜单
# 画菜单
screen.fill(BG)
# 增加按钮
if start\_button.draw(screen):
start\_game = True
start\_intro = True
if exit\_button.draw(screen):
run = False
else: draw_bg()
显示地图
world.draw()
# 显示血条
health\_bar.draw(player.health)
# 显示弹药量
draw\_text("AMMO: ", font, WHITE, 10, 35)
for x in range(player.ammo):
screen.blit(bullet\_img, (90 + (x * 10), 40))
# 显示手榴弹数量
draw\_text("GRENADES: ", font, WHITE, 10, 60)
for x in range(player.grenades):
screen.blit(grenade\_img, (135 + (x * 15), 60))
# 显示血条数量
# draw\_text(f"AMMO: {player.ammo}", font, WHITE, 10, 35)
player.update()
player.draw()
for enemy in enemy\_group:
enemy.ai()
enemy.update()
enemy.draw()
# 更新和绘制组
bullet\_group.update()
grenade\_group.update()
explosion\_group.update()
item\_box\_group.update()
decoration\_group.update()
water\_group.update()
exit\_group.update()
bullet\_group.draw(screen)
grenade\_group.draw(screen)
explosion\_group.draw(screen)
item\_box\_group.draw(screen)
decoration\_group.draw(screen)
water\_group.draw(screen)
exit\_group.draw(screen)
# 显示淡入
if start\_intro:
if intro\_fade.fade():
start\_intro = False
intro\_fade.fade\_counter = 0
# 更新玩家的动作
if player.alive:
# 发射子弹
if shoot:
player.shoot()
# 扔手雷
elif grenade and grenade\_thrown == False and player.grenades > 0:
grenade = Grenade(player.rect.centerx + (0.5 * player.rect.size[0] * player.direction),
player.rect.top, player.direction)
grenade\_group.add(grenade)
player.grenades -= 1
grenade\_thrown = True
if player.in\_air:
player.update\_action(2)
elif moving\_left or moving\_right:
player.update\_action(1)
else:
player.update\_action(0)
screen\_scroll, level\_complete = player.move(moving\_left, moving\_right)
bg\_scroll -= screen\_scroll
# 检测玩家是否已通过此级别,并为两位数列表的特定位置(一行中的一列)分配一个值。
if level\_complete:
start\_intro = True
level += 1
bg\_scroll = 0
world\_data = reset\_level()
if level <= MAX\_LEVELS:
# 负荷水平数据创建图
with open(f"level{level}\_data.csv", newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",")
for y, row in enumerate(reader):
for x, tile in enumerate(row):
world\_data[y][x] = int(tile)
world = World()
player, health\_bar = world.process\_data(world\_data)
else:
screen\_scroll = 0
if death\_fade.fade(): # 在覆盖完成之前,按钮中间转换不会出现
if restart\_button.draw(screen):
death\_fade.fade\_counter = 0 # 计数清零
start\_intro = True
bg\_scroll = 0
world\_data = reset\_level()
# 负荷水平数据创建图
with open(f"level{level}\_data.csv", newline="") as csvfile:
reader = csv.reader(csvfile, delimiter=",")
for y, row in enumerate(reader):
for x, tile in enumerate(row):
world\_data[y][x] = int(tile)
world = World()
player, health\_bar = world.process\_data(world\_data)
for event in pygame.event.get():
退出游戏
if event.type == pygame.QUIT:
run = False
pygame.quit()
sys.exit()
# 键盘按键
if event.type == pygame.KEYDOWN:
if event.key == pygame.K\_a:
moving\_left = True
if event.key == pygame.K\_d:
moving\_right = True
if event.key == pygame.K\_SPACE:
shoot = True
if event.key == pygame.K\_q:
grenade = True
if event.key == pygame.K\_w and player.alive:
player.jump = True
jump\_fx.play()
if event.key == pygame.K\_ESCAPE:
run = False
# 按键释放
if event.type == pygame.KEYUP:
if event.key == pygame.K\_a:
moving\_left = False
if event.key == pygame.K\_d:
moving\_right = False
if event.key == pygame.K\_SPACE:
shoot = False
if event.key == pygame.K\_q:
grenade = False
grenade\_thrown = False
pygame.display.update()
部分游戏截图:
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除