您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“Python如何實(shí)現(xiàn)射擊闖關(guān)游戲”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Python如何實(shí)現(xiàn)射擊闖關(guān)游戲”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
地圖編輯器:可以實(shí)現(xiàn)玩家自己定義每一關(guān)卡的樣式和難易程度
運(yùn)行界面:實(shí)現(xiàn)了玩家的移動,跳躍,發(fā)射子彈,投擲手雷,以及敵人的AL(移動,發(fā)射子彈,扔手雷),同時(shí)游戲中有一系列的道具(生命值藥箱,子彈補(bǔ)給,手雷補(bǔ)給)以及各種動畫和音樂音效,還有各種花草巖石裝飾品,以及懸崖和水渦危險(xiǎn)地方,更多未知,自己體驗(yàn)就能感受到!
總代碼累計(jì)1100行左右!
import pygame import sys import csv import button pygame.init() # 定義一個(gè)時(shí)鐘 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) # 創(chuàng)建保存按鈕 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) # 創(chuàng)建空的瓷磚列表(二維) world_data = [] for row in range(ROWS): r = [-1] * MAX_COLS world_data.append(r) # 創(chuàng)建一個(gè)組 for tile in range(0, MAX_COLS): world_data[ROWS - 1][tile] = 0 # 在屏幕上顯示下一級定義文本顯示函數(shù) def draw_text(text, font, text_color, x, y): img = font.render(text, True, text_color) screen.blit(img, (x, y)) # 創(chuàng)建背景函數(shù) 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)) # 創(chuàng)建按鈕 # 創(chuàng)建保存和加載數(shù)據(jù)按鈕 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) # 制作一個(gè)按鈕瓷片列表 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) # 保存和加載地圖數(shù)據(jù) if save_button.draw(screen): # 保存級別數(shù)據(jù) 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): # 加載地圖級別數(shù)據(jù) # 重置滾動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)) # 選擇一種瓷磚,獲取右側(cè)瓷磚列表的具體 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 # 在窗口中增加新的瓷磚 # 獲取鼠標(biāo)的位置 pos = pygame.mouse.get_pos() x = (pos[0] + scroll) // TILE_SIZE y = pos[1] // TILE_SIZE # 檢測點(diǎn)擊的區(qū)域,把右側(cè)獲取的瓷片放在地圖中 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("射擊游戲") # 設(shè)置幀 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 # 定義游戲狀態(tài) start_game = False # 定義是否淡入進(jìn)入游戲畫面 start_intro = False # 定義玩家狀態(tài)變量 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) # 定義一個(gè)顯示文本函數(shù),用來顯示玩家的相關(guān)屬性 def draw_text(text, font, text_color, x, y): img = font.render(text, True, text_color) screen.blit(img, (x, y)) # 刷新背景函數(shù),for循環(huán)重復(fù)背景,刷新背景中不同的照片的x坐標(biāo),以此達(dá)到背景動態(tài)效果 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())) # 重置游戲函數(shù)定義,碰撞”通關(guān)“瓷片時(shí),清空本關(guān)的所有顯示元素 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() # 創(chuàng)建空的瓷磚列表。二維列表行列 data = [] for row in range(ROWS): r = [-1] * COLS data.append(r) return data # 創(chuàng)建士兵類(敵人和玩家) 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 # 默認(rèn)方向右 self.vel_y = 0 # 垂直 self.jump = False # 跳躍 self.in_air = True # 是否在空中 self.flip = False # 默認(rèn)左為false self.animation_list = [] # 動畫列表 self.frame_index = 0 # 索引 self.action = 0 # 選擇動作變量 self.update_time = pygame.time.get_ticks() # 以毫秒為單位獲取時(shí)間 # 創(chuàng)建AI特定變量 self.move_counter = 0 # 移動計(jì)數(shù),對應(yīng)下文敵人來回徘徊 self.vision = pygame.Rect(0, 0, 150, 20) # 搜索玩家在玩家視線之內(nèi) self.idling = False # 閑置狀態(tài),對應(yīng)下文AI開槍和扔手雷的狀態(tài) self.idling_counter = 0 # 閑置計(jì)數(shù) self.grenade_time = pygame.time.get_ticks() # 對應(yīng)下文手雷爆炸時(shí)間 # 加載玩家是所有的圖片類型 animation_types = ["Idle", "Run", "Jump", "Death"] for animation in animation_types: # 重置臨時(shí)列表 temp_list = [] # 統(tǒng)計(jì)每種動畫幀數(shù)量 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() # 更新冷卻時(shí)間 if self.shoot_cooldown > 0: self.shoot_cooldown -= 1 def move(self, moving_left, moving_right): # 重置移動變量 screen_scroll = 0 dx = 0 dy = 0 # 根據(jù)移動變量判斷向左還是向右移動 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方向跳躍高度進(jìn)行限制 self.vel_y += GRAVITY if self.vel_y > 10: self.vel_y dy += self.vel_y # 檢測與地面的碰撞 for tile in world.obstacle_list: # 檢測玩家與每個(gè)地面瓷磚x方向上的碰撞 if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 # 檢測如果是ai機(jī)器人碰到墻就返回 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 # 檢車與出口標(biāo)志碰撞 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 # 在玩家位置的基礎(chǔ)上更新滾動平臺 rect.right 對應(yīng)矩形的左,以此類推 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): # 停止奔跑并面向玩家的時(shí)候 self.update_action(0) # 并射擊 self.shoot() else: # 不定時(shí)扔手雷 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): # 停止奔跑并面向玩家的時(shí)候 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) # 選擇運(yùn)動動作 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 # 更新當(dāng)前的幀 self.image = self.animation_list[self.action][self.frame_index] # 檢測現(xiàn)在的時(shí)間更新時(shí)間 if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 # 檢測如果列表索引超出了動畫幀數(shù) 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 # 更新動畫設(shè)置 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() # 創(chuàng)建血條類 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 # 計(jì)算血條的比率 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() # 創(chuàng)建手雷 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 # 檢測手雷與每個(gè)瓷磚的碰撞 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 # 手雷爆炸冷卻時(shí)間 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) # 爆炸后對任何人在一定的范圍內(nèi)都有傷害 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 # 創(chuàng)建地圖的類 class World(): def __init__(self): self.obstacle_list = [] # 障礙列表 def process_data(self, data1): self.level_length = len(data1[0]) # 迭代加載數(shù)據(jù)的每個(gè)值 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: # 創(chuàng)建玩家自己 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: # 創(chuàng)建敵人 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: # 收集醫(yī)藥 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 # 創(chuàng)建水類 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 # 創(chuàng)建出口 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 # 創(chuàng)建爆炸類 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 # 創(chuàng)建淡入淡出 intro_fade = ScreenFade(1, BLACK, 4) death_fade = ScreenFade(2, PINK, 4) #創(chuàng)建開始、退出、重置菜單按鈕 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) #創(chuàng)建群組 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() # 創(chuàng)建空的瓷磚列表 world_data = [] for row in range(ROWS): r = [-1] * COLS world_data.append(r) # 加載級別數(shù)據(jù)創(chuàng)建地圖 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: # 發(fā)射子彈 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: # 加載級別數(shù)據(jù)創(chuàng)建地圖 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(): # 完成覆蓋后才出現(xiàn)按鈕中間時(shí)間過渡 if restart_button.draw(screen): death_fade.fade_counter = 0 # 計(jì)數(shù)清零 start_intro = True bg_scroll = 0 world_data = reset_level() # 加載級別數(shù)據(jù)創(chuàng)建地圖 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()
讀到這里,這篇“Python如何實(shí)現(xiàn)射擊闖關(guān)游戲”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點(diǎn)還需要大家自己動手實(shí)踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。