weidongzi 发表于 2016-6-26 02:00:02

想写一个判断血量的简单AI,遇到一些问题

本帖最后由 weidongzi 于 2016-6-27 14:49 编辑

这是一个夺塔小实验,塔1-7为腐败之塔,塔8为诅咒之塔(id为4480-4486以及4597)。代码如下:

(defconst Object-data-hitpoints 10)

(defrule
    (true)
=>
    (set-strategic-number sn-maximum-food-drop-distance 0)
    (set-strategic-number sn-maximum-wood-drop-distance 0)
    (set-strategic-number sn-maximum-gold-drop-distance 0)
    (set-strategic-number sn-maximum-stone-drop-distance 0)
    (set-strategic-number sn-percent-civilian-gatherers 0)
    (set-strategic-number sn-percent-civilian-builders 0)
    (set-strategic-number sn-percent-civilian-explorers 0)
    (set-strategic-number sn-maximum-hunt-drop-distance 0)
    (set-strategic-number sn-maximum-fish-boat-drop-distance 0)
    (set-strategic-number sn-task-ungrouped-soldiers 0)
    (set-strategic-number sn-total-number-explorers 0)
    (disable-self)
)


(defrule
    (true)
=>
    (up-set-target-by-id c: 4484)
    (up-get-object-data object-data-hitpoints towerHP1)
    (up-set-target-by-id c: 4480)
    (up-get-object-data object-data-hitpoints towerHP2)
    (up-set-target-by-id c: 4481)
    (up-get-object-data object-data-hitpoints towerHP3)
    (up-set-target-by-id c: 4482)
    (up-get-object-data object-data-hitpoints towerHP4)
    (up-set-target-by-id c: 4497)
    (up-get-object-data object-data-hitpoints towerHP5)
    (up-set-target-by-id c: 4483)
    (up-get-object-data object-data-hitpoints towerHP6)
    (up-set-target-by-id c: 4485)
    (up-get-object-data object-data-hitpoints towerHP7)
    (up-set-target-by-id c: 4486)
    (up-get-object-data object-data-hitpoints towerHP8)
)

(defrule
    (true)
=>
    (set-goal 1 0)
    (set-goal 2 0)
    (set-goal 3 0)
    (set-goal 4 0)
    (set-goal 5 0)
    (set-goal 6 0)
    (set-goal 7 0)
    (set-goal 8 0)
    (disable-self)
)


(defrule
    (goal 1 0)
    (up-compare-goal towerHP1 < 380)
=>
    (chat-to-all "tower1中立" )
    (set-signal 1)
    (set-goal 1 1)
)

(defrule
    (goal 1 1)
    (up-compare-goal towerHP1 >= 380)
=>
    (chat-to-all "tower1占领" )
    (set-signal 2)
    (set-goal 1 0)
)

(defrule
    (goal 2 0)
    (up-compare-goal towerHP2 < 380)
=>
    (chat-to-all "tower2中立" )
    (set-signal 3)
    (set-goal 2 1)
)

(defrule
    (goal 2 1)
    (up-compare-goal towerHP2 >= 380)
=>
    (chat-to-all "tower2占领" )
    (set-signal 4)
    (set-goal 2 0)
)

(defrule
    (goal 3 0)
    (up-compare-goal towerHP3 < 380)
=>
    (chat-to-all "tower3中立" )
    (set-signal 5)
    (set-goal 3 1)
)

(defrule
    (goal 3 1)
    (up-compare-goal towerHP3 >= 380)
=>
    (chat-to-all "tower3占领" )
    (set-signal 6)
    (set-goal 3 0)
)

(defrule
    (goal 4 0)
    (up-compare-goal towerHP4 < 380)
=>
    (chat-to-all "tower4中立" )
    (set-signal 7)
    (set-goal 4 1)
)

(defrule
    (goal 4 1)
    (up-compare-goal towerHP4 >= 380)
=>
    (chat-to-all "tower4占领" )
    (set-signal 8)
    (set-goal 4 0)
)

(defrule
    (goal 5 0)
    (up-compare-goal towerHP5 < 380)
=>
    (chat-to-all "tower5中立" )
    (set-signal 9)
    (set-goal 5 1)
)

(defrule
    (goal 5 1)
    (up-compare-goal towerHP5 >= 380)
=>
    (chat-to-all "tower5占领" )
    (set-signal 10)
    (set-goal 5 0)
)

(defrule
    (goal 6 0)
    (up-compare-goal towerHP6 < 380)
=>
    (chat-to-all "tower6中立" )
    (set-signal 11)
    (set-goal 6 1)
)

