Проблемы с игрой

#python #game-development

Вопрос:

Я молодой программист на Python. Я решил создать 2D-игру, используя pygame Цель игры: проехать как можно большее расстояние на автомобиле, не врезавшись в объекты, которые будут «появляться» во время игры. Машина проедет по полю.

У меня проблемы со спрайтами оформления (во время игры деревья будут «падать» вниз по краям окна) Рис.1. рис. 1

Итак, деревья должны появляться сразу после того, как предыдущие достигнут середины окна, но когда появляются новые деревья, со мной происходит вот что: рис. 2. И игра начинает зависать рис2

Вот мой код:

 from superwires import games, color
from random import randrange
games.init(screen_width = 530, screen_height = 600, fps = 60)

#Car sprite

class Car(games.Sprite):
    image = games.load_image("C:/python/car.bmp")
    def __init__(self):
        super(Car, self).__init__(image = Car.image,
                                  x = games.mouse.x,
                                  bottom = games.screen.height - 10)
        self.score = games.Text(value = 0, size = 25, color = color.yellow,
                                top = 5, right = games.screen.width/2)
        games.screen.add(self.score)
    def update(self):
        self.x = games.mouse.x
        if self.left < 65:
            self.left = 65
        if self.right > games.screen.width - 65:
            self.right = games.screen.width - 65

#Tree sprite

class Bush1(games.Sprite):
    image = games.load_image("C:/python/bush.bmp")
    speed = 1
    def __init__(self, x = 20, y = 100):
        super(Bush1, self).__init__(image = Bush1.image,
                                   x = x, y = y,
                                   dy = Bush1.speed)
    def update(self):
        if self.bottom > games.screen.height/2:
            newbush = Bush1()
            newbush.__init__(x = 20, y = -100)
            games.screen.add(newbush)

class Bush2(games.Sprite):
    image = games.load_image("C:/python/bush.bmp")
    speed = 1
    def __init__(self, x = 515, y = 100):
        super(Bush2, self).__init__(image = Bush2.image,
                                   x = x, y = y,
                                   dy = Bush2.speed)

    #Spawning new trees

    def update(self):
        if self.bottom > games.screen.height/2:
            newbush = Bush2()
            newbush.__init__(x = 515, y = -100)
            games.screen.add(newbush)

#Start
def main(): 
    road = games.load_image("road.jpg", transparent = False)
    games.screen.background = road
    bush1 = Bush1()
    bush2 = Bush2()
    car = Car()
    games.screen.add(bush1)
    games.screen.add(bush2)
    games.screen.add(car)
    games.mouse.is_visible = False
    games.screen.event_grab = True
    games.screen.mainloop()

main()
 

Я буду рад узнать, где я допустил ошибку.

Используется: Python 3.9, сверхпроводники, игры

Комментарии:

1. Вы получаете какие-либо ошибки, выводимые в другом месте? Кроме того, это похоже Bush1 и Bush2 является одним и тем же классом, и что вы используете __init__ в своем update методе странным образом. __init__ вызывается при создании экземпляра нового объекта — прямой вызов может привести к неожиданным результатам. Аналогичным образом, поскольку эти классы зависят от games того, находятся ли они в глобальной области, у вас могут возникнуть проблемы со ссылками — их отсутствие или их перезапись.

2. @NathanielFord я нигде не получаю никаких ошибок, просто вещи в pic2

3. Я не вижу никакой разницы между этими двумя изображениями.

4. Автоматически вызывается создание нового объекта __init__ . Ты должен этим заниматься newbush = Bush2(x=515, y=-100) . И, поскольку это значения по умолчанию, вам вообще не нужно их указывать.

5. @TimRoberts проверьте фотографии еще раз, пожалуйста

Ответ №1:

Вот в чем твоя проблема. Как только ваш первый куст достигнет середины, вы создадите два новых куста НА КАЖДОМ КАДРЕ. Это то, что вы видите на своем рис. 2-у вас есть сотни слегка перекрывающихся кустов. Вам нужно создать новый куст только тогда, когда старый находится ТОЧНО на полпути, а не НА полпути ИЛИ НИЖЕ нее:

     if self.bottom == games.screen.height//2:
 

Вы также можете рассмотреть возможность удаления кустов, как только они упадут со дна

Комментарии:

1. Это именно так — из-за этого полностью произойдет ошибочный вывод, а также замораживание.

