加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

VB和TV3D6.5做3D游戏高阶教程3 AI系统

(2012-02-27 13:57:17)
标签:

tv3d6.5

教程

3d游戏制作

杂谈

分类: 程序教程

AI也不属于tv3d的专属范畴,不过有人问起,还是简单讲下。

tv3d确实自带寻路AI系统,不过在tv6.3中已经有附带的例子,在6.5的使用方法也基本差不多,不再赘述。

AI是人工智能,其实就是模拟人类的思考,开发者基本也是模拟自己的思考,所以从AI的智商或多或少能看看出作者的智商,所以还是那句老话,别让人透过你的AI鄙视你的智商。

因为内容不多,所以我多讲一些好了。如果你要深刻的理解AI,就必须要了解到底什么是思考。

人与动物最大的不同是什么?是思维。

我猜没有人会为植物设计AI吧,除了食人植物。我们从最简单的动物开始探究:草履虫,真核细胞生物。它没有任何思考方式,是完完全全的条件反射和本能。本能是怎样来的,目前还是一个谜,现在科学家普遍相信的是本能行为是通过一种指令激素开始启动的,这种激素会引起脑中一系列神经细胞的活动,这些神经细胞能释放小蛋白分子与其他脑细胞和身体其他部分进行联系。没关系,我们大可以将本能也看作一种出生时就已经建立好的条件反射。

条件反射就很简单了,给了一个条件就会有一种反应。草履虫是低级条件反射,中间没有反射弧(包括感受器、传入神经、神经中枢、传出神经和效应器。)的存在,也就是受到外界刺激直接作用于效应器,中间没有神经中枢。

我们用代码来解释一下:

If 接收到刺激 then 收缩

动物的思考进化还是很慢的,直到哺乳动物,例如猫和狗依然仅仅是条件反射的层次,但是已经属于高级条件反射了。例子巴普洛夫研究狗的条件反射,建立条件反射后,只要摇铃,狗就有唾液分泌,也就是说中间有神经中枢可以做出复杂的反应,这一点,昆虫是绝对做不到的。用代码来表示,我们可以把神经中枢看做一个函数,就是:

If 听到铃声 then  动作函数(2)

Sub 动作函数(ID as long)

Case ID

Case 0’饿了的反应

找吃的

Case 1’害怕的反应

大声叫

Case 2’听到铃声的反应

分泌唾液

朝向目标

加强听觉

寻找食物

胃肠蠕动

Case 10000

End Select

End Sub

也就是说猫和狗根据一个条件就可以产生很多的反应了,但是无论猫还是狗无论你如何教导它们,它们也不会知道镜子里的像就是自己,只有更高阶的黑猩猩才能做到这点。黑猩猩会使用简单的工具,会将几个木箱叠起来取下吊在高处的香蕉。黑猩猩到底达到了怎样的智慧程度?让我们看几组例子:如学会了几十个手语单词的黑猩猩,它尽管懂得每个单词所代表的含义,并能进行简单的组合,但它所能表述的句子极短,一般超不过五个单词,也不能将这些手语单词组合成新的句子以表达整体性的新的意义。让人类给黑猩猩传递信息,在这次实验中,黑猩猩居然能分辨出正确信息和欺骗信息。黑猩猩在接到它认为信得过的人或黑猩猩的指点时它会毫不犹豫地打开那个容器的盖子。在接到欺骗信息后,它们的反应是朝着指示的容器走过去,却并不打开它,然后再朝着放食物的容器走去,翻过来拿到奖励的食物。

这里出现了一个奇怪的问题,黑猩猩为什么一定要先走到那个没有食物的容器前,然后才走向有食物的容器?

原来黑猩猩的大脑只能“再思”而不能“反思”,它们大脑这种“再思”的工作方式决定了它们对事得一层一层来处理。 我们用代码来模拟一下:

If 2个容器  then

  If 有人指点 then

  走到那个容器

  If 指点那人上次指的对 then

   翻开盖子

