isvisible()缺少1个必需的位置参数:“self”Python错误

2024-09-29 01:18:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我用python turtle开发这个简单的射击游戏已经有几天了,我遇到了一个我找不到答案的错误。 我想要的是,玩家每杀死5次,就会出现一个额外的敌人。但是当我被杀死5次时,无数的错误信息开始涌入。 错误消息是:isvisible() missing 1 required positional argument: 'self' 它指向我的enemy_attack函数,在该函数中,我使用isvisible()命令测试敌人是否被射杀,以使其从另一个随机位置重生。提前谢谢你的帮助。 我为没有评论而道歉

import turtle
import time
import random
from random import randint
game_over = False
kill_counter = 0
enemy_spawn_number = 5

def close():
    turtle.bye()

speed = 10
enemy_speed = 0.5

lives = 3
wn = turtle.Screen()
wn.title("Defend.")
wn.bgcolor("black")
wn.setup(width=600, height=600)
wn.tracer(0)

player = turtle.Turtle()
player.speed(0)
player.shape("triangle")
player.color("white")
player.penup()
player.goto(0,0)

life1 = turtle.Turtle()
life1.speed(0)
life1.shape("triangle")
life1.color("yellow")
life1.penup()
life1.goto(265,-260)
life1.setheading(-90)

life2 = life1.clone()
life2.goto(240,-260)

life3 = life2.clone()
life3.goto(215,-260)

over_message = turtle.Turtle()
over_message.speed(0)
over_message.shape("square")
over_message.color("white")
over_message.penup()
over_message.goto(0,0)
over_message.ht()

killcount = over_message.clone()
killcount.goto(250,250)
killcount.ht()
killcount.write("Kill Count: 0", align="right", font=("Courier", 15, "normal"))


def go_up():
    player.setheading(90)
    player.forward(speed)

def go_right():
    player.setheading(0)
    player.forward(speed)


def go_left():
    player.setheading(180)
    player.forward(speed)

def go_down():
    player.setheading(-90)
    player.forward(speed)

wn.listen()
wn.onkeypress(go_up, "w")
wn.onkeypress(go_right, "d")
wn.onkeypress(go_left, "a")
wn.onkeypress(go_down, "s")
wn.onkeypress(close, "Escape")


collectible = turtle.Turtle()
collectible.speed(0)
collectible.shape("square")
collectible.color("blue")
collectible.penup()
collectible.goto(0,100)

bullet = turtle.Turtle()
bullet.shape("square")
bullet.color("grey")
bullet.shapesize(0.5,1)
bullet.hideturtle()
bullet.penup()
bullet.goto(500,500)

shooting = False
def shoot():
    global shooting
    if bullet.isvisible() == False:
        player_x = player.xcor()
        player_y = player.ycor()
        player_facing = player.heading()
        bullet.goto(player_x,player_y)
        bullet.setheading(player_facing)
        shooting = True
        bullet.showturtle()

enemies = []
enemies.append(turtle.Turtle())
for enemy in enemies:
    enemy.speed(0)
    enemy.shape("circle")
    enemy.color("red")
    enemy.penup()
    enemy.goto(0,350)

def enemy_attack():
    global game_over
    for enemy in enemies:
        if enemy.isvisible() == True:
            enemy.setheading(enemy.towards(player))
            enemy.forward(enemy_speed)
            wn.ontimer(enemy_attack, 10)
        else:
            if game_over == False:
                rand_direction = randint(0,3)
                if rand_direction == 0:
                    x = randint(-240, 200)
                    enemy.goto(x,450)
                    enemy.st()
                    enemy_attack()
                elif rand_direction == 1:
                    x = randint(-240, 200)
                    enemy.goto(x,-450)
                    enemy.st()
                    enemy_attack()
                elif rand_direction == 2:
                    y = randint(-210, 210)
                    enemy.goto(-450,y)
                    enemy.st()
                    enemy_attack()
                elif rand_direction == 3:
                    y = randint(-210, 210)
                    enemy.goto(450,y)
                    enemy.st()
                    enemy_attack()

