Черепаха Программа замедляется через некоторое время.Пробовал очищать экран и удалять но без эффекта - PullRequest
0 голосов
/ 25 сентября 2019
# set up the environment
wn = turtle.Screen()
wn.bgpic("space_invaders_background_new.gif")
turtle.fd(0)
turtle.speed(0)
turtle.bgcolor("black")
turtle.ht()
turtle.setundobuffer(None)
turtle.tracer(20,0)

# draw white boundaries around
class Game():   
    def draw_border(self):
        #Draw border
        self.pen = turtle.Turtle()
        self.pen.speed(0)
        self.pen.color("white")
        self.pen.pensize(0)
        self.pen.penup()
        self.pen.goto(-400, 400)
        self.pen.pendown()
        for side in range(4):
            self.pen.fd(800)
            self.pen.rt(90)
        self.pen.penup()
        self.pen.ht()

game = Game()
game.draw_border()

# player 1 and his actions

class Bullet(turtle.Turtle):
    def __init__(self):
        turtle.Turtle.__init__(self)
        self.hideturtle()
        self.shape("arrow")
        self.penup()
        self.speed(0)
        self.color("white")
        self.fd(0)
        self.goto(0, 0)

# player class
class Player(turtle.Turtle):
    def __init__(self, spriteshape, color, startx, starty):
        turtle.Turtle.__init__(self, shape = spriteshape)
        self.hideturtle()
        self.speed(0)
        self.penup()
        self.color(color)
        self.fd(0)
        self.goto(startx, starty)
        self.left(90)
        self.showturtle()

    def move(self):
        self.fd(10)
    def turn_left(self):
        self.lt(20)
    def turn_right(self):
        self.rt(20)
    def accelerate(self):
        self.move()

# Define Enemy1 class

class Enemy1(turtle.Turtle):

    a=[] # to store the bullets per enemy

    def __init__(self, spriteshape, color, startx, starty):
        turtle.Turtle.__init__(self, shape = "circle")
        self.hideturtle
        self.speed(0)
        self.penup()
        self.color(color)
        self.fd(0)
        self.setposition(startx, starty)

# function to invoked at firing frequency
    def enemy1_fire(self):
        x = self.xcor()
        y = self.ycor()
        bullet1 = Bullet()
        bullet1.setposition(x,y) # bullet will appear just above the player
        bullet1.setheading(270)
        bullet1.showturtle()
        self.a.append(bullet1)

num_Enemy1 = 1
enemies1 = []
for i in range(num_Enemy1): # design the enemies
    b = Enemy1("circle", "red", random.randint(-180,180), random.randint(-100,250))
    enemies1.append(b)

# Enemy1 class defined

player = Player("triangle", "white", 0, -390) # player declared

#key bindings
turtle.listen()
turtle.onkey(player.turn_left,"Left")
turtle.onkey(player.turn_right,"Right")
turtle.onkey(player.accelerate,"Up")
#turtle.onkey(player.brake,"Down")


# define the firing intervals
freq1 = 8

Как только участники игры определены, в основном игровом цикле я определяю условия движения и стрельбы.Я убираю черепах после того, как они исчезнут с экрана, думая, что следует избегать замедления, но не получил никаких улучшений при использовании clear.

# main game loop

while True:

    # enemy 1 loop

    for enemy1 in enemies1:
        enemy1.rt(10)
        enemy1.fd(10)
        freq1 = freq1 - 1
        if (freq1==0):
            enemy1.enemy1_fire()
            freq1 = 8


        for bullets in enemy1.a: # movement of each bullet defined
            y = bullets.ycor()
            y1 = y - 10
            bullets.sety(y1)

        for bullets in enemy1.a: # hide and delete bullets once they go off screen
            if (bullets.ycor()>390 or bullets.xcor()>390 or bullets.ycor()<-390 or bullets.xcor()<-390):
                bullets.hideturtle()
                bullets.clear() # should speed up the simulation
                del bullets # should speed up the simulation

delay = raw_input("Press enter to finish. > ")

Ответы [ 2 ]

1 голос
/ 25 сентября 2019

Вы относитесь к черепахам (под видом пуль) как к местным сущностям, которые собирают мусор, когда вы закончите с ними.Они не - они глобальные (из-за внутреннего списка черепах) и никогда не уходят.Вместо того, чтобы рассчитывать на сбор мусора, следите за ними и используйте их повторно.Вот доработка вашего кода, который использует этот подход:

from turtle import Screen, Turtle, mainloop
from random import randint

class Bullet(Turtle):
    def __init__(self):
        Turtle.__init__(self)
        self.hideturtle()
        self.setundobuffer(None)
        self.shape('arrow')
        self.speed('fastest')
        self.color('white')
        self.setheading(270)
        self.penup()

# player class
class Player(Turtle):
    def __init__(self, sprite_shape, color, startx, starty):
        Turtle.__init__(self, shape=sprite_shape)
        self.hideturtle()
        self.speed('fastest')
        self.color(color)
        self.penup()
        self.goto(startx, starty)
        self.left(90)
        self.showturtle()

        self.setundobuffer(None)

    def turn_left(self):
        self.left(20)

    def turn_right(self):
        self.right(20)

    def move(self):
        self.forward(10)