Else

 移动到下一个容器

  End if

Else

随机挑一个走过去

End If

End If

 

如果你看不懂,我只能说你的智商还不如黑猩猩。都说黑猩猩能达到人类4岁的智商,但实际上,2岁的儿童都不会像黑猩猩一样先走向错误的容器,思维是有本质差别的。如果说条件反射来源于记忆,黑猩猩可以说已经达到了“记忆阶段”的最高级,但是依然是没有思维的。倘若有一天,黑猩猩真的学会了反思的时候,那你要是杀害了只黑猩猩就要被判谋杀了。因为凡是拥有反思能力的生物,都是可以通过法律等手段改造的,都会意识到自己的存在,不能被人随意决定生死。我相信宇宙间拥有高级智慧的外星人一定对此有所规定,人类想在法律中加上这一条,我猜得等到人类突破了“思维阶段”,进化到下一个阶段——“精神力阶段”才有可能。

   不说了,扯远了。好,我们用代码来模拟一下人得再思,还是以翻盖子为例。

If 2个容器 then

   目标容器=随机选取其中一个

Aaa:

走向目标 (目标容器)

If目标容器= 所指点的容器 then

If 指点那人上次是错的 then

目标容器=另一个容器ID

Goto Aaa:

End if

Else

 If 指点那人上次是对的 then

目标容器=另一个容器ID

Goto Aaa:

    End if

End if

看着似乎有些啰嗦,那是因为杀鸡用牛刀缘故。其实最主要的就是实现了预判和修正功能,也就是提前根据各种条件进行计算,得出结果后再进行动作,如果动作出了问题,可以修正结果,然后根据修正的结果重新进行动作。