enemy_attack()      
wn.onkey(shoot, "space")
while True:
    wn.update()

    if player.distance(collectible) < 20:
        x = randint(-290, 290)
        y = randint(-290, 290)
        collectible.goto(x,y)

    if bullet.xcor()>310 or bullet.xcor()<-310 or bullet.ycor()>310 or bullet.ycor()<-300:
        shooting = False
        bullet.hideturtle()

    if shooting == True:
        bullet.forward(0.2)

    if player.xcor()>285:
        playerX = player.xcor()
        playerX = playerX-5
        playerY = player.ycor()
        player.goto(playerX,playerY)
    elif player.xcor()<-285:
        playerX = player.xcor()
        playerX = playerX+5
        playerY = player.ycor()
        player.goto(playerX,playerY)
    elif player.ycor()>285:
        playerY = player.ycor()
        playerY = playerY-5
        playerX = player.xcor()
        player.goto(playerX,playerY)
    elif player.ycor()<-285:
        playerY = player.ycor()
        playerY = playerY+5
        playerX = player.xcor()
        player.goto(playerX,playerY)

    for enemy in enemies:
        if bullet.distance(enemy) < 20:
            bullet.hideturtle()
            enemy.hideturtle()
            enemy.goto(0,350)
            kill_counter = kill_counter+1
            killcount.clear()
            killcount.write("Kill Count: {}".format(kill_counter), align="right", font=("Courier", 15, "normal"))
            if kill_counter == enemy_spawn_number:
                enemies.append(turtle.Turtle)
                for enemy in enemies:
                        enemy.speed(0)
                        enemy.shape("circle")
                        enemy.color("red")
                        enemy.penup()
                        enemy.goto(0,350)
                enemy_spawn_number += 5

        if enemy.distance(player) < 20:
            enemy.ht()
            player.goto(0,0)
            lives = lives-1
            if lives == 2:
                life3.ht()
            elif lives == 1:
                life2.ht()
            elif lives == 0:
                life1.ht()
            time.sleep(0.1)

    if lives == 0:
        game_over = True
        collectible.ht()
        player.ht()
        for enemy in enemies:
            enemy.ht()
        over_message.write("Game Over! Press Esc to exit.", align="center", font=("Courier", 24, "normal"))```

Tags: messageifoverhtplayerspeedturtlegoto
2条回答

我运行代码,大部分时间都能正常工作

在某个时刻它出错了

Traceback (most recent call last):
  File "/home/furas/main.py", line 198, in <module>
    enemy.speed(0)
  File "/usr/lib/python3.7/turtle.py", line 2167, in speed
    return self._speed
AttributeError: 'int' object has no attribute '_speed'

我开始思考为什么enemy(也就是turtle)没有_speed?为什么它将其视为整数?所有的enemy都在列表上enemies,所以我开始检查您添加到这个列表中的内容,我发现您在其中一个Turtle()中忘记了()

enemies.append(turtle.Turtle)

所以它添加了类Turtle而不是Turle的实例

添加()后,我没有这个错误,但似乎还有其他问题,因为在杀死5个敌人后,它会冻结。它需要一些调试(或使用print())来找出问题所在


编辑:如果我在开始时添加两个敌人,我会遇到同样的问题。问题可能是它可能会运行两次wn.ontimer,而这可能会运行另外两次wn.ontimer,所以最后它可能没有时间执行它们


EDIT:如果我在函数末尾只使用wn.ontimer(enemy_attack, 10)并删除其他enemy_attack()代码,效果会更好。但这一次,敌人大多同时出现,当我杀死其中一个敌人时,它就会将他们全部移除。它可能需要更多的改变

def enemy_attack():
    global game_over
    for enemy in enemies:
        if enemy.isvisible() == True:
            enemy.setheading(enemy.towards(player))
            enemy.forward(enemy_speed)
        else:
            if game_over == False:
                rand_direction = randint(0,3)
                if rand_direction == 0:
                    x = randint(-240, 200)
                    enemy.goto(x,450)
                    enemy.st()
                    #enemy_attack()
                elif rand_direction == 1:
                    x = randint(-240, 200)
                    enemy.goto(x,-450)
                    enemy.st()
                    #enemy_attack()
                elif rand_direction == 2:
                    y = randint(-210, 210)
                    enemy.goto(-450,y)
                    enemy.st()
                    #enemy_attack()
                elif rand_direction == 3:
                    y = randint(-210, 210)
                    enemy.goto(450,y)
                    enemy.st()
                    #enemy_attack()

    wn.ontimer(enemy_attack, 10)

我看到的主要问题是@furas所指的:enemy_attack()通过递归和计时器调用自身turtle.Turtle调用时不带括号。我不认为以任何方式调用enemy_attack()都是一个好主意,相反,应该在主程序循环中调用它

使用ontimer()的一个问题是,您需要确保使用的超时时间大于执行函数所需的时间。除非它被设计为同时运行自身的多个实例。如果它写的是一个全局变量,那么它可能一次只能写一个

在基于事件的环境(如turtle)中,不应该有while True:(或time.sleep())。ontimer()方法应该同时处理这两个问题

在Python方面,您不应该执行以下操作:

if bullet.isvisible() == False:
    if enemy.isvisible() == True:
        if game_over == False:
if shooting == True:

相反,你应该:

if not bullet.isvisible():
    if enemy.isvisible():
        if not game_over:
if shooting:

下面,我把你的代码拆开,按照我期望的海龟游戏的设计方式重新组装。可能还有bug,但现在似乎可以玩了:

from turtle import Screen, Turtle
from random import randint

ENEMY_SPEED = 1
PLAYER_SPEED = 4
BULLET_SPEED = 6

SMALL_FONT = ('Courier', 15, 'normal')
LARGE_FONT = ('Courier', 24, 'normal')

def go_up():
    player.setheading(90)
    player.forward(PLAYER_SPEED)

def go_right():
    player.setheading(0)
    player.forward(PLAYER_SPEED)

def go_left():
    player.setheading(180)
    player.forward(PLAYER_SPEED)

def go_down():
    player.setheading(-90)
    player.forward(PLAYER_SPEED)

def enemy_attack():

    for enemy in enemies:

        if enemy.isvisible():
            enemy.setheading(enemy.towards(player))
            enemy.forward(ENEMY_SPEED)
        else:
            rand_direction = randint(0, 3)

            if rand_direction == 0:
                x = randint(-240, 200)
                enemy.goto(x, 325)
            elif rand_direction == 1:
                x = randint(-240, 200)
                enemy.goto(x, -325)
            elif rand_direction == 2:
                y = randint(-210, 210)
                enemy.goto(-325, y)
            elif rand_direction == 3:
                y = randint(-210, 210)
                enemy.goto(325, y)

            enemy.showturtle()

def shoot():
    if not bullet.isvisible():
        bullet.goto(player.position())
        bullet.setheading(player.heading())
        bullet.showturtle()

kill_counter = 0
enemy_spawn_number = 5
lives = 3

def move():
    global kill_counter, enemy_spawn_number, lives

    enemy_attack()

    if player.distance(collectible) < 20:
        collectible.goto(randint(-260, 260), randint(-260, 260))

    if bullet.isvisible():
        if not (-310 < bullet.xcor() < 310 and -310 < bullet.ycor() < 310):
            bullet.hideturtle()
        else:
            bullet.forward(BULLET_SPEED)

    playerX, playerY = player.position()

    if playerX > 285:
        player.setx(playerX - 5)
    elif playerX < -285:
        player.setx(playerX + 5)
    elif playerY > 285:
        player.sety(playerY - 5)
    elif playerY < -285:
        player.sety(playerY + 5)

    for enemy in enemies:
        if bullet.isvisible() and bullet.distance(enemy) < 15:
            bullet.hideturtle()
            enemy.hideturtle()
            enemy.sety(325)

            kill_counter += 1
            killcount.clear()
            killcount.write("Kill Count: {}".format(kill_counter), align='right', font=SMALL_FONT)

            if kill_counter == enemy_spawn_number:
                enemy = enemy_prototype.clone()
                enemy.showturtle()

                enemies.append(enemy)

                for enemy in enemies:
                    enemy.sety(325)

                enemy_spawn_number += 5

        if enemy.distance(player) < 20:
            enemy.hideturtle()
            player.goto(0, 0)

            lives -= 1

            if lives == 2:
                life3.hideturtle()
            elif lives == 1:
                life2.hideturtle()
            elif lives == 0:
                life1.hideturtle()

    if lives == 0:
        collectible.hideturtle()
        player.hideturtle()

        for enemy in enemies:
            enemy.hideturtle()

        over_message.write("Game Over! Press Esc to exit.", align='center', font=LARGE_FONT)
    else:
        screen.ontimer(move, 70)

    screen.update()

screen = Screen()
screen.setup(width=600, height=600)
screen.title("Defend.")
screen.bgcolor('black')
screen.tracer(0)

player = Turtle()
player.shape('triangle')
player.color('white')
player.penup()

life1 = Turtle()
life1.shape('triangle')
life1.color('yellow')
life1.penup()
life1.goto(265, -260)
life1.setheading(-90)

life2 = life1.clone()
life2.goto(240, -260)

life3 = life2.clone()
life3.goto(215, -260)

over_message = Turtle()
over_message.hideturtle()
over_message.color('white')
over_message.penup()

killcount = over_message.clone()
killcount.goto(270, 270)
killcount.write("Kill Count: 0", align='right', font=SMALL_FONT)

collectible = Turtle()
collectible.shape('square')
collectible.color('blue')
collectible.penup()
collectible.goto(randint(-260, 260), randint(-260, 260))

bullet = Turtle()
bullet.hideturtle()
bullet.shape('square')
bullet.shapesize(0.5, 1)
bullet.color('grey')
bullet.penup()
bullet.goto(500, 500)

enemy_prototype = Turtle()
enemy_prototype.hideturtle()
enemy_prototype.shape('circle')
enemy_prototype.color('red')
enemy_prototype.penup()
enemy_prototype.sety(325)

enemy = enemy_prototype.clone()
enemy.showturtle()

enemies = [enemy]

screen.onkeypress(go_up, 'w')
screen.onkeypress(go_right, 'd')
screen.onkeypress(go_left, 'a')
screen.onkeypress(go_down, 's')
screen.onkeypress(screen.bye, 'Escape')
screen.onkeypress(shoot, 'space')
screen.listen()

move()

screen.mainloop()

我认为您应该解决的下一个问题是代码中阻止您调整屏幕大小的所有数字常量:

life1.goto(265,-260)
life2.goto(240,-260)
life3.goto(215,-260)
killcount.goto(250,250)
x = randint(-240, 200)
x = randint(-240, 200)
y = randint(-210, 210)
y = randint(-210, 210)
x = randint(-290, 290)
y = randint(-290, 290)
if bullet.xcor()>310 or bullet.xcor()<-310 or bullet.ycor()>310 or bullet.ycor()<-300:
if player.xcor()>285:
elif player.xcor()<-285:
elif player.ycor()>285:
elif player.ycor()<-285:

这些都应根据屏幕大小进行定义:

screen.setup(width=600, height=600)

以及他们操纵的对象。(即代码中没有大数字!)

相关问题 更多 >