Turtle程序在一段时间后变慢。尝试清除屏幕并删除但没有效果

问题描述 投票:0回答:1
# 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. > ")
python-2.7 memory-management turtle-graphics
1个回答
0
投票

[项目符号处理逻辑中存在一些错误,这意味着您在每一帧上所做的工作都比您需要做的要多(并且某些工作可能无法达到您的预期目的。]

第一个问题在Enemy类的这一行中:

a=[] # to store the bullets per enemy

此评论是错误的,并且极具误导性。您不是要存储子弹每个敌人,而是在类变量中只有一个列表,并且所有Enemy实例都共享它。如果要为每个实例创建单独的列表,则需要将该行移到__init__方法中并编写:

self.a = []

每个敌人实例都引用同一列表的事实意味着,稍后当您使用嵌套循环遍历enemies1enemy1.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作为项目符号列表的名称。像bulletsbullets_list这样的名称将更具描述性。而且,将bullets用作项目符号列表上的循环变量会产生误导,因为它是单个Bullet实例,而不是多个项目符号集合。 enemies1enemy1中的数字也没有任何用处(通常,变量名中的数字建议您使用列表,但是这里只需要处理一件事,数字是多余的) 。

© www.soinside.com 2019 - 2024. All rights reserved.