Pygame TypeError: аргумент join () должен быть объектом str, bytes или os.PathLike, а не «Surface» - PullRequest
1 голос
/ 29 марта 2020

Я учил Python только пару недель, и эта проблема поставила меня в тупик. Я пытаюсь создать простую игру в стиле Tower Defense, используя Pygame. Занимался поиском и поиском более 4 часов (на момент публикации веб-сайт Pygame Docs не работал, полагаясь на кэшированную версию). Я уверен, что это в конечном итоге будет легко исправить, но у меня нет идей.

У меня есть класс Tower в одном файле, а основная игра l oop в другом файле. Файлы изображений хранятся в папке с именем «assets», которая находится в том же каталоге, что и класс tower и основная игра l oop. Когда я пытаюсь создать новую башню, в частности загрузить изображение башни, я получаю сообщение об ошибке, указанное в заголовке.

Я понимаю, что каким-то образом передаю «Поверхность» в качестве параметра, но не могу для жизнь меня понять, где это. У меня есть игрок, выбирающий тип башни, которую он строит, используя клавиши 1 или 2, затем ищите соответствующее изображение для этого нажатия клавиши, затем помещайте башню там, где они щелкают по экрану. Оператор print сразу после события pygame для щелчка мыши правильно указывает «elf_tower.png» в качестве имени файла, но оператор печати в init класса говорит «». Класс работает нормально, если я жестко закодирую имя файла для изображения, но я сомневаюсь, что это лучшее решение. Я также попытался установить переменную равной «assets /» + tower_type, но он также сказал, что не может объединить Surface с str.

Основной файл:

"""Homebrew tower defense game using pygame and object oriented programming.
This is a learning project"""
import pygame
from tower import Tower
from scaling import get_scaling_info

get_scaling_info()

def run_game():
    """Runs the game"""
    pygame.init()
    get_scaling_info()
    width, height = get_scaling_info()[1:]
    screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN, 32)
    pygame.display.set_caption("Tower Defense")
    game_surface = screen.copy()

    def toggle_fullscreen():
        """Toggles between fullscreen and windowed mode"""
        if screen.get_flags() & pygame.FULLSCREEN:
            return pygame.display.set_mode((800, 600), pygame.RESIZABLE)
        return pygame.display.set_mode((width, height), pygame.FULLSCREEN)

    def update_display():
        """Update the game display"""
        scaling_info = get_scaling_info()[0]
        screen.fill((0, 0, 0))
        for tower in Tower.towers:
            tower.draw()
        screen.blit(pygame.transform.scale(
            game_surface, (scaling_info.current_w, scaling_info.current_h)), (0, 0))
        pygame.display.update()

    run = True
    tower_type = 0
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    run = False
                if event.key == pygame.K_F11:
                    toggle_fullscreen()
                if event.key == pygame.K_1 or event.key == pygame.K_2:
                    tower_type = Tower.selection_dict[event.key]
            if event.type == pygame.MOUSEBUTTONDOWN and tower_type != 0: #to prevent game from breaking if no tower selected.
                print(tower_type) #returns elf_tower.png which is the expected result
                mouse_x, mouse_y = pygame.mouse.get_pos()
                Tower(tower_type, mouse_x, mouse_y).create_tower()

        update_display()

    pygame.quit()

run_game()

Класс Tower file:

"""Contains the class used to generate towers"""
import os
import pygame
from scaling import get_scaling_info

get_scaling_info()

class Tower:
    """Tower information"""
    selection_dict = {49:"elf_tower.png", 50:"dwarf_tower.png"} #pygame keypress of 1 corresponds to value 49, 2 to 50.
    towers = []
    def __init__(self, img, x, y, display_surface="game_surface"):
        x_scale, y_scale = get_scaling_info()[1:]
        self.img = pygame.image.load(os.path.join('assets', img))
        print(self.img) # returns <Surface(40x40x32 SW)>
        self.x_coord = x * x_scale
        self.y_coord = y * y_scale
        self.display_surface = display_surface

    def create_tower(self):
        """Creates a tower of the selected type and scales to the correct size"""
        Tower.towers.append(Tower(self.img, self.x_coord, self.y_coord))
        print(Tower.towers)

    def draw(self):
        """Draws the tower on the screen using the specified image at coordinates x and y"""
        pygame.transform.scale(self.img, (32, 32))
        self.display_surface.blit(self.img, (self.x_coord, self.y_coord))
        print(self.img)

 #   def attack(self):
 #       """Causes the tower to attack enemies in range
 #       Not yet written"""

Файл масштабирования изображения

"""Gets the scaling info used in the other modules of the game"""
import pygame

def get_scaling_info():
    """Gathers display info for scaling elements of the game"""
    pygame.init()
    display_info = pygame.display.Info()
    scaling_info = pygame.display.Info()
    x_ratio = display_info.current_w/scaling_info.current_w
    y_ratio = display_info.current_h/scaling_info.current_h
    return scaling_info, x_ratio, y_ratio

1 Ответ

1 голос
/ 29 марта 2020

Вы смотрите на неправильную Tower конструкцию (т.е. в run_game); проблема на самом деле возникает в строке

Tower.towers.append(Tower(self.img, self.x_coord, self.y_coord))

в методе create_tower, где вы создаете новый Tower, используя self.img в качестве первого аргумента. В __init__ self.img инициализируется в pygame.image.load(os.path.join('assets', img)), что возвращает Surface.

Вероятно, вы хотите сохранить аргумент img, с помощью которого Tower был создан как другой экземпляр атрибут, затем используйте его в методе create_tower, например:

class Tower:
    """Tower information"""
    selection_dict = {49:"elf_tower.png", 50:"dwarf_tower.png"} #pygame keypress of 1 corresponds to value 49, 2 to 50.
    towers = []
    def __init__(self, img, x, y, display_surface="game_surface"):
        x_scale, y_scale = get_scaling_info()[1:]
        self.img_file = img
        self.img = pygame.image.load(os.path.join('assets', self.img_file))
        print(self.img) # returns <Surface(40x40x32 SW)>
        self.x_coord = x * x_scale
        self.y_coord = y * y_scale
        self.display_surface = display_surface

    def create_tower(self):
        """Creates a tower of the selected type and scales to the correct size"""
        Tower.towers.append(Tower(self.img_file, self.x_coord, self.y_coord))
        print(Tower.towers)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...