达真堪布火施仪轨视频:魔兽争霸3人工智能脚本(AI JASS)初级教程 - 游戏策划

来源:百度文库 编辑:九乡新闻网 时间:2024/05/07 18:19:08

魔兽争霸3人工智能脚本(AI JASS)初级教程

作者:马晓超发表于 2011-2-22 12:19:32 评论(0) 阅读(576) JASS与其他的面向流程性质的编程语言很类似,所以在阅读以下内容之前,首先应该对流程性质的编程以及TRIGGER JASS有着一定的了解。了解JASS语言并有一定的基础之后,你将很快的了解AI JASS。

AI JASS的概念

最主要的是理解AI线程(Threads)的概念。

线程是什么?

线程就象TRIGGER的一个循环判断语句,线程会不停的判断在线程程序列表内所缺少的元素,并去按照线程的指令排放顺序去完成它。就象碗中的饭,有即吃,有即吃,有即吃,Loop......

为什么不用TRIGGER去完成电脑的人工智能呢?

由于使用TRIGGER相比之下可能会消耗大量的内存,所以,最好用AI线程来完成电脑的人工智能。

注意: 线程只针对单个玩家进行运作。

AI的类型(Melee AI 和 Campaign AI )

Melee AI 对战AI基本上完全可以利用WORLDEDITOR自带的AI编辑器(AI Edior)完成

Campaign AI 战役AI(即“非对战AI”),可以详细了解以下内容即可制作一般常用的战役AI

注:战役AI的用途十分广泛,完全可以利用其制作生存,3C,TD等类型的地图,并且免除了不停使用TRIGGER创造单位所带来的内存泄露。

线程(Threads)和触发器(Trigger)的区别AI脚本只能使用JASS函数库common.j和common.ai中的函数和量Trigger脚本只能使用common.j和Blizzard.j中的函数和量线程只应用于AI脚本(AI JASS), 不能用于触发器脚本(Trigger Jass)触发器只应用用于触发器脚本(Trigger Jass),不能用于AI脚本(AI JASS)
通常, 当AI脚本开始运行时只创建一个线程, 创建更多的线程可以用comman.j的本地函数:

native StartThread takes code func returns nothing

运行方式的区别在于线程一旦开启即可自动运转,触发器必须调用或者借助事件的发生才可以运行。调用 call StartThread(function myfunc) 将创建一个从函数myfunc开始执行的线程。

调用 call SleepForever() 使线程永久性的关闭

  • 每个玩家最多可以拥有6个线程(包括一开始执行的主线程在内,当一个玩家有6个线程数时,调用StartThread()的语句将被忽略. ) *线程不能回收, 当你为某玩家创建了5个自定义线程,将无法为该玩家创建更多的线程。
  • 局域性的全局状态,在同一玩家中的所有线程都共享全局状态(包括变量). 即是修改某个全局变量, 修改后的值在此玩家的所有线程中都是可见的。
  • 当新线程创建时, 线程立即生效。
  • 当线程让步执行时, 创建此线程的父线程将继续执行.

线程在以下的情况让步执行, 返回父线程

  • 当线程中的操作码(opcode)超出限制, 线程会自动休眠 1 秒
  • 当线程中用使用 Sleep(n), 线程将休眠 n 秒, 然后继续执行.

线程在以下情况会中止, 返回父线程

  1. 如果 call StartThread(null)中, 线程中止
  2. 当线程的主函数返回, 线程中止.
    (StartThread()中之间调用的函数就是主函数.)
  3. 当线程中使用没有声明的变量, 线程中止. 在使用之前, 变量必须声明.
  4. 当线程中出现零为被除数时, 线程中止
  5. 线程主函数出现语法错误.
    注意: 虽然AI脚本可以使用大部分common.j的库函数, 但有些类型的函数在AI不能正常工作, 如:返回字符串类型(string)的本地函数, 如I2S(), SubString()等需要以code, trigger, boolexpr 等类型数据为参数的本地函数, 如触发器函数, 队列函数(ForGroup, 等)

    注意: AI中不可以使用Blizzard.j的函数, 触发器中也不可以使用common.ai的函数, AI和触发器都可以使用common.j的函数(当然, 对于AI, 还受上面所说的限制)

    common.ai和common.j是写AI时可以调用和参考库文件, 要研究AI, 先去读这2个文件.******************************************************************

跨脚本通讯(Inter-Script Communication)

在游戏中, 可能会有多个独立的Jass脚本文件同时运行. 比如在对战地图中的游戏, 运行触发器脚本文件的同时, 也可能运行了每个电脑玩家的AI脚本文件. 每个脚本文件之间的全局变量不是共享的. 所以, 一个电脑玩家的AI脚本中设置的全局变量不会影响另一个电脑玩家的AI脚本的执行.

触发器脚本也不可以和AI脚本共享全局变量. 但可以用传递命令的方法进行脚本之间的数据交换. 命令由一对数值型数据(integer)组成: 命令值(command value)和数据值(data value).

从触发器脚本向AI脚本发出通讯命令, 可以使用common.j中定义的以下本地函数:

native CommandAI takes player num,