这里说到了预判,那就不得不说一下思维的最高级阶段,也就是预言。我们常听到这个词,不过这个词确实是为神准备的,人类还没有这个能力。人类能实现的是在简单的系统,不受外界干扰的情况下能做简单的预言。人类之所以能预言哈雷彗星76年后必将重临地球,是因为人类拥有大量的事实记录通过计算得出轨迹和周期,且宇宙中能够干扰的因素很小。但这种预言还是有实现不了的可能,因为我们不知道会不会有别的干扰因素,比如突然一颗小行星和其相撞。所以,预言必须建立在全知的基础上,例如当我们能够确切的知道,枪的后座力、稳定性,子弹的规整度,风力、空气密度,射击者的瞄准能力、反应能力、手臂肌肉强度,以及在射击的一瞬间的心理活动,我们通过计算完全可以在他开枪的一瞬间就知道这颗子弹会命中到什么地方。正如我第一篇教程所说,世界上根本就没有随机,只是我们的知道的信息不够全面。当然要达到这种程度,人类的脑开发度至少要达到或者超过100%才行。所以不要小看推理,复杂而又正确的推理,正是目前人类智者的标志。

   又扯远了,看看你的游戏AI达到了什么层次?实际上大部分简单的AI只要达到黑猩猩的程度就可以了,换句话说,我们玩的游戏其实都是在和黑猩猩玩对战。以csol安娜篇的AI为例,不一定能看懂,大家就看看大概模式好了:

 

  If .State = 0 Then '未发现敌人时

      '//////////////////////////////////////////////////////////////////////////

     

                 If Abs(.AimX + TspeedA) < PI * 0.33 Then    '敌人在自己正面

                 '检测中间是否有障碍

                 If MapCollision(Vector(.Poz.x, .Poz.y + .Height, .Poz.z), Vector(Hero.Poz.x, Hero.Poz.y + Hero.Height, Hero.Poz.z), Result, False, False) = False Then tempAim = True    '被发现

                 Else

                 If R < 300 Then tempAim = True '如果距离小于3,无论正面背面都会发现敌人

                 End If

                 End If

                    If Hero.FlashNum = 50 Then tempAim = True '敌人如果开枪,直接发现敌人

                 If tempAim Then '如果已经发现敌人了

                 NpcSound SoundFind(Int(Rnd * 6)), .Poz '播放发现敌人的语音

                 .State = 1 '状态改为发现敌人状态

                 .ActNum(0) = -500

                 .Loop = False

                    If .Rush = 0 Then '.rush为敌人运动方式0冲过来1原地隐蔽2沿指定路径运动

                    If .Movement = 0 Then .Act = 7   '如果发现时不运动,变换为静止瞄准姿势

                    ElseIf .Rush = 1 Then

                    .Act = 9

                    .Movement = 0

                     .Step = 0

                    ElseIf .Rush = 2 Then

                    .Movement = 1 '如果是运动狂,则直接跑动

                    End If

 

                End If

  ElseIf .State = 1 Then '发现敌人时

 

      .ActNum(5) = .ActNum(5) + Timelast

     .ActNum(4) = .ActNum(4) + Timelast

         .AimX = -TspeedA '枪口朝向目标

         .AimY = TspeedAY

        

        

             If .ActNum(5) > 500 Then  '计数器

             If MapCollision(Vector(.Poz.x, .Poz.y + .Height, .Poz.z), Vector(Hero.Poz.x, Hero.Poz.y + Hero.Height, Hero.Poz.z), Result) Then   '检测敌人是否可见

             .CanSeeT = True

             Else

             .CanSeeT = False

              .Path(0).x = Hero.Poz.x '记录敌人最后出现的位置

              .Path(0).y = Hero.Poz.z

             End If

             .ActNum(5) = 0

             End If

           

     

            If .CanSeeT Then '敌人不可见

                If .ActNum(4) > EnemyAimTime Then '到一定时间放松警惕

                 NpcSound SoundLost(Int(Rnd * 6)), .Poz

                .State = 0: .ActNum(4) = 0

                Else '未放松警惕

                  If .Rush = 0 And .Step <= 0 Then '勇猛型,一直追人

                  .Movement = 1

                  .WhichPath = 0

                  .WhichPathMax = 1

                  .Path(1).x = .Path(0).x + Int(Rnd * 600) - 300

                  .Path(1).y = .Path(0).y + Int(Rnd * 600) - 300

                  .Step = 0

                  End If

                  If .ActNum(0) < -150 Or .ActNum(0) > 0 Then .ActNum(0) = .ActNum(0) + Timelast

                End If

               

            Else '敌人可见

            .ActNum(0) = .ActNum(0) + Timelast

            .ActNum(4) = 0

            End If 'mapcollision

   

             '发子弹的程序

         

    

           

             If .ActNum(0) >= 2000 Then '发射时间间隔,能看敌人到时更新时间

             

              .ActNum(0) = -1000 '换子弹时间

            

             ElseIf .ActNum(0) >= 0 Then

       

            .ActNum(1) = .ActNum(1) + Timelast

               If .ActNum(1) > 200 Then  '发射子弹,随机计算发射角度

               .ActNum(1) = 0

               tPoz = .Gun.GetBonePosition(3)

              .FlashNum = 50

              .Flash.SetTexture FlashTex(Int(Rnd * 3))

              .Flash.SetPosition tPoz.x, tPoz.y, tPoz.z

          Sounds.Item("bullet").Stop_

          Sounds.Item("bullet").Play

               tempAngle = -.Angle + 2 + Rnd * 10 - 5

               TspeedAY = .AimY + Rnd * 10 - 5

              NpcCollShot i, tPoz, Vector(tPoz.x + CCos(tempAngle) * CCos(TspeedAY) * 5000, tPoz.y + SSin(TspeedAY) * 5000, tPoz.z + SSin(tempAngle) * CCos(TspeedAY) * 5000)

               End If '.actnum(1)

            End If '.actnum(0)

        

    '//////////////////////////////////////////////////////////////////////////

 

  If .Rush = 0 Then '远程勇猛型

                If .WhichPathMax > 1 Then .Step = 0 '停止沿着路径运动改为冲向敌人

                 If R < 500 Then '离敌人过近则停止

                   If .CanSeeT = False Then

                     If .Step <= 0 Then .WhichPath = .WhichPathMax: .Act = 7

                   End If

                 

                 ElseIf R > 700 Then '离得远就追

                   

                  If .Step <= 0 Then

                  .Path(1).x = Hero.Poz.x + Int(Rnd * 600) - 300

                  .Path(1).y = Hero.Poz.z + Int(Rnd * 600) - 300

                  .WhichPath = 0

                  .WhichPathMax = 1

                  .Movement = 1

                  End If

                 

                 End If 'r

   ElseIf .Rush = 1 Then '原地蹲下型,躲闪型

 

       .ActNum(2) = .ActNum(2) + Timelast

      If .Movement = 0 And .State = 1 Then .Act = 9

    

          If .ActNum(2) > 3000 Or .TempColl = True Then

                  .Path(1).x = .Poz.x + Int(Rnd * 600) - 300

                  .Path(1).y = .Poz.z + Int(Rnd * 600) - 300

                  .WhichPath = 0

                  .WhichPathMax = 1

                  .Movement = 1

                 

                .ActNum(2) = 0

          End If

 

