在UE4编辑器中,打开内容浏览器,右击鼠标,创建传说中的行为树:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQTM2MzA2MjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

之后便会得到存在一个根节点的空的行为树:

右側是设置行为树的黑板资源,此资源可自己创建与定义。实质就是不同bot之间协调时使用的一些公共内存罢了。UE4仅仅是简单实现。就是一些映射罢了。当然不用也能够哦。亲!

设置一颗例如以下行为树,和官网shootergame一样:

之后为了让此行为树跑起来。我们须要把他与我们的bot关联。在我们定义的bot中

在编辑器中赋值:

虽说这个行为树定义在这里,可是我们常常会在其controller中调用(来自ShooterAIController类中的代码):

AShooterAIController::AShooterAIController(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP)
{
BlackboardComp = PCIP.CreateDefaultSubobject<UBlackboardComponent>(this, TEXT("BlackBoardComp"));//创建黑板组件 BehaviorComp = PCIP.CreateDefaultSubobject<UBehaviorTreeComponent>(this, TEXT("BehaviorComp"));//创建行为树组件 bWantsPlayerState = true;
}
//此方法在控制类(controller)关联肉身(APawn。UE4为人物增添了角色类。当然也是APawn的子类)时调用。熟悉UDK脚本的应该知道。
void AShooterAIController::Possess(APawn* InPawn)
{
Super::Possess(InPawn); AShooterBot* Bot = Cast<AShooterBot>(InPawn); // start behavior
if (Bot && Bot->BotBehavior)//由于在编辑器中已经赋值,所以这里行为树指针的值非空
{
BlackboardComp->InitializeBlackboard(Bot->BotBehavior->BlackboardAsset);//利用黑板资源初始化黑板组件
//获取黑板中的键ID
EnemyKeyID = BlackboardComp->GetKeyID("Enemy");
NeedAmmoKeyID = BlackboardComp->GetKeyID("NeedAmmo");
//启动行为树
BehaviorComp->StartTree(Bot->BotBehavior);
}
}

能够看出这里便使得AIController与我们创建的黑板资源与行为树资源相关联。

最后我们看看,上面行为树中的服务是啥回事?先看UE4中:

这三个关键类UBTService_BlackboardBase,UBTServe_BlueprintBase,UBTService_DefaultFoces便是UE4为我们创建的主要的服务类,在shooterGame项目里,是继承的中间UBTServe_BlueprintBase类,显然是为了在蓝图中可视化。

注意当中的FindClosestEnemy函数,这是哪里来的??,请看AShooterAIController类中:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQTM2MzA2MjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />

	UFUNCTION(BlueprintCallable, Category=Behavior)//不用说这样的声明是啥意思,看上图
void FindClosestEnemy();
void AShooterAIController::FindClosestEnemy()
{
APawn* MyBot = GetPawn();
if (MyBot == NULL)
{
return;
} const FVector MyLoc = MyBot->GetActorLocation();
float BestDistSq = MAX_FLT;
AShooterCharacter* BestPawn = NULL; for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It)
{
AShooterCharacter* TestPawn = Cast<AShooterCharacter>(*It);
if (TestPawn && TestPawn->IsAlive() && TestPawn->IsEnemyFor(this))
{
const float DistSq = (TestPawn->GetActorLocation() - MyLoc).SizeSquared();
if (DistSq < BestDistSq)
{
BestDistSq = DistSq;
BestPawn = TestPawn;
}
}
} if (BestPawn)
{
SetEnemy(BestPawn);
}
}

相似的有ShootEnemy:

	UFUNCTION(BlueprintCallable, Category=Behavior)
void ShootEnemy();
void AShooterAIController::ShootEnemy()
{
AShooterBot* MyBot = Cast<AShooterBot>(GetPawn());
AShooterWeapon* MyWeapon = MyBot ? MyBot->GetWeapon() : NULL;
if (MyWeapon == NULL)
{
return;
} bool bCanShoot = false;
AShooterCharacter* Enemy = GetEnemy();
if (Enemy && Enemy->IsAlive() && MyWeapon->GetCurrentAmmo() > 0)
{
if (LineOfSightTo(Enemy, MyBot->GetActorLocation()))
{
bCanShoot = true;
}
} if (bCanShoot)
{
MyBot->StartWeaponFire();
}
else
{
MyBot->StopWeaponFire();
}
}