nteger command, integer data returns nothing

固定参数:

player num //玩家
integer command //命令
integer data //命令数据

//--------------------------------------------------------------------
constant integer M1 = 60 实际上是时间!
constant integer M2 = 2*60
constant integer M3 = 3*60
constant integer M4 = 4*60
constant integer M5 = 5*60
constant integer M6 = 6*60
constant integer M7 = 7*60
constant integer M8 = 8*60
constant integer M9 = 9*60
constant integer M10 = 10*60
constant integer M11 = 11*60
constant integer M12 = 12*60
constant integer M13 = 13*60
constant integer M14 = 14*60
constant integer M15 = 15*60

constant integer EASY = 1
constant integer NORMAL = 2
constant integer HARD = 3
constant integer INSANE = 4 // not used

constant integer MELEE_NEWBIE = 1
constant integer MELEE_NORMAL = 2
constant integer MELEE_INSANE = 3

constant integer ATTACK_CAPTAIN = 1
constant integer DEFENSE_CAPTAIN = 2
constant integer BOTH_CAPTAINS = 3

constant integer BUILD_UNIT = 1
constant integer BUILD_UPGRADE = 2
constant integer BUILD_EXPAND = 3

constant integer UPKEEP_TIER1 = 50
constant integer UPKEEP_TIER2 = 80


JASS函数库common.ai的全局变量(可以更改,也可以自行增加,以下内容会经常在AI脚本中使用):player ai_player //AI玩家 integer sleep_seconds
//等待时间
integer total_gold = 0 //总计的金钱 integer total_wood = 0
//总计的木材
integer gold_buffer = 0
// usually for potion money
integer difficulty = NORMAL
//难度,默认为中等难度
integer exp_seen = 0
integer racial_farm = 'hhou'
integer hero_id = 'Hamg'
//第一个英雄的ID,默认为圣骑士
integer hero_id2 = 'Hmkg'
//第二个英雄的ID,默认为山丘之王
integer hero_id3 = 'Hpal'
//第三个英雄的ID,默认为大法
integer array skill
integer array skills1
integer array skills2
integer array skills3
integer max_hero_level = 0
integer array harass_qty
integer array harass_max
integer array harass_units
integer harass_length = 0
防守单位的全局变量
例子:防守单位defense_units[defense_length]的数量为defense_qty[defense_length]
integer array defense_qty //设置防守单位的数量
integer array defense_units //设置防守的单位
integer defense_length = 0 //单位Index
建造的全局变量
为了区分建造的种类,BLZ为建造的全局变量设置了4类例子:建造单位build_type[build_length]的数量为build_qty[build_length]
integer array build_qty //建造的数量 设置建造单位的数量
integer array build_type //建造的种类 普通单位类(包括单位和建筑)
integer array build_item //购买物品的种类 物品类
integer array build_town //建造基地的种类 基地类
integer build_length = 0
设置采集工人的数量
integer campaign_gold_peons = 5 //主基地采集金子的人数
integer campaign_wood_peons = 3 //住基地采集木材的人数
integer campaign_basics_speed = 5
integer min_creeps = -1 integer max_creeps = -1
游戏初试设置的全局变量
boolean harvest_town1 = true
boolean harvest_town2 = true
boolean harvest_town3 = true
boolean do_campaign_farms = true
//自动制造战役AI 提供人口的建筑
boolean two_heroes = false
//双英雄
boolean allow_air_creeps = false
//空中的中立单位(假如有,AI会针对性的发展)
boolean take_exp = false //<

一般战役AI常用函数

CampaignAI takes integer farms, code heroes returns nothing
是BLZ在COMMON.AI中设置的一个简便函数,直接初始化战役AI
farms - 提供AI玩家人口的建筑类型
heroes - 指向设置英雄的ID的CODE

SetReplacements takes integer easy, integer med, integer hard returns nothing
尚未研究的函数,一般用法为:
call SetReplacement( 2, 2, 4 )
easy - 游戏难度为简单所赋的值
med - 游戏难度为普通所赋的值
hard - 游戏难度为困难所赋的值

native SetCaptainHome takes integer which, real x, real y returns nothing
设置攻击组队长在家的点?
which - 什么的聚集点,参数有:
constant integer ATTACK_CAPTAIN = 1 进攻的点
constant integer DEFENSE_CAPTAIN = 2 防御的点
constant integer BOTH_CAPTAINS = 3 进攻和防御的点
x - X坐标
Y - Y坐标

SetBuildUnit takes integer qty, integer unitid returns nothing
指令AI玩家制造(所有类型的建造,包括升级)
qty - 数量
unitid - 单位类型

SetBuildUnitEx takes integer easy, integer med, integer hard, integer unitid returns nothing
指令AI玩家制造单位按照游戏难度
easy - 简单时候的数量
med - 普通时候的数量
hard - 困难时候的数量
unitid - 单位类型

CampaignDefender takes integer level, integer qty, integer unitid returns nothing
设置防守单位的数量

