Ursina: Создание умных NPC через поведенческие деревья (Часть 2). game development.. game development. gamedev.. game development. gamedev. python.. game development. gamedev. python. python 3.. game development. gamedev. python. python 3. python class.. game development. gamedev. python. python 3. python class. python tutor.. game development. gamedev. python. python 3. python class. python tutor. python3.. game development. gamedev. python. python 3. python class. python tutor. python3. pythonic.. game development. gamedev. python. python 3. python class. python tutor. python3. pythonic. ursina.. game development. gamedev. python. python 3. python class. python tutor. python3. pythonic. ursina. ursina engine.

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

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


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

Поведенческое дерево — это структура, которая определяет логику действий 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 могут реагировать на слова игрока.

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

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

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

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

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

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

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

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

Автор: TitledCube

Источник

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