UE4 中的人工智能解析—ShooterGame为例的更多相关文章

  1. Java并发编程中的设计模式解析(二)一个单例的七种写法

    Java单例模式是最常见的设计模式之一,广泛应用于各种框架.中间件和应用开发中.单例模式实现起来比较简单,基本是每个Java工程师都能信手拈来的,本文将结合多线程.类的加载等知识,系统地介绍一下单例模 ...

  2. UE4中使用数据表(Data Table)

    本文依据官方文档数据驱动游戏性元素整理而来. 做过游戏的应该都清楚,如果游戏稍微有点规模,那么使用数据驱动来做游戏一般是必不可少的一步,一般也就是策划通过本表的方式来解决.下面我们来简单说一下UE4中 ...

  3. .NET Core中的CSV解析库

    感谢 本篇首先特别感谢从此启程兄的<.NetCore外国一些高质量博客分享>, 发现很多国外的.NET Core技术博客资源, 我会不定期从中选择一些有意思的文章翻译总结一下. .NET ...

  4. 【转载】 [unreal4入门系列之七] UE4中的Actor类和Pawn类

    原文地址: http://www.52vr.com/article-558-1.html 现在我们开始进入UE4的代码开发工作.首先,UE4的类框架是非常庞大的,看起来有点让人措手不及.不过正因为UE ...

  5. maven中使用dom4j解析、生成XML的简易方法

    此片文章主要写一些关于如何在maven工程中使用dom4j来解析或生成XML的建议方法,实际可使用的写法不仅限于如下所写的样例代码.此处进攻快速入手和提供思路使用. 首先配置pom.xml中的依赖的包 ...

  6. UE4 中的 C++ 编程介绍

    https://docs.unrealengine.com/latest/CHN/Programming/Introduction/index.html UE4 中的 C++ 编程介绍 Unreal ...

  7. 「Python 编程」编码实现网络请求库中的 URL 解析器

    摘要:怎么写出更短的代码并不是这次要讨论的话题.今天我们来研究一下:运行代码的计算机是如何找到目标服务器的? 相信各位 Python 开发者都用过 Requests 库,有些朋友还用过 WebSock ...

  8. UE4命令行参数解析

    转自:https://blog.csdn.net/u012999985/article/details/53544389 一 .命令行参数简述命令行参数是一连串的关键字字符串,当运行可执行文件时可以通 ...

  9. 前进中的人工智能——聚焦Faculty Summit 2015人工智能主题研讨会

    Summit 2015人工智能主题研讨会" title="前进中的人工智能--聚焦Faculty Summit 2015人工智能主题研讨会"> 在近几年上映的科幻大 ...

随机推荐

  1. 【codeforces 747E】Comments

    [题目链接]:http://codeforces.com/problemset/problem/747/E [题意] 给你一个类似递归的结构; 让你把每一层的字符串按照层,一层层地输出出来; 并输出层 ...

  2. 为什么要重写toString()方法

    因为在System.out.println(类的对象名)时,类的对象名是个引用,如果不重写,就输出引用地址. 其实实际是这样的System.out.println(类的对象名.toString()), ...

  3. Spring中 @Autowired标签与 @Resource标签 的区别(转)

    spring不但支持自己定义的@Autowired注解,还支持由JSR-250规范定义的几个注解,如:@Resource. @PostConstruct及@PreDestroy. 1. @Autowi ...

  4. POJ 1286

    Burnside定理. 可以用Euler函数优化. #include <iostream> #include <cstdio> #include <cstring> ...

  5. CentOS进入图形界面

    CentOS进入图形界面 学习了: http://www.centoscn.com/CentosBug/osbug/2014/0831/3620.html http://bbs.csdn.net/to ...

  6. 使用malloc分别分配2KB的空间,然后用realloc调整为6KB的内存空间,打印指针地址

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<malloc.h> i ...

  7. fastjson 的简单使用

    public static void main(String[] args) { /*普通对象与json相互转换*/ User u = new User("miquan", &qu ...

  8. node21---mongoose

    01.js //引包 var mongoose = require('mongoose'); //创建一个数据库连接 mongoose.connect('mongodb://localhost/tes ...

  9. [JZOJ 5912] [NOIP2018模拟10.18] VanUSee 解题报告 (KMP+博弈)

    题目链接: https://jzoj.net/senior/#contest/show/2530/2 题目: 众所周知,cqf童鞋对哲学有着深入的理解和认识,并常常将哲学思想应用在实际生活中,例如锻炼 ...

  10. POJ 3320 Jessica's Reading Problem (尺取法,时间复杂度O(n logn))

    题目: 解法:定义左索引和右索引 1.先让右索引往右移,直到得到所有知识点为止: 2.然后让左索引向右移,直到刚刚能够得到所有知识点: 3.用右索引减去左索引更新答案,因为这是满足要求的子串. 4.不 ...