# Define Enemy class
class Enemy(Turtle):

    available_bullets = [] # to store the bullets

    def __init__(self, sprite_shape, color, startx, starty):
        Turtle.__init__(self, shape=sprite_shape)
        self.hideturtle()
        self.speed('fastest')
        self.color(color)
        self.penup()
        self.setposition(startx, starty)
        self.showturtle()

        self.bullets = []  # my outstanding fired bullets

    # function to invoked at firing frequency
    def enemy_fire(self):
        if Enemy.available_bullets:
            bullet = Enemy.available_bullets.pop()
        else:
            bullet = Bullet()

        bullet.setposition(self.position()) # bullet will appear just above the player
        bullet.showturtle()

        self.bullets.append(bullet)

# draw white boundaries
def draw_border():
    pen = Turtle()
    pen.hideturtle()
    pen.speed('fastest')
    pen.color('white')

    pen.penup()
    pen.goto(-400, 400)
    pen.pendown()

    for _ in range(4):
        pen.forward(800)
        pen.right(90)

# set up the environment
screen = Screen()
screen.setup(850, 850)
screen.bgcolor('black')

draw_border()

num_Enemy = 2
enemies = []
for _ in range(num_Enemy): # design the enemies
    enemy = Enemy('circle', 'red', randint(-180, 180), randint(-100, 250))
    enemies.append(enemy)

player = Player('triangle', 'white', 0, -390) # player declared

# key bindings
screen.onkey(player.turn_left, 'Left')
screen.onkey(player.turn_right, 'Right')
screen.onkey(player.move, 'Up')
screen.listen()

# define the firing intervals
frequency = 8

# main game loop
while True:

    for enemy in enemies:
        enemy.right(10)
        enemy.forward(10)

        if frequency == 0:
            enemy.enemy_fire()

        frequency = (frequency + 1) % 9

        dead_bullets = []

        for bullet in enemy.bullets: # movement of each bullet defined
            bullet.forward(10)

            if not -390 < bullet.ycor() < 390:
                bullet.hideturtle()
                dead_bullets.append(bullet)

        for bullet in dead_bullets:
            enemy.bullets.remove(bullet)
            Enemy.available_bullets.append(bullet)

mainloop()

Следующим важным исправлением должно стать избавление от while True:, который не имеет никакого отношения к среде, основанной на событиях, и использование ontimer() метод Screen вместо.

1 голос
/ 25 сентября 2019

У вас есть некоторые ошибки в логике обработки маркеров, которые означают, что вы выполняете намного больше работы, чем нужно для каждого кадра (и некоторые из них могут не выполнять то, что вы намеревались).

Первая проблема в этой строке в классе Enemy:

a=[] # to store the bullets per enemy

Комментарий неправильный и вводит в заблуждение.Вы не храните маркеры на врага , но у вас есть только один список в переменной класса, и все ваши экземпляры Enemy делят его.Если вам нужен отдельный список для каждого экземпляра, вам нужно переместить эту строку в метод __init__ и написать:

self.a = []

Тот факт, что каждый экземпляр противника имеет ссылку на один и тот же список, означаетчто позже, когда вы используете вложенные циклы для итерации по enemies1 и enemy1.a, вы фактически поражаете каждую пулю во всей игре несколько раз (по одному на каждого врага).Вероятно, это не то, что вы намеревались.

Как я упоминал выше, вы можете переместить список в экземпляры.Но альтернатива состоит в том, чтобы сохранить список переменных класса и вместо этого просто повторить его один раз, а не несколько раз.Объекты Bullet на самом деле не заботятся о том, какие Enemy запустили их после того, как они были созданы, поэтому вы можете достичь правильного поведения даже с одним списком пуль.Просто удалите отступ для цикла for над пулями и итерируйте по Enemy.a.

Другая важная проблема в вашем коде заключается в том, что вы неправильно удаляете маркеры, которые вышли за пределы.В вашем коде у вас есть del bullets, но это только удаляет переменную bullets из локального пространства имен, но не удаляет объект, на который ссылается это имя, из списка, который вы перебираете.Таким образом, вы постепенно накапливаете все больше и больше маркеров, что, вероятно, замедляет ваш код.

К сожалению, удаление элементов из списка во время итерации по нему немного опасно.Если вы просто исправили логику удаления, чтобы использовать индекс в списке (например, с enumerate), вы обнаружите, что вы проверяете только некоторые из своих маркеров, а не все.Это происходит потому, что каждый раз, когда вы удаляете один маркер, все последующие перемещаются вверх по списку, и поэтому вы пропускаете следующий в списке (так как теперь он находится в индексе, который был у удаленного маркера).Хотя существует несколько возможных обходных путей (например, итерация от конца списка к началу), часто лучшим подходом является создание целого нового списка для следующего кадра, исключая те, которые находятся за пределами.

new_bullet_list = []
for bullets in Enemy.a:
    if (bullets.ycor()>390 or bullets.xcor()>390 or bullets.ycor()<-390 or bullets.xcor()<-390):
        bullets.hideturtle()
        bullets.clear()
    else:
        new_bullet_list.append(bullets)
Enemy.a = new_bullet_list

В качестве дополнительного примечания, вы должны действительно попытаться улучшить имена переменных.Использование a в качестве названия вашего списка будет излишне лаконичным.Имя типа bullets или bullets_list было бы гораздо более наглядным.И использование bullets в качестве переменной цикла над списком маркеров вводит в заблуждение, поскольку это один экземпляр Bullet, а не несколько множественных наборов маркеров.Числа в enemies1 и enemy1 также не делают ничего полезного (обычно числа в имени переменной предполагают, что вы должны использовать список, но здесь есть только одна вещь для каждого из них, числа избыточны).

...