找回密码
 点一下
查看: 2255|回复: 7

帮我看看我写的-战斗AI(Jass版)

[复制链接]
发表于 2008-1-28 10:15:33 | 显示全部楼层 |阅读模式
最近上网不是很方便 呵呵~
作图需要,之前求了一个问题:

只用一个Player来完成如下的操作。
在这个Player里面产生不同的Team(就是用一个Player模仿多个Player),这些Team见面后就会厮杀,不见面时就四处走动(就好像Player1见到Player2一样)。

没有人回答我呵呵~所以只好自己动手写了一篇AI。目前我大体已经DeBug完毕了,还有一些收尾工作。 想让大家帮我看看,里面有没有什么问题,有没有什么泄露问题(最不擅长就是泄露方面的检查了-。-)

代码如下

[codes=jass]function U2I takes unit u returns integer
return u
return 0
endfunction

function I2U takes integer i returns unit
return i
return null
endfunction

function G2I takes group g returns integer
return g
return 0
endfunction

function BeAttack_Condition takes nothing returns boolean
if(IsUnitInGroup(GetFilterUnit(),udg_F_Group))then
return TRUE
endif
return FALSE
endfunction

function Attack_Each_Other_Condition takes nothing returns boolean
if(IsUnitInGroup(GetFilterUnit(),udg_Q_Group))then
return TRUE
endif
return FALSE
endfunction

function Attack takes unit whichunit returns nothing
local boolean t
local boolexpr cond
local boolean outloop
local real x
local real y
local unit beattacker
local integer attacker
local integer n = 0
local group beattack = CreateGroup()
//call DisplayTextToPlayer(Player(0),0,0,"Attack函数被调用!")
set outloop = FALSE
set x = GetLocationX(GetUnitLoc(whichunit))
set y = GetLocationY(GetUnitLoc(whichunit))
set cond = Condition(function BeAttack_Condition)
set t = GetStoredBoolean(udg_GC,I2S(U2I(whichunit)),"IsNormal")
if(t) then
call GroupEnumUnitsInRange(beattack,x,y,300.0,cond)
if(not(CountUnitsInGroup(beattack)==0 )) then
set beattacker = GroupPickRandomUnit(beattack)
call StoreBoolean(udg_GC,I2S(U2I(whichunit)),"IsNormal",FALSE)
call IssueTargetOrderById( whichunit, 851983,beattacker)
loop
set attacker = GetStoredInteger(udg_GC,I2S(U2I(beattacker)),"AttackByWho"+I2S(n))
if(attacker==0)then
call StoreInteger(udg_GC,I2S(U2I(beattacker)),"AttackByWho"+I2S(n),U2I(whichunit))
set outloop = TRUE
endif
exitwhen outloop
set n = n + 1
endloop
set n = 0
set attacker = 0
set outloop = FALSE
endif
endif
set x = 0.00
set y = 0.00
set t = FALSE
set beattacker = null
call DestroyGroup(beattack)
endfunction

function AttackBack takes unit beattacker,unit attacker returns nothing //没有加入缓存
call IssueTargetOrderById( beattacker, 851983, attacker )
endfunction

function Give_Normal_Unit_Order takes unit whichunit returns nothing
local boolean t
//call DisplayTextToPlayer(Player(0),0,0,"Give_Normal_Unit_Order函数被调用!")
set t = GetStoredBoolean(udg_GC,I2S(U2I(whichunit)),"IsNormal")
if( not(IsUnitPaused(whichunit)) and t) then
call IssuePointOrderById( whichunit, 851986, GetRandomInt(-3000,3000), GetRandomInt(-3000,3000) )
endif
endfunction

function Created_Unit takes group whichgroup,integer N returns nothing
local unit Tunit
local integer TUnitId
set TUnitId = GetStoredInteger(udg_GC,"UnitType",I2S(G2I(whichgroup)))
loop
exitwhen N==0
set Tunit = CreateUnit(Player(0),TUnitId,GetRandomInt(-3000,1000),GetRandomInt(-3000,1000),bj_UNIT_FACING)
call GroupAddUnit(whichgroup,Tunit)
call StoreBoolean(udg_GC,I2S(U2I(Tunit)),"IsNormal",TRUE)
call StoreInteger(udg_GC,I2S(U2I(Tunit)),"AttackByWho",0)
call Give_Normal_Unit_Order(Tunit)
set Tunit = null
set N = N -1
endloop
endfunction

