“Nonetype 对象在 Pygame 中没有属性 'take turn'。挂在单行上

"Nonetype object has no attribute 'take turn' in Pygame. Hung up on a single line

我正在用 python 2.7 创建一个类流氓游戏,使用 pygame 和 libtcodpy 库。这是一个基于图块的游戏,当我尝试实现一个名为 'take turn' 的函数时,每次玩家移动时都会将敌人 space 移动到左侧 - 它对玩家应用了相同的函数并且结果非常有问题,"PLAYER" 也向左移动了一个 space。错误发生在第 101 行。我正在查看是否有人可以指出该缺陷。我尝试使用此建议解决它,但无法弄清楚他要我把代码行放在哪里:

“即使我将 self.ai = ai 放在 if 语句之外,我仍然收到 NoneType 没有名为 take_turn 的函数的错误。

我怀疑与 'ai' 和 'take_turn' 函数相关的任何错误。

我通过创建一个名为 ai_Player 的新 ai 解决了这个问题,在 take_turn 函数中我只是输入了 return,所以它什么都不做。奇迹般有效。 (不要忘记将 AI 添加到播放器)"

我的代码如下(星号表示我删除代码并重新制作游戏的地方运行):

class obj_Actor:
    def __init__(self, x, y, name_object, sprite, creature = None, ai = None):
        self.x = x #map address
        self.y = y #map address
        self.sprite = sprite

        self.creature = creature
        if creature:
            creature.owner = self

        **self.ai = ai
        if ai:
            ai.owner = self**

    def draw(self):
        SURFACE_MAIN.blit(self.sprite, (self.x*constants.CELL_WIDTH, self.y*constants.CELL_HEIGHT))

    def move(self, dx, dy):
        if GAME_MAP[self.x + dx][self.y + dy].block_path == False:
            self.x += dx
            self.y += dy

**class ai_Test:
    def take_turn(self):
        self.owner.move(-1, 0)**

def game_main_loop():

    game_quit = False

    #player action definition
    player_action = 'no-action'

    while not game_quit:

        #handle player input
        player_action = game_handle_keys()

        if player_action == 'QUIT':
            game_quit == True

        **if player_action != 'no-action':
            for obj in GAME_OBJECTS:
                obj.ai.take_turn()**
        #TODO draw the game
        draw_game()

    #quit the game
    pygame.quit()
    exit()

def game_initialize():
    #This function, initializes main window, and pygame

    global SURFACE_MAIN, GAME_MAP, PLAYER, ENEMY, GAME_OBJECTS

    #initialize pygame
    pygame.init()

    SURFACE_MAIN = pygame.display.set_mode( (constants.GAME_WIDTH,constants.GAME_HEIGHT) )

    GAME_MAP = map_create()

    creature_com1 = com_Creature('Greg')
    PLAYER = obj_Actor(0, 0, "Human", constants.S_PLAYER, creature = creature_com1)

    creature_com2 = com_Creature('Skeletor')
    **ai_com = ai_Test()**
    ENEMY = obj_Actor(15, 15, 'Skeleton', constants.S_ENEMY, **ai = ai_com)**

    GAME_OBJECTS = [PLAYER, ENEMY]

    #execute game

def game_handle_keys():
    #gets player input
    events_list = pygame.event.get()
    #process player input
    for event in events_list:
        if event.type == pygame.QUIT:
            return 'QUIT'

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                PLAYER.move(0, -1)
                return 'player-moved'

            if event.key == pygame.K_DOWN:
                PLAYER.move(0, 1)
                return 'player-moved'

            if event.key == pygame.K_LEFT:
                PLAYER.move(-1, 0)
                return 'player-moved'

            if event.key == pygame.K_RIGHT:
                PLAYER.move (1, 0)
                return 'player-moved'
    return "no-action"

if __name__ == '__main__':
    game_initialize()
    game_main_loop()

Traceback (most recent call last):
  File "/Users/wills/Desktop/my-pygame/my_pygame.py", line 152, in <module>
    game_main_loop()
  File "/Users/wills/Desktop/my-pygame/my_pygame.py", line 93, in game_main_loop
    obj.ai.take_turn()
AttributeError: obj_Actor instance has no attribute 'ai'

我认为你的问题出在这里:

I thought by not assigning it a specific ai, PLAYER which is initialized in the initialize function would ignore the "take turn" function.

如果您将某些内容设置为 None,它不会忽略您对其调用的所有内容,它会在您尝试调用任何内容时引发 AttributeError


一个选项是在调用之前检查值:

for obj in GAME_OBJECTS:
    if obj.ai:
        obj.ai.take_turn()

如果这绝对是您唯一会使用 ai 属性的地方,那么这可能是最佳答案。


但是如果你打算在多个地方使用它,那么很容易在 7 个地方进行检查而忘记第 8 个地方并且得到只在奇怪的情况下才会发生的神秘错误。在那种情况下,您确实希望它按照您期望的方式运行,而这样做的方法是分配一些自动忽略 "take turn" 函数的 "dummy" 对象。

最简单的版本是:

class DummyPlayer:
    def take_turn(self):
        pass

然后,当您将播放器分配给 None 时,将其分配给 DummyPlayer 实例。我想就在这里:

class obj_Actor:
    def __init__(self, x, y, name_object, sprite, creature = None, ai = None):
        # etc.

        if ai:
            ai.owner = self
        else:
            ai = DummyPlayer()
        self.ai = ai

        # etc.

现在,self.ai 总是带有 take_turn 方法的东西——要么是真正的 AI,要么是 DummyPlayer——所以不检查就调用该方法总是安全的。