(defrule
    (goal 6 1)
    (up-compare-goal towerHP6 >= 380)
=>
    (chat-to-all "tower6占领" )
    (set-signal 12)
    (set-goal 6 0)
)

(defrule
    (goal 7 0)
    (up-compare-goal towerHP7 < 380)
=>
    (chat-to-all "tower7中立" )
    (set-signal 13)
    (set-goal 7 1)
)

(defrule
    (goal 7 1)
    (up-compare-goal towerHP7 >= 380)
=>
    (chat-to-all "tower7占领" )
    (set-signal 14)
    (set-goal 7 0)
)

(defrule
    (goal 8 0)
    (up-compare-goal towerHP8 < 500)
=>
    (chat-to-all "tower8中立" )
    (set-signal 15)
    (set-goal 8 1)
)

(defrule
    (goal 8 1)
    (up-compare-goal towerHP8 >= 500)
=>
    (chat-to-all "tower8占领" )
    (set-signal 16)
    (set-goal 8 0)
)

测试时遇到了这样的问题:


有请高手看一下,是不是我的代码写漏了什么。感谢!


条顿武士 发表于 2016-6-26 09:48:55

AI出错的提示说的很清楚,是25行的位置,TowerHp1这个词没有定义。

实际上在使用目标变量存储数据的时候需要事先定义,方法和定义常数一样,使用defconst,需要定义的是TowerHp1这个词所带表的目标变量编号。

1.4的AI最多支持512个变量,但是一般个位数的变量我们会直接调用,比如下面这段:

(defrule
    (true)
=>
    (set-goal 1 0)
    (set-goal 2 0)
    (set-goal 3 0)
    (set-goal 4 0)
    (set-goal 5 0)
    (set-goal 6 0)
    (set-goal 7 0)
    (set-goal 8 0)
    (disable-self)
)

这里就把编号为1-8的变量全部设置成了0。

如果把这句话中的TowerHP1换成数字9,实际上就不会出错了…意思是把塔的HP存在了编号为9的变量里。

    (up-set-target-by-id c: 4484)
    (up-get-object-data Object-data-hitpoints TowerHP1)

但是如果数字编号直接使用过多,AI的可读性就会下降,到了后来作者自己都会忘了哪个变量存的是什么数据…所以一般我们自定义一个英文名来代表一个编号。

只需要在AI最开始的地方加一些编号定义:

(defconst TowerHP1 9)
(defconst TowerHP2 10)
(defconst TowerHP3 11)
等等

那么后面的语句就不会出错了。

weidongzi 发表于 2016-6-26 19:22:19

条顿武士 发表于 2016-6-26 09:48
AI出错的提示说的很清楚,是25行的位置,TowerHp1这个词没有定义。

实际上在使用目标变量存储数据的时候 ...

谢谢解答。AI现在能读了,但是测试时又出了问题。我的触发这么做:

触发1:循环,开启
条件:AI信号1
效果:改变所有权,将塔换至中立玩家名下

触发2:循环,开启
条件:AI信号2
效果:改变所有权,将塔给玩家1

测试中,我把塔1HP削至不足20%,塔1归中立玩家,中立玩家发送消息“tower1中立”;
腐败之塔自动回血,达到20%,塔1归我,中立玩家发送消息“tower1占领”。

以上两步均符合先前设计。

但当塔1再次遭受攻击,HP不足20%,中立玩家也发送了“tower1中立”的消息,但此时塔1所有权循环归我(没法持续选中)。敌方连续攻击,直至塔1被毁。此时,中立玩家发送消息“tower1占领”。

这让我有点摸不着头脑,到底是哪里出了错。难道goal 1变量此时恒为0了?

PS:在AI版讨论触发不算太离题吧{:146:}。。。

条顿武士 发表于 2016-6-26 20:11:38

weidongzi 发表于 2016-6-26 19:22
谢谢解答。AI现在能读了,但是测试时又出了问题。我的触发这么做:

触发1:循环,开启

是因为AI信号这个东西原理上比较奇怪。

(set-signal 1)

这句其实不是我们理解的发送AI信号1,而是把1号AI信号设为“开”。

相当于AI信号从1到255是255个开关,只有开和关两个状态。将一个AI信号设置为“开”之后,如果不手动关闭它,它就一直是“开”状态。而触发里面的“检测AI信号”条件实际上就是检测对应的信号是“开”还是“关”,如果是“开”就满足条件。

所以一开始箭塔血少于20%,1号AI信号开启,变成中立;之后箭塔回血,2号AI信号也开启,箭塔变回玩家1,这里都可以运行。但是之后无论箭塔HP怎么变化,实际上都是两个AI信号全部开启的状态,两个触发就一直满足条件循环运行…导致bug。