CampaignDefenderEx takes integer easy, integer med, integer hard, integer unitid returns nothing
设置防守单位的数量,
按难度 call WaitForSignal() 等待TRIGGER发出AI指令,当堆积的指令数量不等于0时,继续进行AI线程
进攻组的指令
function InitAssaultGroup takes nothing returns nothing
初始化进攻组,设置全局变量harass_length = 0
CampaignAttacker takes integer level, integer qty, integer unitid returns nothing
增加进攻组的进攻单位
qty - 数量
unitid - 单位类型

CampaignAttackerEx takes integer easy, integer med, integer hard, integer unitid returns nothing
增加进攻组的进攻单位,按游戏难度
easy - 简单时候的数量
med - 普通时候的数量
hard - 困难时候的数量
unitid - 单位类型

SuicideOnPoint takes integer seconds, player p, integer x, integer y returns nothing
设置进攻的玩家的点seconds 发起进攻等待的时间,
常量参数有
constant integer M1 = 60
constant integer M2 = 260
constant integer M3 = 360
constant integer M4 = 460
constant integer M5 = 560
constant integer M6 = 660
constant integer M7 = 760
constant integer M8 = 860
constant integer M9 = 960
constant integer M10 = 1060
constant integer M11 = 1160
constant integer M12 = 1260
constant integer M13 = 1360
constant integer M14 = 1460
constant integer M15 = 1560
p - 目标玩家

SuicideOnUnits takes integer seconds, player p returns nothing
设置进攻的目标玩家seconds


一般战役AI的制作方案

参看BLZ在战役中所制作的AI脚本“n08_green.ai”来了解怎么制作AI

//变量 进攻的目标玩家
globals
player user = Player(1)
endglobals function main takes nothing returns nothing //AI初试设置
call CampaignAI(ZIGGURAT_1,null)
call SetReplacements(2,2,4)
call SetCaptainHome(ATTACK_CAPTAIN,4161,-4668 )
call SetCaptainHome(DEFENSE_CAPTAIN,5218,-6441 )
set campaign_wood_peons = 2 //需要建造的建筑以及单位
call SetBuildUnit( 1, NECROPOLIS_1 )
call SetBuildUnit( 1, ACOLYTE )
call SetBuildUnit( 1, UNDEAD_MINE )
call SetBuildUnit( 1, GRAVEYARD )
call SetBuildUnit( 8, ZIGGURAT_1 )
call SetBuildUnit( 2, CRYPT )
call SetBuildUnit( 1, UNDEAD_ALTAR )
call SetBuildUnit( 1, NECROPOLIS_2 )
call SetBuildUnit( 2, SLAUGHTERHOUSE )
call SetBuildUnit( 1, DAMNED_TEMPLE )
call SetBuildUnit( 1, NECROPOLIS_3 )
call SetBuildUnit( 2, BONEYARD )
call SetBuildUnit( 5, ACOLYTE )
call SetBuildUnit( 8, ZIGGURAT_2 ) //防守单位
call CampaignDefenderEx( 1,1,2, ABOMINATION )
call CampaignDefenderEx( 1,1,1, GARGOYLE )
call CampaignDefenderEx( 1,1,1, FROST_WYRM )
call CampaignDefenderEx( 1,1,1, CRYPT_FIEND )
call CampaignDefenderEx( 1,1,1, DREAD_LORD ) //TRIGGER发出指令就开始进行下面的AI进程
call WaitForSignal() //进攻,制造
//WAVE 1
call InitAssaultGroup()
call CampaignAttackerEx( 6,6,8, GARGOYLE )
call SuicideOnPlayerEx(M5,M5,M3,user)
call SetBuildUpgrEx( 1,1,1, UPG_FIEND_WEB )
call SetBuildUpgrEx( 1,1,1, UPG_CANNIBALIZE )
call SetBuildUpgrEx( 1,1,1, UPG_UNHOLY_STR )
call SetBuildUpgrEx( 1,1,1, UPG_CR_ATTACK )
//WAVE 2
call InitAssaultGroup()
call CampaignAttackerEx( 6,6,8, GARGOYLE )
call CampaignAttackerEx( 2,2,4, CRYPT_FIEND )
call CampaignAttackerEx( 1,1,2, FROST_WYRM )
call SuicideOnPlayerEx(M6,M6,M4,user)
//WAVE 3
call InitAssaultGroup()
call CampaignAttackerEx( 6,6,8, GARGOYLE )
call CampaignAttackerEx( 2,2,4, CRYPT_FIEND )
call CampaignAttackerEx( 1,1,2, FROST_WYRM )
call CampaignAttackerEx( 1,1,1, DREAD_LORD )
call SuicideOnPlayerEx(M6,M6,M4,user)
call SetBuildUpgrEx( 2,2,2, UPG_UNHOLY_STR )
call SetBuildUpgrEx( 2,2,2, UPG_CR_ATTACK )
call SetBuildUpgrEx( 1,1,1, UPG_SKEL_LIFE )
call SetBuildUpgrEx( 1,1,1, UPG_WYRM_BREATH )
//WAVE 4
call InitAssaultGroup()
call CampaignAttackerEx( 2,2,3, GARGOYLE )
call CampaignAttackerEx( 5,5,6, CRYPT_FIEND )