function Unit_Status takes group whichgroup,unit whichunit returns nothing
local integer attacker
local boolean outloop
local integer n = 0
//call DisplayTextToPlayer(Player(0),0,0,"Unit_Status函数被调用!")
if ((IsUnitDeadBJ(whichunit)==true))then
loop
set attacker = GetStoredInteger(udg_GC,I2S(U2I(whichunit)),"AttackByWho"+I2S(n))
if(not(attacker==0))then
call StoreBoolean(udg_GC,I2S(attacker),"IsNormal",TRUE)
set n = n + 1
set outloop = FALSE
endif
if(attacker==0)then
set outloop = TRUE
endif
exitwhen outloop
endloop
call RemoveUnit(whichunit)
call GroupRemoveUnit(whichgroup,whichunit)
call FlushStoredMission(udg_GC,I2S(U2I(whichunit)))
call Created_Unit(whichgroup,1)
endif
endfunction

function Check_Unit_IsDied_Status_Q takes nothing returns nothing
call Unit_Status(udg_Q_Group,GetEnumUnit())
endfunction

function Check_Unit_IsDied_Status_F takes nothing returns nothing
call Unit_Status(udg_F_Group,GetEnumUnit())
endfunction

function Check_Unit_IsNormal_Status takes nothing returns nothing
call Give_Normal_Unit_Order(GetEnumUnit())
endfunction

function Check_Unit_Around_Status takes nothing returns nothing
call Attack(GetEnumUnit())
endfunction

function Check_IsNoraml_Status takes nothing returns nothing
call ForGroup(udg_F_Group,function Check_Unit_IsNormal_Status)
call ForGroup(udg_Q_Group,function Check_Unit_IsNormal_Status)
endfunction

function Check_IsDied_Status takes nothing returns nothing
call ForGroup(udg_F_Group,function Check_Unit_IsDied_Status_F)
call ForGroup(udg_Q_Group,function Check_Unit_IsDied_Status_Q)
endfunction

function Check_Around_Status takes nothing returns nothing
call ForGroup(udg_Q_Group,function Check_Unit_Around_Status)
endfunction



function ChangeRandomSeed takes nothing returns nothing
//local timer tm=GetExpiredTimer()
//call SetRandomSeed(T2I(tm))
endfunction

function InitTrig_AI takes nothing returns nothing
endfunction[/codes]

具体的测试地图如下:

战斗AI.w3x (40 KB, 下载次数: 42)


目前正在解决的问题有:

1·Unit可能随即产生在地图那些不能移动的区域里面(比如深水区)
2·攻击模式为A攻击B,B攻击C 大鱼吃小鱼的模式,若要互相攻击起来会出现Bug(比如A攻击B,B也攻击A)

这两个正在解决中,大家帮我看看还有没别的一些毛病。 谢谢了 诸位。
发表于 2008-1-28 16:54:36 | 显示全部楼层
1.-
set x = GetLocationX(GetUnitLoc(whichunit))
set y = GetLocationY(GetUnitLoc(whichunit))<--------这个东西很么效率,可以用GetUnitX(u)这样的东西来直接获得单位坐标。
----------------------------------------------------------------------
2.-
if(not(CountUnitsInGroup(beattack)==0 )) then
set beattacker = GroupPickRandomUnit(beattack)
call StoreBoolean(udg_GC,I2S(U2I(whichunit)),"IsNormal",FALSE)
call IssueTargetOrderById( whichunit, 851983,beattacker)
loop

这个操作纯粹属于浪费,因为CountUnitsInGroup(beattack)本身就是对单位组进行了一次操作,可以直接用全局变量保存攻击单位,用ForGroup在另外的函数里面发布命令。
------------------------------------
3.-
function Created_Unit takes group whichgroup,integer N returns nothing
local unit Tunit
local integer TUnitId
set TUnitId = GetStoredInteger(udg_GC,"UnitType",I2S(G2I(whichgroup)))
loop
exitwhen N==0
set Tunit = CreateUnit(Player(0),TUnitId,GetRandomInt(-3000,1000),GetRandomInt(-3000,1000),bj_UNIT_FACING)
call GroupAddUnit(whichgroup,Tunit)
call StoreBoolean(udg_GC,I2S(U2I(Tunit)),"IsNormal",TRUE)
call StoreInteger(udg_GC,I2S(U2I(Tunit)),"AttackByWho",0)
call Give_Normal_Unit_Order(Tunit)
set Tunit = null
set N = N -1
endloop
endfunction
这个函数是干什么的。。。。。
回复

使用道具 举报

发表于 2008-1-28 17:10:02 | 显示全部楼层
handle类(包括unit,group等)转成integer可以用h2i一个函数代替u2i,g2i这些,因为unit、group这些都是继承自handle的
回复

使用道具 举报

 楼主| 发表于 2008-1-28 21:22:04 | 显示全部楼层
谢谢 eff  和 zhuzeitou ^_^