ElseIf .Rush = 2 Then '按路径至死不渝型

 

  If .State = 1 Then '路径跑完,变勇猛型

  .Act = 6

   If .Movement = 0 Then .Rush = 0

  End If

ElseIf .Rush = 3 Then '站在高塔上

.Act = 7

ElseIf .Rush = 4 Then '僵尸类型

 

 

   If R > 200 Then '离得近,停止

   .Act = 11

   Else

   .Act = 7

   End If

  

                

             

ElseIf .Rush = 5 Then

End If 'rush

 

 

  ElseIf .State = 2 Then '死亡

 

 

  End If

 

      '//////////////////////////////////////////////////////////////////////////

      '//////////////////////////////////////////////////////////////////////////

      '//////////////////////////////////////////////////////////////////////////

 

 

  '运动

 

  If .Movement <> 0 Then '运动

                 If .TempColl Then '线路被阻

                   .WhichPath = .WhichPath - 1

                   If .WhichPath < 0 Then .WhichPath = 0

                  .Path(.WhichPath).x = .Poz.x + Int(Rnd * 500) - 250

                  .Path(.WhichPath).y = .Poz.z + Int(Rnd * 500) - 250

                  .WhichPath = .WhichPath - 1

                  .Step = 0

                  .TempColl = False

                  End If

 

            If .Step <= 0 Then '到达一个位置

            .WhichPath = .WhichPath + 1

           .Step = 0

       '下面这段程序用来算和路点的夹角,以便运动和转向

               If .WhichPath > .WhichPathMax Then   '到达终点

                 .WhichPath = 0

                If .Loop = False Then

                  .Movement = 0

                  .SpeedX = 0

                  .SpeedY = 0

                  .WhichPathMax = 0

                  .AimX = -.SpeedA

                If .State = 0 Then '无目标

                 .Act = 8

                 .ActNum(1) = 0

                Else '有目标

                 .Act = 7

                End If 'state

                End If 'loop

                 '计算步数

                 Else

                 ComAngle .Poz, Vector(.Path(.WhichPath).x, 0, .Path(.WhichPath).y), False, .SpeedA, , , XR

                  .Step = XR

                .AimX = -.SpeedA

                End If '.which

               

                      '//////////////////////////////////////////////////////////////////////////

                  If .Movement = 1 Then '

                    If .State = 1 Then

                   .Act = 6

                   ElseIf .State = 0 Then

                   .Act = 5

                   End If

                  ElseIf .Movement = 2 Then '

                   .Act = 4

                  End If

                 

            End If '.step

  End If 'movent

 

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有