#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
, что предоставляемый метод переопределяет метод суперклассов и должен вызывать его либо до, либо после того, как он сделает все остальное?