2. @NathanielFord Я попробовал ваш код выше. Я получаю ошибку при «обновлении» метода класса «Куст»: «newbush = Куст(self.__image», «self.__image = games.load_image(изображение)» «изображение = pygame.image.load(имя файла) Ошибка типа: не файловый объект

3. Это не похоже на код Натаниэля. Вероятно, вам пора задать новый вопрос.

Ответ №2:

Это может не решить конкретную проблему, с которой вы столкнулись, но это может помочь распаковать вещи и сосредоточиться на том, что происходит.

Здесь вы создаете новый Bush1 и Bush2 объект:

 bush1 = Bush1()
bush2 = Bush2()
 

Обратите внимание, что код для этих двух классов практически идентичен. Различия заключаются только в значениях по init умолчанию. Это равносильно тому, чтобы сделать это:

 bush1 = Bush1()
bush2 = Bush1(515, 100)
 

Похоже, у вас есть недопонимание, основанное на этом, о том, как работают классы в Python. Это подкрепляется двумя почти равнозначными, но постоянными update блоками:

     def update(self):
        if self.bottom > games.screen.height/2:
            newbush = Bush1()
            newbush.__init__(x = 20, y = -100)
            games.screen.add(newbush)
 

В третьей строке этих блоков вы создаете новый объект. Затем вы повторно вызываете этот __init__ метод объектов. При создании нового объекта запускается несколько скрытых «частных» методов, последним из которых является __init__ метод. Обычно, если вам нужно создать экземпляр объекта для изменения, вы должны изменить этот метод. Вам никогда не понадобится повторно вызывать этот метод.

Наконец, насколько я могу судить, вы на самом деле не двигаете кусты. Я подозреваю, что, когда вы говорите «начинает замерзать», происходит то, что у вас много экземпляров кустов, перекрывающих друг друга, и игра занимает все больше и больше времени для обработки каждого цикла. Включение инструкции print в каждый метод инициализации, вероятно, помогло бы выявить эту проблему, но, возможно, у ваших фреймворков может быть лучший способ сделать это. (Я с ними не знаком.)

Небольшой рефакторинг для правильной очистки использования классов и переменных области действия должен привести к чему-то в этом роде (хотя почти наверняка мы могли бы сделать больше).:

 from superwires import games, color
from random import randrange
games.init(screen_width = 530, screen_height = 600, fps = 60)

#Car sprite

class Car(games.Sprite):
    
    def __init__(self, image: str):
        self.__image = games.load_image(image)
        #  Is the car really instantiated at the point the mouse currently is at?
        super().__init__(image = self.__image,
                         x = games.mouse.x,
                         bottom = games.screen.height - 10)
        #  Is 'score' really a field of 'car'?
        self.score = games.Text(value = 0, 
                                size = 25, 
                                color = color.yellow,
                                top = 5, 
                                right = games.screen.width/2)
        games.screen.add(self.score)

    def update(self):
        self.x = games.mouse.x
        self.left = 65 if self.left < 65 else self.left
        # This should probably be defined in a broader scope
        max_right = games.screen.width - 65
        self.right = self.right if self.right <= max_right else max_right 


class Bush(games.Sprite):
    speed = 1
    def __init__(self, 
                 image: str 
                 x: int, 
                 y: int):
        self.__image = games.load_image(image)
        self.__start_x = x
        self.__start_y = y
        super().__init__(image = self.__image,
                         x = x, 
                         y = y,
                         dy = Bush.speed)

    def update(self):
        if self.bottom > games.screen.height/2:
            # uses the same initial values as this object
            newbush = Bush(self.__image, 
                           self.__start_x,
                           -100)  # start vertically above the screen
            games.screen.add(newbush)

#Start
def main(): 
    road = games.load_image("road.jpg", transparent = False)
    games.screen.background = road
    bush1 = Bush("C:/python/bush.bmp", 20, 100)
    bush2 = Bush("C:/python/bush.bmp", 515, 100)
    car = Car("C:/python/car.bmp")
    games.screen.add(bush1)
    games.screen.add(bush2)
    games.screen.add(car)
    games.mouse.is_visible = False
    games.screen.event_grab = True
    games.screen.mainloop()

main()
 

Комментарии:

1. К вашему сведению, спрайты автоматически перемещаются на каждом кадре из-за параметра «dy».

2. @TimRoberts Это имеет смысл. Есть ли вероятность update , что предоставляемый метод переопределяет метод суперклассов и должен вызывать его либо до, либо после того, как он сделает все остальное?