照着eff的1 、2两条更改了代码。 代码如下:

[codes=jass]function U2I takes unit u returns integer
      return u
      return 0
endfunction

function I2U takes integer i returns unit
    return i
    return null
endfunction

function G2I takes group g returns integer
      return g
      return 0
endfunction

function B2I takes boolean b returns integer
      return b
      return 0
endfunction


//检测周围是否有可攻击的目标,检测到一个后就不再检测
function BeAttack_Condition takes nothing returns boolean
   if(udg_BeAttackCond)then
        if(IsUnitInGroup(GetFilterUnit(),udg_F_Group))then
            set udg_BeAttackCond = FALSE
            return TRUE
        endif
    endif
    return FALSE
endfunction


//查看Unit周围是否有可攻击的目标 ,若有的话则攻击,没有的话则什么都不做
function Attack takes unit whichunit returns nothing
    local boolean isnormal
    local boolean outloop
    local boolexpr cond
    local real x
    local real y
    local unit beattacker
    local integer attacker   
    local integer n = 0
    local group beattack = CreateGroup()
    set isnormal = GetStoredBoolean(udg_GC,I2S(U2I(whichunit)),"IsNormal")
    set x = GetUnitX(whichunit)
    set y = GetUnitY(whichunit)
    set outloop = FALSE
    set cond = Condition(function BeAttack_Condition)
    set attacker = GetStoredInteger(udg_GC,I2S(U2I(whichunit)),"AttackByWho"+I2S(n))
    if(isnormal) then
        set udg_BeAttackCond = TRUE
        call GroupEnumUnitsInRange(beattack,x,y,300.0,cond)
        if(not(udg_BeAttackCond))then
            call StoreBoolean(udg_GC,I2S(U2I(whichunit)),"IsNormal",FALSE)
            set beattacker = FirstOfGroup(beattack)
            call IssueTargetOrderById( whichunit, 851983,beattacker)
            loop
                set attacker = GetStoredInteger(udg_GC,I2S(U2I(beattacker)),"AttackByWho"+I2S(n))
                if(attacker==0)then
                    call StoreInteger(udg_GC,I2S(U2I(beattacker)),"AttackByWho"+I2S(n),U2I(whichunit))
                    set outloop = TRUE
                endif
                exitwhen outloop
                set n = n + 1
            endloop
            set n = 0
            set attacker = 0
            set outloop = FALSE   
        endif              
    endif
    call DestroyGroup(beattack)
endfunction

//对那些正常状态的Unit发出移动到某某地方的命令
function Give_Normal_Unit_Order takes unit whichunit returns nothing
    local boolean t
    set t = GetStoredBoolean(udg_GC,I2S(U2I(whichunit)),"IsNormal")
    if( not(IsUnitPaused(whichunit)) and t) then
        call IssuePointOrderById( whichunit, 851986, GetRandomInt(-3000,3000), GetRandomInt(-3000,3000) )
    endif
endfunction

//在随机的地点产生某一个单位组(可能是强盗组,也可能是农民组)的单位,并命令其移动到某个地点
function Created_Unit takes group whichgroup,integer N returns nothing
    local unit Tunit
    local integer TUnitId
    set TUnitId = GetStoredInteger(udg_GC,"UnitType",I2S(G2I(whichgroup)))
    loop
        exitwhen N==0
        set Tunit = CreateUnit(Player(0),TUnitId,GetRandomInt(-3000,3000),GetRandomInt(-3000,3000),bj_UNIT_FACING)
        call GroupAddUnit(whichgroup,Tunit)
        call StoreBoolean(udg_GC,I2S(U2I(Tunit)),"IsNormal",TRUE)
        call StoreInteger(udg_GC,I2S(U2I(Tunit)),"AttackByWho",0)
        call Give_Normal_Unit_Order(Tunit)
        set Tunit = null
        set N = N -1
    endloop   
endfunction


//检测单位是否已经死亡,如果死亡的话则清除该单位,让攻击他的单位的状态变为正常
function Unit_Status takes group whichgroup,unit whichunit returns nothing
    local integer attacker
    local boolean outloop
    local integer n = 0
    if ((IsUnitDeadBJ(whichunit)==true))then
        loop
            set attacker = GetStoredInteger(udg_GC,I2S(U2I(whichunit)),"AttackByWho"+I2S(n))
            if(not(attacker==0))then
                call StoreBoolean(udg_GC,I2S(attacker),"IsNormal",TRUE)
                call Give_Normal_Unit_Order(I2U(attacker))
                set n = n + 1
                set outloop = FALSE
            endif
            if(attacker==0)then
                set outloop = TRUE
            endif
            exitwhen outloop
        endloop
        call RemoveUnit(whichunit)
        call GroupRemoveUnit(whichgroup,whichunit)
        call FlushStoredMission(udg_GC,I2S(U2I(whichunit)))
        call Created_Unit(whichgroup,1)
    endif     
