Я работал над маленькой игрой в пигаме. С помощью некоторых участников сообщества я смог запустить игру, и все работает отлично. я могу запустить его на pycharm и, как я уже сказал, все работает отлично, уровни загружаются, враги тоже. столкновение так и должно быть. Но вот моя проблема: после использования pyinstaller, чтобы изменить игру с py-файла на exe-файл, он не будет загружать ни один уровень, кроме первого. Игра работает нормально, вы можете играть на первом уровне, но как только второй уровень должен начаться, он вылетает. Сообщение об ошибке говорит, что «не может загрузить внешний набор тайлов». Путь к файлу, который он показывает в этом сообщении об ошибке, - полная ерунда, я попытался изменить источник img в файле tsx, но это не сработало. Неважно, где я сохраняю свои активы карты тайлов и какой путь я не указал в исходном коде img, я просто не могу заставить его загружать больше, чем начальный уровень
, вот код main.py и карта тайлов. код py для моей игры:
main.py
import pygame as pg
import sys
from os import path
from settings import *
from sprites import *
from tilemap import *
# HUD functions
def draw_player_health(surf, x, y, pct):
if pct < 0:
pct = 0
BAR_LENGTH = 100
BAR_HEIGHT = 20
fill = pct * BAR_LENGTH
outline_rect = pg.Rect(x, y, BAR_LENGTH, BAR_HEIGHT)
fill_rect = pg.Rect(x, y, fill, BAR_HEIGHT)
if pct > 0.6:
col = GREEN
elif pct > 0.3:
col = YELLOW
else:
col = RED
pg.draw.rect(surf, col, fill_rect)
pg.draw.rect(surf, BLACK, outline_rect, 2)
class Game:
def __init__(self):
pg.mixer.pre_init(44100, -16, 2, 2048)
pg.init()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.load_data()
self.current_level = 1
def draw_text(self, text, font_name, size, color, x, y, align="nw"):
font = pg.font.Font(font_name, size)
text_surface = font.render(text, True, color)
text_rect = text_surface.get_rect()
if align == "nw":
text_rect.topleft = (x, y)
if align == "ne":
text_rect.topright = (x, y)
if align == "sw":
text_rect.bottomleft = (x, y)
if align == "se":
text_rect.bottomright = (x, y)
if align == "n":
text_rect.midtop = (x, y)
if align == "s":
text_rect.midbottom = (x, y)
if align == "e":
text_rect.midright = (x, y)
if align == "w":
text_rect.midleft = (x, y)
if align == "center":
text_rect.center = (x, y)
self.screen.blit(text_surface, text_rect)
def load_data(self):
game_folder = path.dirname(__file__)
img_folder = path.join(game_folder, "img")
self.map_folder = path.join(game_folder, "maps")
sfx_folder = path.join(game_folder, "sfx")
music_folder = path.join(game_folder, "music")
self.title_font = path.join(img_folder, "ZOMBIE.TTF")
self.hud_font = path.join(img_folder, "Impacted2.0.ttf")
self.dim_screen = pg.Surface(self.screen.get_size()).convert_alpha()
self.dim_screen.fill((0, 0, 0, 180))
self.player_img = pg.image.load(path.join(img_folder, PLAYER_IMG)).convert_alpha()
self.mob_img = pg.image.load(path.join(img_folder, MOB_IMG)).convert_alpha()
self.wall_img = pg.image.load(path.join(img_folder, WALL_IMG)).convert_alpha()
self.wall_img = pg.transform.scale(self.wall_img, (TILESIZE, TILESIZE))
self.bullet_images = {}
self.bullet_images["lg"] = pg.image.load(path.join(img_folder, BULLET_IMG)).convert_alpha()
self.bullet_images["sm"] = pg.transform.scale(self.bullet_images["lg"], (10, 10))
self.splat = pg.image.load(path.join(img_folder, SPLAT)).convert_alpha()
self.splat = pg.transform.scale(self.splat, (64, 64))
self.gun_flashes = []
for img in MUZZLE_FLASHES:
self.gun_flashes.append(pg.image.load(path.join(img_folder, img)).convert_alpha())
self.item_images = {}
for item in ITEM_IMAGES:
self.item_images[item] = pg.image.load(path.join(img_folder, ITEM_IMAGES[item])).convert_alpha()
# lighting effect
self.fog = pg.Surface((WIDTH, HEIGHT))
self.fog.fill(NIGHT_COLOR)
self.light_mask = pg.image.load(path.join(img_folder, LIGHT_MASK)).convert_alpha()
self.light_mask = pg.transform.scale(self.light_mask, LIGHT_RADIUS)
self.light_rect = self.light_mask.get_rect()
# SOUND LOADING
pg.mixer.music.load(path.join(music_folder, BG_MUSIC))
self.effects_sounds = {}
for type in EFFECTS_SOUNDS:
self.effects_sounds[type] = pg.mixer.Sound(path.join(sfx_folder, EFFECTS_SOUNDS[type]))
self.weapon_sounds = {}
for weapon in WEAPON_SOUNDS:
self.weapon_sounds[weapon] = []
for sfx in WEAPON_SOUNDS[weapon]:
s = pg.mixer.Sound(path.join(sfx_folder, sfx))
s.set_volume(0.2)
self.weapon_sounds[weapon].append(s)
self.zombie_moan_sounds = []
for sfx in ZOMBIE_MOAN_SOUNDS:
s = pg.mixer.Sound(path.join(sfx_folder, sfx))
s.set_volume(0.2)
self.zombie_moan_sounds.append(s)
self.player_hit_sounds = []
for sfx in PLAYER_HIT_SOUNDS:
self.player_hit_sounds.append(pg.mixer.Sound(path.join(sfx_folder, sfx)))
self.zombie_hit_sounds = []
for sfx in ZOMBIE_HIT_SOUNDS:
self.zombie_hit_sounds.append(pg.mixer.Sound(path.join(sfx_folder, sfx)))
def new(self):
# initialize all variables and do all the setup for a new game
self.all_sprites = pg.sprite.LayeredUpdates()
self.walls = pg.sprite.Group()
self.bullets = pg.sprite.Group()
self.mobs = pg.sprite.Group()
self.items = pg.sprite.Group()
self.map = Tiled_Map(path.join(self.map_folder, 'level1.tmx'))
self.map_image = self.map.make_map()
self.map_rect = self.map_image.get_rect()
# for row, tiles in enumerate(self.map.data):
# for col, tile in enumerate(tiles):
# if tile == '1':
# Wall(self, col, row)
# if tile == 'M':
# Mob(self, col, row)
# if tile == 'P':
# self.player = Player(self, col, row)
for tile_object in self.map.tmxdata.objects:
obj_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2)
if tile_object.name == "player":
self.player = Player(self, obj_center.x, obj_center.y)
if tile_object.name == "zombie":
Mob(self, obj_center.x, obj_center.y)
if tile_object.name == "wall":
Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height)
if tile_object.name in ["health", "shotgun", "m_gun", "desert_eagle"]:
Item(self, obj_center, tile_object.name)
self.camera = Camera(self.map.width, self.map.height)
self.draw_debug = False
self.paused = False
self.night = False
self.effects_sounds["level_start"].play()
def new_2(self):
# initialize all variables and do all the setup for a new game
self.all_sprites = pg.sprite.LayeredUpdates()
self.walls = pg.sprite.Group()
self.bullets = pg.sprite.Group()
self.mobs = pg.sprite.Group()
self.items = pg.sprite.Group()
self.map = Tiled_Map(path.join(self.map_folder, 'level2.tmx'))
self.map_image = self.map.make_map()
self.map_rect = self.map_image.get_rect()
# for row, tiles in enumerate(self.map.data):
# for col, tile in enumerate(tiles):
# if tile == '1':
# Wall(self, col, row)
# if tile == 'M':
# Mob(self, col, row)
# if tile == 'P':
# self.player = Player(self, col, row)
for tile_object in self.map.tmxdata.objects:
obj_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2)
if tile_object.name == "player":
self.player = Player(self, obj_center.x, obj_center.y)
if tile_object.name == "zombie":
Mob(self, obj_center.x, obj_center.y)
if tile_object.name == "wall":
Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height)
if tile_object.name in ["health", "shotgun", "m_gun", "desert_eagle"]:
Item(self, obj_center, tile_object.name)
self.camera = Camera(self.map.width, self.map.height)
self.draw_debug = False
self.paused = False
self.night = False
self.effects_sounds["level_start"].play()
def new_3(self):
# initialize all variables and do all the setup for a new game
self.all_sprites = pg.sprite.LayeredUpdates()
self.walls = pg.sprite.Group()
self.bullets = pg.sprite.Group()
self.mobs = pg.sprite.Group()
self.items = pg.sprite.Group()
self.map = Tiled_Map(path.join(self.map_folder, 'level3.tmx'))
self.map_image = self.map.make_map()
self.map_rect = self.map_image.get_rect()
# for row, tiles in enumerate(self.map.data):
# for col, tile in enumerate(tiles):
# if tile == '1':
# Wall(self, col, row)
# if tile == 'M':
# Mob(self, col, row)
# if tile == 'P':
# self.player = Player(self, col, row)
for tile_object in self.map.tmxdata.objects:
obj_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2)
if tile_object.name == "player":
self.player = Player(self, obj_center.x, obj_center.y)
if tile_object.name == "zombie":
Mob(self, obj_center.x, obj_center.y)
if tile_object.name == "wall":
Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height)
if tile_object.name in ["health", "shotgun", "m_gun", "desert_eagle"]:
Item(self, obj_center, tile_object.name)
self.camera = Camera(self.map.width, self.map.height)
self.draw_debug = False
self.paused = False
self.night = False
self.effects_sounds["level_start"].play()
def run(self):
# game loop - set self.playing = False to end the game
self.playing = True
pg.mixer.music.play(loops=-1)
while self.playing:
self.dt = self.clock.tick(FPS) / 1000.0 # fix for Python 2.x
self.events()
if not self.paused:
self.update()
self.draw()
def quit(self):
pg.quit()
sys.exit()
def update(self):
# Game over?
if len(self.mobs) == 0:
self.current_level += 1
if self.current_level == 2:
self.new_2()
else:
self.new_3()
# update portion of the game loop
self.all_sprites.update()
self.camera.update(self.player)
# player hits item
hits = pg.sprite.spritecollide(self.player, self.items, False, collide_hit_rect)
for hit in hits:
if hit.type == "health" and self.player.health < PLAYER_HEALTH:
hit.kill()
self.effects_sounds["health_up"].play()
self.player.add_health(HEALTH_PACK_AMOUNT)
if hit.type == "shotgun":
hit.kill()
self.player.weapon = "shotgun"
self.effects_sounds["gun_pickup"].play()
if hit.type == "m_gun":
hit.kill()
self.player.weapon = "m_gun"
self.effects_sounds["gun_pickup"].play()
if hit.type == "desert_eagle":
hit.kill()
self.player.weapon = "desert_eagle"
self.effects_sounds["gun_pickup"].play()
# mobs hit player
hits = pg.sprite.spritecollide(self.player, self.mobs, False, collide_hit_rect)
for hit in hits:
if random() < 0.7:
choice(self.player_hit_sounds).play()
self.player.health -= MOB_DAMAGE
hit.vel = vec(0, 0)
if self.player.health <= 0:
self.playing = False
if hits:
self.player.hit()
self.player.pos += vec(MOB_KNOCKBACK, 0).rotate(-hits[0].rot)
# bullet hit mobs
hits = pg.sprite.groupcollide(self.mobs, self.bullets, False, True)
for mob in hits:
# hit.health -= WEAPONS[self.player.weapon]["damage"] * len(hits[hit])
for bullet in hits[mob]:
mob.health -= bullet.damage
mob.vel = vec(0, 0)
def draw_grid(self):
for x in range(0, WIDTH, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT))
for y in range(0, HEIGHT, TILESIZE):
pg.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y))
def render_fog(self):
# draw the light mask (gradient) onto the fog image
self.fog.fill(NIGHT_COLOR)
self.light_rect.center = self.camera.apply(self.player).center
self.fog.blit(self.light_mask, self.light_rect)
self.screen.blit(self.fog, (0, 0), special_flags=pg.BLEND_MULT)
def draw(self):
pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
# self.screen.fill(BGCOLOR)
self.screen.blit(self.map_image, self.camera.apply_rect(self.map_rect))
# self.draw_grid()
for sprite in self.all_sprites:
if isinstance(sprite, Mob):
sprite.draw_health()
self.screen.blit(sprite.image, self.camera.apply(sprite))
if self.draw_debug:
pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(sprite.rect), 1)
if self.draw_debug:
for wall in self.walls:
pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(wall.rect), 1)
# pg.draw.rect(self.screen, WHITE, self.player.hit_rect, 2)
if self.night:
self.render_fog()
# HUD functions
draw_player_health(self.screen, 10, 10, self.player.health / PLAYER_HEALTH)
self.draw_text("Zombies: {}".format(len(self.mobs)), self.hud_font,
30, WHITE, WIDTH - 10, 10, align="ne")
if self.paused:
self.screen.blit(self.dim_screen, (0, 0))
self.draw_text("PAUSED", self.title_font, 105, RED, WIDTH / 2, HEIGHT / 2, align="center")
pg.display.flip()
def events(self):
# catch all events here
for event in pg.event.get():
if event.type == pg.QUIT:
self.quit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
self.quit()
if event.key == pg.K_h:
self.draw_debug = not self.draw_debug
if event.key == pg.K_p:
self.paused = not self.paused
if event.key == pg.K_n:
self.night = not self.night
def show_start_screen(self):
self.screen.fill(BLACK)
self.screen.blit(background, (0, 0))
# self.draw_text(TITLE, self.title_font, 100,
# RED, WIDTH / 2, HEIGHT * 1 / 4, align="center")
# vself.draw_text("Press a key to start", self.title_font, 75, WHITE, WIDTH / 2, HEIGHT * 3 / 4, align="center")
pg.display.flip()
self.wait_for_key()
def show_go_screen(self):
self.screen.fill(BLACK)
self.draw_text("GAME OVER", self.title_font, 100,
RED, WIDTH / 2, HEIGHT / 2, align="center")
self.draw_text("Press a key to start", self.title_font, 75, WHITE, WIDTH / 2, HEIGHT * 3 / 4, align="center")
pg.display.flip()
self.wait_for_key()
def wait_for_key(self):
pg.event.wait()
waiting = True
while waiting:
self.clock.tick(FPS)
for event in pg.event.get():
if event.type == pg.QUIT:
waiting = False
self.quit()
if event.type == pg.KEYUP:
waiting = False
# create the game object
background = pg.image.load("start_screen.png")
g = Game()
g.show_start_screen()
while True:
g.new()
g.run()
g.show_go_screen()
tilemap.py
import pygame as pg
from settings import *
import pytmx
def collide_hit_rect(one, two):
return one.hit_rect.colliderect(two.rect)
class Map:
def __init__(self, filename):
self.data = []
with open(filename, 'rt') as f:
for line in f:
self.data.append(line.strip())
self.tilewidth = len(self.data[0])
self.tileheight = len(self.data)
self.width = self.tilewidth * TILESIZE
self.height = self.tileheight * TILESIZE
class Tiled_Map:
def __init__(self, filename):
tm = pytmx.load_pygame(filename, pixelalpha=True)
self.width = tm.width * tm.tilewidth
self.height = tm.height * tm.tileheight
self.tmxdata = tm
def render(self, surface):
ti = self.tmxdata.get_tile_image_by_gid
for layer in self.tmxdata.visible_layers:
if isinstance(layer, pytmx.TiledTileLayer):
for x, y, gid, in layer:
tile = ti(gid)
if tile:
surface.blit(tile, (x * self.tmxdata.tilewidth, y * self.tmxdata.tileheight))
def make_map(self):
temp_surface = pg.Surface((self.width, self.height))
self.render(temp_surface)
return temp_surface
и вот сообщение об ошибке: ![enter image description here](https://i.stack.imgur.com/aswsf.png)
Любая помощь здесь будет высоко ценится