解决方法是手动添加一个关闭注销AI信号的语句:
(acknowledge-taunt this-any-computer X)

其中X的位置填入对应的AI信号编号即可。

比如下面语句中加入红色的部分:

(defrule
    (goal 1 0)
    (up-compare-goal TowerHP1 < 380) ; 血量削至腐败之塔20%以下。
=>
    (chat-to-all "tower1中立" )
    (acknowledge-taunt this-any-computer 2)
    (set-signal 1) ; 发送AI信号,触发改变所有权,将塔换至中立玩家名下。
    (set-goal 1 1)
)

(defrule
    (goal 1 1)
    (up-compare-goal TowerHP1 >= 380) ; 血量恢复至腐败之塔20%以上。
=>
    (chat-to-all "tower1占领" )
    (acknowledge-taunt this-any-computer 1)
    (set-signal 2) ; 发送AI信号,触发改变所有权,将塔换至占领玩家名下。
    (set-goal 1 0)
) ; 以下塔2-8原理相同。
AI信号1开启之前先关闭2,同样2开启之前先关闭1,这样就不会出现1和2同时开启的情况了。

一窍不开 发表于 2016-6-26 20:40:47

本帖最后由 一窍不开 于 2016-6-26 20:43 编辑

条顿武士 发表于 2016-6-26 20:11
是因为AI信号这个东西原理上比较奇怪。

(set-signal 1)

印象里这个set-signal是无法被取消的。

建议楼主使用资源法进行联动。

条顿武士 发表于 2016-6-26 20:52:45

一窍不开 发表于 2016-6-26 20:40
印象里这个set-signal是无法被取消的。

建议楼主使用资源法进行联动。

啊,我想起来了…

那么就只能使用资源和触发连接了,用cc-add-resource动作使AI作弊增加资源,然后用触发检测资源实行命令,最后用触发清零资源保证可以多次触发。

把(set-signal 1)换成(cc-add-resource <资源种类> <数量>) ,资源种类只能是是以下其中一项:

food(食物)
gold(黄金)
stone(石头)
wood(木材)

触发检测到电脑玩家有某项资源之后,进贡这项资源给盖亚,然后执行效果即可。

由于资源栏数量有限,所以楼主可以考虑使用下面的方法来检测8个箭塔。

cc-add-resource 100石头 1木材 替代(set-signal 1)
cc-add-resource 99石头 2木材 替代(set-signal 2)
等等

以此类推…检测资源的时候使用两个条件来检测即可。

weidongzi 发表于 2016-6-27 14:38:41

感谢楼上的高手们。可惜正常采集资源的玩家无法借助资源法判定。目前除了资源法还有没有方便AI与触发进行交互的方法呢?另外,进贡的资源真的只能是这四种基本资源吗?既然Aokts可以启用隐藏资源,那么理论上来说AI也可以吧?

条顿武士 发表于 2016-6-27 16:38:24

weidongzi 发表于 2016-6-27 14:38
感谢楼上的高手们。可惜正常采集资源的玩家无法借助资源法判定。目前除了资源法还有没有方便AI与触发进行交 ...
可以使用cc-add-resource作用于隐藏资源,后面依次填入资源编号和数量即可。

但是有些隐藏资源会在游戏中改变,尽量不要用,比如杀敌数之类的,而相对安全的隐藏资源,比如56号资源矿物,和15号资源肉量都是相对稳定的,可以利用。

(cc-add-resource 56 1)
(cc-add-resource 15 100)

然后用触发检测这些资源就好了~方法和普通资源是一样的,需要用到触发工作室AOKTS。

43rer3 发表于 2016-6-27 17:55:12

可以判断血量的AI?太支持了{:149:}{:149:}{:149:}
本来打算做一个,何奈对AI一窍不通{:156:}
楼楼做好了一定要发布出来注明使用方法,期待{:154:}

条顿武士 发表于 2016-6-27 19:26:46

另外楼主可以考虑加入翔鹰活跃的战役制作者QQ群498122293,大家一起讨论会比较及时的解决一些制作上的问题~

weidongzi 发表于 2016-6-27 23:29:32

条顿武士 发表于 2016-6-27 19:26
另外楼主可以考虑加入翔鹰活跃的战役制作者QQ群498122293,大家一起讨论会比较及时的解决一些制作上的问题~

哈哈,荣幸之至~
页: [1]
查看完整版本: 想写一个判断血量的简单AI,遇到一些问题