endfunction
   
function Check_Unit_IsDied_Status_Q takes nothing returns nothing
    call Unit_Status(udg_Q_Group,GetEnumUnit())
endfunction

function Check_Unit_IsDied_Status_F takes nothing returns nothing
    call Unit_Status(udg_F_Group,GetEnumUnit())
endfunction

function Check_Unit_IsNormal_Status takes nothing returns nothing
    call Give_Normal_Unit_Order(GetEnumUnit())
endfunction

function Check_Unit_Around_Status takes nothing returns nothing
    call Attack(GetEnumUnit())
endfunction

function Check_IsNoraml_Status takes nothing returns nothing
    call ForGroup(udg_F_Group,function Check_Unit_IsNormal_Status)
    call ForGroup(udg_Q_Group,function Check_Unit_IsNormal_Status)
endfunction

function Check_IsDied_Status takes nothing returns nothing
    call ForGroup(udg_F_Group,function Check_Unit_IsDied_Status_F)
endfunction

function Check_Around_Status takes nothing returns nothing
    call ForGroup(udg_Q_Group,function Check_Unit_Around_Status)
endfunction


//=========================================================
//具体的调用函数如下,当输入debug则开始调用函数
//=========================================================

function Trig_DeBug_Actions takes nothing returns nothing
      local timer tm1=CreateTimer()
      local timer tm2=CreateTimer()
      local timer tm3=CreateTimer()
      local unit Tunit
      call StoreInteger(udg_GC,"UnitType",I2S(G2I(udg_F_Group)),'hpea')
      call StoreInteger(udg_GC,"UnitType",I2S(G2I(udg_Q_Group)),'njks')
      call Created_Unit(udg_Q_Group,50)
      call Created_Unit(udg_F_Group,50)
      call TimerStart(tm1,10,true,function Check_IsNoraml_Status)
      call TimerStart(tm2,2,true,function Check_IsDied_Status)
      call TimerStart(tm3,2,true,function Check_Around_Status)
endfunction

//===========================================================================
function InitTrig_DeBug takes nothing returns nothing
    set gg_trg_DeBug = CreateTrigger(  )
    call TriggerRegisterPlayerChatEvent( gg_trg_DeBug, Player(0), "debug", true )
    call TriggerAddAction( gg_trg_DeBug, function Trig_DeBug_Actions )
endfunction[/codes]

现在我知道的Bug是发生在Attack函数里面,我本初的想法是强盗Group(udg_Group_Q)在周围没有农民(udg_Group_F)的时候攻击周围的强盗。于是就用了两组 call GroupEnumUnitsInRange(beattack,x,y,300.0,cond) 只是更改了cond的条件,让找不到农民的时候,更改条件 来找
周围是否有没有强盗。不过我把两个Call放在同一个函数里面不管临时的Group是否都为beattack,总是会发生异常的。

希望大家再帮我看看 找找哪里还有毛病了 谢谢了 万分感激 o(∩_∩)o...

ps:zhuzeitou的那个ReturnBug问题我没改,因为要改的地方太多了。。懒得弄了 -.-|||
回复

使用道具 举报

发表于 2008-1-28 22:13:37 | 显示全部楼层
实际上,使用缓存保存单位名字是很不推荐的做法,因为缓存会在存储数据的时候不定时丢失数据。。。。这个根本就是无规律事件
回复

使用道具 举报

 楼主| 发表于 2008-1-29 09:47:53 | 显示全部楼层
我也不是很喜欢用这个东西,刚接触的时候还算喜欢这个东西,不过程序一但有时候需要多次存储和调用缓存的话就会变得很卡,是不是因为缓存是存储在硬盘上面啊。。。。
要是不用缓存是不是就要用数组啊,可是数组好像只能用一元的,储存起来总是感觉不爽。。。
不用缓存还有别的方法么?

感觉自己要放弃GameCache的样子。。。。。一用自己的程序就变的很卡。-.-|||
回复

使用道具 举报

发表于 2008-1-29 12:23:52 | 显示全部楼层
你可以研究研究这个。DataSystem.
缓存的问题好像和字符串初始化有关系,在字符串数量达到临界区域就会出问题。

给你研究研究里面的函数把。

LT_New.rar

784 KB, 下载次数: 1090

回复

使用道具 举报

发表于 2008-2-5 17:24:53 | 显示全部楼层
zealotwang就是zealotone吧?
呵呵
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-5-3 11:13 , Processed in 0.164218 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表