- BrainTools - https://www.braintools.ru -

Ursina: Создание умных NPC через поведенческие деревья (Часть 2)

<– Прошлая статья [1]

В первой части мы разобрали основы Ursina и создали простую 3D-игру. Теперь перейдем к более сложной механике — искусственному интеллекту [2] для NPC с помощью поведенческих деревьев (Behavior Trees).


1. Что такое поведенческие деревья?

Поведенческое дерево — это структура, которая определяет логику [3] действий NPC. В отличие от простых скриптов, оно позволяет:

  • Гибко комбинировать условия и действия

  • Легко масштабировать ИИ-логику

  • Избегать спагетти-кода в сложных сценариях

Пример простого дерева для NPC-стража:

Copy

Поведение охранника:  
├─ Если видит игрока → Атаковать  
├─ Если слышит шум → Исследовать  
└─ Иначе → Патрулировать  

2. Подключаем AI в Ursina

Ursina включает модуль Behavior для работы с поведенческими деревьями.

Шаг 1: Создаем базового NPC

python

Copy

from ursina import *  
from ursina.prefabs.ai import Behavior  

app = Ursina()  

# NPC - это просто куб с "мозгами"  
npc = Entity(model='cube', color=color.red, position=(3, 0, 0))  

Шаг 2: Добавляем поведение

python

Copy

# Определяем действия NPC  
def patrol():  
    npc.x += time.dt * 2  # Движется вправо  
    if npc.x > 5:  
        npc.x = -5  # Возвращается на старт  

def chase_player():  
    npc.position += (player.position - npc.position).normalized() * time.dt * 3  

# Создаем дерево поведения  
npc.add_script(Behavior({  
    'sequence': [  
        {'condition': lambda: distance(npc, player) < 3, 'action': chase_player},  
        {'action': patrol}  
    ]  
}))  

Как это работает:

  1. NPC сначала проверяет, близко ли игрок (distance < 3).

  2. Если да — преследует (chase_player).

  3. Если нет — патрулирует (patrol).


3. Сложные сценарии

Пример: NPC с тремя состояниями

python

Copy

states = {  
    'calm': {  
        'action': lambda: setattr(npc, 'color', color.green),  
        'transition': [  
            {'condition': lambda: distance(npc, player) < 4, 'next_state': 'alert'},  
        ]  
    },  
    'alert': {  
        'action': lambda: setattr(npc, 'color', color.yellow),  
        'transition': [  
            {'condition': lambda: distance(npc, player) < 2, 'next_state': 'angry'},  
            {'condition': lambda: distance(npc, player) > 5, 'next_state': 'calm'},  
        ]  
    },  
    'angry': {  
        'action': chase_player,  
        'transition': [  
            {'condition': lambda: distance(npc, player) > 4, 'next_state': 'alert'},  
        ]  
    }  
}  

npc.add_script(Behavior({'state_machine': states}))  

Логика:

  • 🟢 Спокойный (зеленый): игрок далеко → NPC стоит.

  • 🟡 Настороженный (желтый): игрок приближается → NPC поворачивается к нему.

  • 🔴 Агрессивный (красный): игрок слишком близко → погоня!


4. Продвинутые техники

4.1. Работа с памятью NPC

Чтобы NPC “запоминал” игрока даже когда тот скрылся:

python

Copy

npc.memory = {'last_seen_player_pos': None}  

def remember_player():  
    if distance(npc, player) < 3:  
        npc.memory['last_seen_player_pos'] = player.position  

Behavior({  
    'action': remember_player,  
    'sequence': [  
        {'condition': lambda: npc.memory['last_seen_player_pos'] is not None,  
         'action': lambda: npc.look_at(npc.memory['last_seen_player_pos'])},  
        {'action': patrol}  
    ]  
})  

4.2. Групповое поведение

Создаем стаю NPC, которая атакует вместе:

python

Copy

enemies = [Entity(model='cube', color=color.red) for _ in range(5)]  

for enemy in enemies:  
    enemy.add_script(Behavior({  
        'parallel': [  
            {'condition': lambda e=enemy: distance(e, player) < 4, 'action': chase_player},  
            {'action': lambda e=enemy: e.look_at_2d(player)}  
        ]  
    }))  

5. Оптимизация производительности

  • Используйте distance_squared вместо distance для проверок (избегаем квадратного корня).

  • Ограничивайте частоту проверок через time.dt:

    python

    Copy

    def update():  
        if time.time() % 1.0 < time.dt:  # Проверяем раз в секунду  
            npc.bt.update()  

6. Что дальше?

  1. Добавьте путьfinding через ursina.pathfinding для обхода препятствий.

  2. Создайте диалоговую систему — NPC могут реагировать [4] на слова игрока.

  3. Экспериментируйте с нейросетями (подключите TensorFlow для обучения [5] NPC).

Совет: Для сложных проектов используйте визуальный редактор поведенческих деревьев Behavior Tree Editor [6].

Итог: С Ursina даже сложный ИИ становится доступным. Начните с простых патрулей, а затем создавайте NPC с характером!

P.S. Попробуйте сделать NPC, который:

  • Прячется за укрытиями

  • Подбирает предметы

  • Общается с другими NPC

Какой вариант реализуете первым? 🚀

Автор: TitledCube

Источник [7]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/13968

URLs in this post:

[1] <– Прошлая статья: https://habr.com/ru/articles/898354/

[2] интеллекту: http://www.braintools.ru/article/7605

[3] логику: http://www.braintools.ru/article/7640

[4] реагировать: http://www.braintools.ru/article/1549

[5] обучения: http://www.braintools.ru/article/5125

[6] Behavior Tree Editor: https://github.com/mwoolweaver/BehaviorTreeEditor

[7] Источник: https://habr.com/ru/articles/898360/?utm_source=habrahabr&utm_medium=rss&utm_campaign=898360

www.BrainTools.ru

Рейтинг@Mail.ru
Rambler's Top100