为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

魔兽地图制作文档解释

2017-09-30 50页 doc 118KB 48阅读

用户头像

is_353097

暂无简介

举报
魔兽地图制作文档解释魔兽地图制作文档解释 必须 最后列举一下常用的快捷指令 地形编辑器是地图编辑器的主要模块。在这里用户可以设计和编辑地形放置单位和装饰物。 地形面板 要想修改地形,首先使用’T’键或者’窗口’菜单中选择新建地形面板,打开地形面板。一旦 地形面板被打开,则可以使用四个工具。 地形面板上的第一个工具是应用质材。通过点击任何一种场景样式,选择它并放置在您的地图中。甚至您可以在地图上放置荒芜之地和边界质材。边界是一种 特殊的地形,任何单位都无法穿越它。它类似于地图边缘的黑色区域。荒芜之地是不死族建筑周围延伸出来的地形。通过...
魔兽地图制作文档解释
魔兽地图制作文档解释 必须 最后列举一下常用的快捷指令 地形编辑器是地图编辑器的主要模块。在这里用户可以设计和编辑地形放置单位和装饰物。 地形面板 要想修改地形,首先使用’T’键或者’窗口’菜单中选择新建地形面板,打开地形面板。一旦 地形面板被打开,则可以使用四个工具。 地形面板上的第一个工具是应用质材。通过点击任何一种场景样式,选择它并放置在您的地图中。甚至您可以在地图上放置荒芜之地和边界质材。边界是一种 特殊的地形,任何单位都无法穿越它。它类似于地图边缘的黑色区域。荒芜之地是不死族建筑周围延伸出来的地形。通过随机放置变量(预览中)允许编辑器自动从选择的类型中随机放置地形,而不是固定一 种的效果。 第二个工具是放置峭壁选项。这个选项允许用户添加和删除地图上的峭壁、浅水、深水和斜 坡。用户不但能够通过画笔增加/减少峭壁区域,而且能够改变已经放置的峭壁。 第三个工具是改变高度选项。这部分包括: 圆形山脉 - 允许用户制造圆形的山脉,按住Shift键,左键点击可以制造出圆形的山谷。 高原 - 允许用户制造圆形山脉和山谷之间的高地。 碎裂工具 - 这个工具可以制造破裂的地面。 光滑工具 - 这个工具可以进行平滑地面。 最后一个选项用来改变画笔的形状和大小。 修改地形 用户可以通过修改地形,修改所选择的地形,甚至是创建新的地形。 在创建自定义地形之前,您必须首先知道地形被归结为一种质材。有些地形在质材页中占用一页,有的则占用更多的页面。用户最多能够设置12页的地形。而且在开始的时候这些质材页都是被占满的。所以在创建新的地形之前,请首先删除足够的地形。但是无论如何您不 能够删除标有红框的地形 单位面板 为了在地图上放置单位,您可以通过键盘上的’U’键或者在打开的面板上拖动下拉列表选择 单位面板 单位面板的第一个菜单是用来决定单位所有者的: 玩家 X - 这里有玩家的列表,玩家1,玩家2一直到地图允许玩家的最大上限。这个玩家 的最大上限可以在玩家属性中调整。 敌对中立单位 - 敌对的中立单位无视你所属的阵营。它是地图上所有玩家的敌人。甚至包 括电脑控制的阵营。但是它们之间并不敌对。 友好中立单位 - 这些单位甚至在受到攻击的时候仍然不会反击。有些单位玩家是无法攻击 的。 物品 - 这里您可以选择一个物品并直接放置到地图上。但是不能够决定野外生物掉落的物 品。如果您想设定掉落的物品,请双击所放置的单位,然后在单位属性中设置。 第二个菜单是种族选项,允许用户选择要防止的单位所在的种族。 第三个菜单是单位的分类: 对战 - 设定单位在对战模式中出现。 战役 - 设定单位在战役模式中出现。 自定义 - 单位是在对象编辑器中创建的。 第四个选项是决定在什么地方能够遇到单位。 玩家的单位(兽族,人族,暗夜精灵族和不死族)被分为了五类: 单位 - 这类是每个种族的非英雄单位。这里要注意一点。比如不死族的石像鬼,它具有两 个状态。所以你将有两个图标代表石像鬼的正常状态和石像状态。 建筑 - 这里包括每个种族能够建造的建筑,包括起始位置。如果选择暗夜精灵族,则在这 部分只能够放下扎根版本的建筑。 英雄 - 每个种族拥有的英雄。 拔起建筑 - 这个选项只针对特定的种族暗夜精灵族。在这里能够放置拔起的建筑。 特殊 - 这部分是战役中的特殊单位。 就象前面的分类一样,中立单位被分为两类。这些单位根据等级和所属地貌,被分为若干组。 物品面板也具有一个菜单,能够通过选择,依据等级分成若干组。 单位属性 在放置一个单位之后,你可以进一步修改它。双击你所放置的单位,或者选择 它之后点击编 辑菜单中的编辑属性。你能够编辑的单位属性有: 通用 玩家 - 通过这项,你能够调整该单位所属的阵营:玩家X,敌对中立,友好中立。 面向 - 你可以通过手动点击肩头或者输入数字,调整单位所面对的方向。 生命值 - 调整该单位的初始生命值。注意,这里通过百分比表示,而不是具体数字。就象 魔法值一样。 魔法值 - 调整该单位的初始魔法值。注意,这里通过百分比表示,而不是具体数字。就象 生命值一样。 等级 - 调整英雄的初始等级。这将会影响单位的最大魔法和生命值。 目标获取距离 - 设置单位能够获取对象的距离。这将会影响单位攻击敌对单位时的效果。 使用默认属性 - 允许英雄拥有不同的力量、敏捷和智力值。 魔法技能 - 这个选项决定单位所具有的魔法能力。而且可以设定拥有技能所需要的条件。并且可以设定英雄升级时能够选择的能力。注意:英雄的终极技能在英雄等级达到六级之前是无法修改的。例如:你如果想圣骑士拥有复生技能,就必须将他的等级提高到六级。 物品栏 - 设定英雄开始时拥有的物品。点击物品槽旁边的按钮,就可以进行选择。 掉落物品 在这里你可以设定单位被杀死时掉落的物品。可以通过在物品掉落部分分配实现。 新建设定 - 为了能够设定物品掉落。必须首先创建一个物品设定。这些设定之间能够相互的影响,分配掉落几率。你如果想能够掉落多个物品,就必须设置多个物品掉落设定。 删除设定 - 删除一个已经完成的设定。 新建物品 - 选择一个新的物品加入到物品掉落设定中。 删除物品 - 删除一个已经加入物品掉落设定中的物品。 编辑物品 - 将已经设定好的物品和其他物品进行交换。 随机分组 随机分组将会在一个特定的区域内随机设定一组野外生物,这些生物能够固定的选择某个等 级物品掉落,并且能够保持一个稳定的能力。野外生物的具体情况在地图被读入的时候决定。 如果想设定随机分组,首先在工具--高级菜单中选定随机分组。然后选择添加分组来设定所创建的第一组怪物。最多能够设定十组。然后再设定哪种怪物能够被选中,和出现的几率。 然后选定随机分组出现的位置。并且可以通过随机单位属性对话框进行属性设置。 在随机分组的随机单位中,你可以设定每个单位的属性和可能出现的位置。 装饰物面板 要放置装饰物,可以使用’D’键,或者在面板菜单中选择装饰物。装饰物是所有不能够在游戏中控制的对象的统称。但是树木并不属于这个类别,因为树木是一种能够消耗的资源。 装饰物通过所属的场景不同被分成若干类别。虽然每个场景拥有的装饰物的样子并无差别, 但是并不是每个场景都包含所有的装饰物。 接下来介绍装饰物面板上的一些按钮: 随机旋转 - 设定装饰物随机朝向某个方向。 随机放大 - 对称 - 当这个按钮被按下时,所放置的装饰物将会被随机放大一定的比例。但 是仍然保持对称:所有变量(X,Y和Z轴)都增加相同的程度。 随机放大 - Z轴 - 当这个按钮被按下时,所放置的装饰物将会被在Z轴上随机放大一定的 比例。 随机放大 - XY轴 - 当这个按钮被按下时,所放置的装饰物将会被在XY轴上随机放大一定 的比例。 防止随机属性的装饰物 - 绝大多数装饰物都不只具有一个样子。这个选项被选定的时候, 编辑器将会随机设定一个样子。 菜单中的最后两项是能够使用的装饰物和画笔菜单。 装饰物属性 当装饰物被放置好之后,你可以象对单位一样编辑它。这个操作可以通过双击它,或者在编 辑菜单中选择编辑属性进行。之后你可以进行以下选项的设定,但是这些选项不是对于所有 的装饰物的。 形状变化 - 一些装饰物拥有不止一个外观,你可以选择一个新的外观。 旋转 - 一些装饰物能够面向多个方向,可以在这里设定。 缩放 (%) - 你可以修改一些装饰物在X,Y,Z轴上的缩放程度。 生命值 (%) - 你可以设定装饰物的起始生命值。甚至可以设置成零。 物品掉落 - 你可以设置装饰物被摧毁之后能够小略的物品。就象普通单位一样。 镜头面板 通过键盘上的’M’键或者在面板菜单中选择镜头来选择镜头菜单。这个面板将依附触发器而存在。如果你在触发器中没有设置有关观看镜头的动作,那么用户甚至将无法知道镜头的存 在。 在镜头面板上有以下的选项: 创建 - 创建一个新镜头,并设置镜头观看你所有的地图。 下面的选项在你没有创建镜头之前是不能使用的。 观看地图 - 通过当前的镜头查看地图。 设置观看 - 改变所选查看地图的镜头。 下面就是镜头的列表,你可以通过双击所选镜头,更改镜头的名字。还可以在右键弹出菜单 中删除和创建镜头。 镜头属性 在放置一个镜头之后,你可以修改放置的位置,名称和焦点。下面是你能够通过镜头属性对 话框改变的镜头属性: 镜头名称 - 这个文本框允许你修改所选镜头的名称。 目标X坐标 - 将镜头移至X坐标位置。 目标Y坐标 - 将镜头移至Y坐标位置。 Z轴移动 - 将镜头在Z轴上下移动。 旋转 - 将镜头关于Z轴旋转。 攻击角度 - 将镜头关于地面旋转。 距离 - 调整镜头和目标之间的距离。 观看区域 - 调整镜头能够看到的区域。 远剪辑 - 增加从地平线上看到的距离。 在主窗口中预览 - 这项选定将会实施你对当前镜头的修改。 区域面板 区域和镜头一样,需要触发器的引用才能实现价值,否则将会在游戏中没有任何效果。它可以在触发器被引用或者被影响。这些内容我们将在触发器部分详细讨论。区域内可以实现对天气,传送门和环境声音的控制。 区域面板比较简单。在需要加入区域的时候点击添加按钮。然后在地图上画出一个区域即可。画出的区域将以白色显示。当你双击划出的区域的时候,你可以设定它的属性,查看它,或者删除。 区域属性 在地图上或者在区域面板上双击某个区域就会出现区域属性对话框。这个对话框包括以下选项: 第一个文本框允许你修改区域的名称。修改文本框中的内容就修改了区域的名称。文本框下方的Region XXX是原有的名称。 名字区域下面的四个数字区域代表区域的大小。你可以通过这四个数字修改区域的大小。 选择颜色选项,允许用户修改区域在地图上的识别颜色。这个选定能够使几个相邻的区域更加容易区分。 天气效果选项允许用户在区域内添加天气效果。这是唯一能够在对战地图上添加天气效果的方法。如果使用触发器,地图将会变成非对战地图。 环境音效选项允许用户在区域内加入环境音效。当然,这个声音首先必须在地图编辑器中有效。注意,如果你在区域内添加了天气效果。则就不需要添加环境音效。天气效果中包含了相关的环境音效。 传送门 传送门是一种特殊的和区域配合的友好中立单位。你可以在地图上放置一个传送门,并且在单位属性中指定这个传送门将单位传送到的区域。如果你不在地图上放置传送门,将无法实现单位的传送。 对象编辑器允许自定义单位、物品、装饰物、技能和升级。这些对象可以被放置到地图上,或者导出并被用于战役编辑器或者AI编辑器。每个对象都能够修改11项不同的设定。 单位 技能 - 修改单位在游戏中所具有的技能,技能可以是技能面板上的任何技能。 外观 - 修改单位的视觉外观,比如包括:模型、颜色、大小和界面图标。 战斗 - 修改单位如何战斗。比如包括:它的攻击看起来像什么,什么时候可以进行攻击,攻击的伤害是多少,它的攻击听起来像什么,攻击的射程是多少,等等。 编辑器 - 修改编辑器如何处理这个单位。比如:在编辑器的菜单中这个单位如何显示,或者当这个单位被杀死的时候掉落什么物品等等。 单位是如何在队伍中行动的,单位的移动 移动 - 修改单位如何移动。例如 速度如何,转 向速度如何,能否飞行等等。 道路 - 修改单位的道路属性。例如:单位是如何计算目标地点的移动路线的。 声音 - 修改单位的声音。比如:单位的移动、死亡和选择的声音。 状态 - 修改单位的状态。比如:单位的的生产花费,所占用的人口、生产时间、单位的分类(是否是城镇),单位的维修花费,单位的生命值和魔法值。 科技树 - 修改单位在科技。包括单位拥有的升级选项和生产这种单位所需要的升级。 文本 - 修改单位相关的文本信息。包括单位的名称,描述和介绍信息。 物品 能力 - 修改物品所具有的能力。这种能力可以是技能面板上的任何一种能力。 外观 - 修改物品的视觉外观。比如:物品的颜色,所使用的模型,当物品掉落在地面上的时候所使用的图标。 战斗 - 修改物品在被攻击时的反映。 状态 - 修改物品的状态。比如:物品的等级,是否能够被扔下或者卖掉,商店中存货的数量,多长时间物品能够在商店中出现。 文本 - 修改物品相关文本信息。比如:物品的名字,描述和介绍。 能够被破坏的 外观 - 修改能够被破坏的单位视觉外观。包括:模型、颜色、大小和射角。 战斗 - 修改破坏的单位在受到攻击时的反映。 编辑器 - 修改修改破坏的单位在编辑器中的处理方式。比如:在编辑器的菜单中如何显示和破坏能够被放置的位置。 道路 - 修改修改破坏的单位的道路情况。比如:其它单位能否通过它。 声音 - 修改修改破坏的单位的声音。在这里可以决定它被摧毁时的声音。 状态 - 修改修改破坏的单位的状态。比如:生命值,建造时间,建造花费等等。 文本 - 修改修改破坏的单位的名称。 装饰物 外观 - 修改装饰物的视觉外观。包括:模型、颜色、大小和高度。 编辑器 - 修改装饰物在编辑器中的处理情况。比如:在编辑器的菜单中的位置和装饰物能够被放置的地方。 道路 - 修改装饰物的道路情况。比如:单位能否通过装饰物。 声音 - 修改装饰物的声音。在这里可以决定装饰物所具有的声音。 文本 - 修改装饰物的名称。 技能 外观 - 修改技能视觉外观。比如:技能所使用的图标,技能产生的效果以及技能效果使用的模型。 数据 - 这个修改区域只对于技能有效。在这里可以修改例如:驱散技能对于召唤单位的伤害,技能的治疗效果或者是技能所召唤出来的单位是什么。 声音 - 修改技能所产生的声音。包括最初的声音和持续播放的声音。 状态 - 修改技能的状态。比如:技能的有效范围,施法间隔,持续时间,魔法消耗和施法的目标类别。 科技树 - 修改技能所需的科技树。包括技能所需要的单位和升级选项。 文本 - 修改技能的文本属性。包括技能的名称,技能的描述和介绍,以及技能使用的快捷键。 升级 外观 - 修改升级选项的视觉外观。包括升级选项在面板中所使用的图标。 数据 - 这个修改区域只对升级有效。其中包括:类似于攻击升级效果,防御等级升级效果等等。 状态 - 修改生机状态。比如:升级所需的金矿和木材,升级能够进行的等级数,升级研究所需要的时间等等。 科技树 - 修改升级所需要的科技树。包括升级所需要的科技等级。 文本 - 修改升级相关的文本信息。比如:升级的名称,升级的描述和简介。 触发器编辑器是地图编辑器中最高级和最强大的部分。在触发器控制器中,用户可以控制游戏中所有的效果。这是一种非常容易理解的简单语言。但是却足够强大到足够高级用户使用。它可以通过使用键盘上的’F4’或者在模块菜单中选择触发器编辑器打开。 一个触发器包括三个部分:事件、条件和动作。一个触发器的动作在触发了事件,并满足了条件之后执行。 事件 事件是开始处理触发器的导火线。当一个触发器的事件发生的时候,如果满足条件,则就会产生动作。在一张地图中默认的触发器是’地图载入’。这个触发器的默认条件是’地图载入’也就是这个事件将发生在地图载入完毕的时候。如果没有条件需要满足,则就会产生相应的动作。如果你想加入条件,就可以加入条件’时间--时间经过’,然后设置10秒。则动作就会发生在’地图读入’的10秒之后。 条件 条件是触发器执行动作必须满足的条件。只有在这个条件为真的时候才能产生动作。但是如 果这样设置条件’False Equal to False’将不产生任何的效果,因为它永远是成立的。默认的触发器’地图载入’是没有条件的。让我们来添加一个。按下Ctrl+D,选择’游戏速度比较’,则会弹出一个有蓝色文本的对话框。’(Current game speed) Equal to Normal.’如果保持这个条件,则’地图载入’触发器将会正常工作。但是如果你将条件中的’Normal’改为’Fastest’。则这个触发器将无法在地图编辑器中触发,因为编辑器将地图的速度设定为普通,条件变成了’Normal speed equal to Fastest speed’,这个条件不为真。 一些触发器中,事件发生后条件不一定能够满足。这样的触发器可以设定为多个事件,只有某个事件发生的时候才能够触发。 触发器真正需要的是动作(事实上,这么说并不准确。也就是说没有动作,这个触发器将对游戏没有任何的影响)。也就是说一个触发器可以在没有事件和条件的情况下运行。这可以通过设定动作’Trigger - Run (Ignoring Conditions)’来实现。触发器将在没有条件和事件的情况下进行。 动作 动作是触发器的结果。这可以是让移动镜头、播放电影或者是让一个单位攻击另一个。动作允许被设计成完全控制游戏中的一切。 创建触发器 首先点击’F4’或者选择模块菜单中的触发器编辑器项,打开触发器编辑器。 在创建触发器之前,必须选择触发器放置的类别。通过在菜单中选择创建类别来创建一个类别。然后你就可以在左边的列表中看到你刚刚创建的类别。类别拥有图标,你可以在创建的时候选择类别的名字,或者之后点击’F2’进行更改。 选择你刚刚创建的类别,然后在新的菜单中选择触发器,就可以创建一个触发器。选择你刚刚创建的触发器,你就会发现触发器的右边有两个复选框: 允许 - 如果这个复选框没有被选定,则这个触发器将不产生作用。 原始打开 - 如果这个复选框没有被选定,则这个触发器开始是被关闭的。只有通过动作’Trigger - Turn On’才能够打开。 在触发器的右边还有几个选项。 注解 - 这个文本区域可以填写有关处发起的注释信息。这些信息将不会影响触发器的功能,只是用来提醒您触发器的功能等信息的。 触发器函数 - 这里将显示你的触发器的内容。你可以看到触发器的事件、条件和动作。你也可以在这里添加触发器的事件、条件和动作。 你可以在触发器之间,甚至是地图之间对触发器的事件、条件和动作进行复制和粘贴。你可以通过双击已经设置的事件、条件和动作,对他们进行编辑。 还有一些关于触发器的常见内容是变量、函数和预先装置。 变量 你可以通过按下Ctrl+B或者在触发器编辑器的菜单中选择变量打开变量部分。这里的变量和BASIC或者C语言中的变量有些类似。变量是编辑者用来存放数据的一些空间。但是这里的变量只能用来存放一种数据。你不能够将整数放入这种变量中。 让一个触发器引用你预先放置在地图上的单位。也就是你想让某个单位执行动作。首先开打你想执行的动作。点击动作文本中能够被改变的部分。也就是红色或者蓝色的带下化线的文本。然后点击选择单位按钮,选择你放置在地图上的单位。你所选单位名字将会显示在变量列表中。 尝试一下这样:打开一张空白地图,放置一个兽族的苦工。然后打开触发器编辑器。使用Ctrl+G创建一个新的类别,再使用Ctrl+T创建一个新的触发器和使用Ctrl+R新的动作。然后点击’U’键选定动作’Unit - Kill’。则触发器的语法文本将显示’Unit - Kill (Triggering unit)’。点击蓝色下画线文本’(Triggering Unit)’点击按钮选择一个单位(在编辑变量按钮的左边)。选择苦工。恭喜你~你已经为地图上的苦工设置了一个触发器。所有预先放置在地图上的单位都有一个名字。 如果你对变量还有疑问,我们推荐你阅读相关的计算机书籍(C++版)。 函数 触发器编辑器包含有很多的函数,允许用户灵活进行更加灵活的控制。函数通常和变量一起使用。一个常用函数的例子是’Last Created Unit’。这个函数允许你访问通过’Unit - Create’最后创建的单位。它是两个能够引用最后创建单位的函数之一(另一个是:’Last Created Unit Group’)。这些函数可以用来代替放在单位变量中或者用来代替已经放置在地图上的单位。注意,虽然这些函数返回值,但是你不能够让函数等于变量。但是可以让变量等于函数。 例如:你通过一个事件检测到一个英雄升级了。’Event Response - Leveling Hero’ 函数将会引用到那个英雄。你不能让这个函数等于其他的英雄。如果你想让某个英雄升级。可以使用这个方法:使用其他的方法检测这个英雄(例如:事?quot;Unit - Player-Owned Unit Event’ 或者条件’Unit-Type Comparison’),然后对这个英雄设置动作,诸如:’Hero - Set Level.’ 预先设置 预先设置是编辑器例子: Events: A unit dies Conditions: Actions: -Floating Text - Create floating text at ((position of (Triggering Unit)) with the message (("A "+(name of (Triggering Unit))) + " dies") with size 20 , red 100, green 100, blue 0, alpha 100. -Wait 5.00 seconds -Destroy (last created floating text) 象以上例子, 如果不使用用局部变量, 将无法准确销毁临时漂浮文字. 因为在等待5秒后(-Wait 5.00 seconds), 最近创建的漂浮文字(last created floating text)可能已经不是原来的那个了!) 要达到目的, 必须对JASS有些了解. 教程将对此TRIGGER作进一步的分析. 第一章 变量篇学新的程序设计语言, 要先学它的变量类型. 首先提醒大家:Jass2是区分大小写的如ABcd和ABCD是不一样的. Jass2 变量类型 变量相当于物件的储存箱子, JASS2很多的变量类型只是个指针(变量地址). 使用变量前必须要首先声明变量类型和变量名称. 看个简单的例子: local string my1stvar //声明1个字符型局部变量, 起名为my1stvar set my1stvar = "GreedWind" //把"GreedWind"赋值给变量my1stvar 以后的程序中就可以直接引用/重新赋值my1stvar 变量(除了数组变量)可以在声明语句中初始化, 上面可以简化成: local string my1stvar = "GreedWind" //声明字符型局部变量my1stvar并赋值为 "GreedWind" JASS2有哪些变量类型呢? 我们用WORLD EDITOR和Jass2变量类型做对照便一目了然了 World Editor中的Order(命令) , Ability(技能) , Unit Type(单位类型), Destructible type(可破坏物类型) 和 Item type(物品类型) 在JASS中对应的变量类型实际上是 integer。 可以用单引号’Xxxx’(Xxxx为在World Editor用View as raw data(以行数据查看)中看到 的代码)表示这些类型的值Jass基本变量类型 integerinteger(数值)是的范围在 -2147483648 和 2147483647 之间的整数, 不能有小数位 在Jass中Integer的几中特殊形式: 1.’xxxx’ 单引号加字符形式,该形式为256进制整数,每个字符代表其AscII码值,区分大小写,一般用来表示单位、物品、技能等代码。比如对战单位里剑圣的代码是 ‘Obla’(在 物编中按Ctrl+D可以看到) 2.0xxx 8进制数字,首位为0表示8进制数字3.0Xaa 16进制数字,以0x开头的表示16进制数字 real real是范围很大的32字节数字, 可以有小数位, 123456.33就是real小数点前或后是0的话,可以省略这个0;比如0.34=.34 4.0=4. 0.0可以写成0.或.0,但不 能都省略boolean boolean的值只有true(真)和false(假), 多用于条件判断语句 if (条件==true) then (符合条件做某事) else (不符合条件就做另一件事) endif stringstring是字符串变量, 可以是null(空值). 注意Jass的字符串是大小写区分的, 赋值时用 双引号 "" 引用handlehandle句柄, 可以是null(空值). 是用于指向Warcraft III定义的数据结构的指针. 比如上表中的location/player等除了integer/real/boean/string外的的变量实际上就是 handle类型的子变量 code code(程序代码), 可以是null(空值). 函数可以有code类型的传递参数, 表示该函数必须 要有其他函数作为参数, 如: function RunFunctionForAllPlayers takes code theFunction returns nothing 我们可以这样调用函数: call RunFunctionForAllPlayers(function someFunction) //先 运行someFunction 也可以: call RunFunctionForAllPlayers(null) //不运行其他函数 用户定义变量类型 正如上面所说, 上表中location/player等除了integer/real/boean/string外的类型实际上就是handle类型的子类型, 这些变量就是用户类型变量, 实际就是一个数据结构的指 针 . 数组 是指一组同类型的有序列的变量. 数组中包含的元素可以用[n]来指明(n 表示第n + 1个元 0 算起). 素, 从 以上所说的变量类型中除了code类型, 其他类型的变量都可以定义数组变量, 如 locate integer array dropitems set dropitems[0] = ‘Xxxx’ ...... set dropitems[18] = ‘Xbbb’ dropitems[18]指dropitems中第19个变量. 注意: 1) 数组所有元素初始值是"空", 比如integer类型的数组初始值为0, handle类型初始值 的为null 2) 数组不能直接再次初始化, 只能数组按元素赋值, 如: locate string array playername = "Greedwind" //数组非法赋值 locate string array playername //数组元素只能逐个赋值 set playername[1] = "Greedwind" set playername[2] = "Greedwind’s girlfriend" unit array myUnits unit array yourUnits ... set myUnits = yourUnits // 非法 set myUnits[0] = yourUnits[10] // 合法 3) 数组在函数间不能互相传递. 即是不能把数组作为函数参数, 而且函数也 不能返回数组 类型的变量. 4) 数组元素域在 0 和JASS_MAX_ARRAY_SIZE = 8192 之间, 即是最多有 JASS_MAX_ARRAY_SIZE + 1 个元素. JASS_MAX_ARRAY_SIZE是在common.j中定义的常数 有问有答 1)什么是全局变量和局部变量, 怎样声明和使用变量? 首先要了解, 从作用范围来区分, 变量有全局变量和局部变量. 全局变量作用于Jass程序的全部分, 即是如果全局变量abc在某个函数中改变了值, 这个 值也将影响其他引用了abc变量的函数. 全局变量声明格式: globals 变量类型 变量名称 = 初始值 //有初始化的全局变量 变量类型 变量名称 //无初始化的全局变量 变量类型 array 变量名称 //数组全局变量, 不能再次初始化赋值 ... endglobals 局部变量只作用于函数内部, 即是如果在函数内部定义了局部变量abc, abc的值只影响该 函数内部, 不影响全局变量abc的值. 局部变量声明格式: local 变量类型 变量名称 = 初始值 //有初始化的局部变量 local 变量类型 变量名称 //无初始化的局部变量 local 变量类型 array 变量名称 //数组局部变量, 不能再次初始化赋值 注意: 1) 不论是全局变量还是局部变量, 必须在程序开始部分首先声明. 即是全局变量声明总是在程序文件的最前端, 而局部变量声明总是在函数的最前面. 2) 在Trigger Editor用变量管理器(Ctrl + B)中定义的变量都是全局变量 3) 在Trigger Editor的循环GUI语句 For Loop (Integer A)和For Loop (Integer B) 中 的(Integer A)(Integer B)都是全局变量 实例: globals integer abc = 5188 endglobals ....... function myfunc1 takes nothing returns nothing local integer abc set abc = 1233 endfunction function myfunc1 takes nothing returns nothing local integer myint set myint = abc set abc = 0 endfunction 如果按顺序调用函数myfunc1 和 myfunc1, 那么在函数myfunc2中的myint的值是多少呢, abc最终值又是多少? 是: int = 5188, abc 最终值为 0 2)怎样在Trigger Editor(GUI)中使用局部变量? (有关在Trigger Editor(GUI)中使用局部变量详细方法请参看我的签名中的链接 - 3c的Custom Script: set udg_TempUnit=u 局部变量的使用: 在变量表(Control + B)中先定义好同类型临时变量(不要加前缀udg_)的变量,该变量可以在多个触发里重复利用 (在变量表中定义此变量是为了方便TIGGER EDITOR引用该变量。) 以下例子实现了在单位死亡的位置显示5秒的死亡信息(漂浮文字) (象这种例子, 如果不使用用局部变量, 将无法准确销毁临时漂浮文字(-Destroy (diesmessage)). 因为在等待5秒后(-Wait 5.00 seconds), 最近创建的漂浮文字(last created floating text)可能已经不是原来的那个了 ) 例子: Events: A unit dies Conditions: Actions: -Custom Script: local texttag diesmessage -Custom Script: set udg_TempTextTag = diesmessage //注意要添加"udg_"前缀 -Floating Text - Create floating text at ((position of (Triggering Unit)) with the message ((A+(name of (Triggering Unit))) + "dies") with size 20 , red 100, green 100, blue 0, alpha 100. -Set TempTextTag= (last created floating text) -Wait 5.00 seconds -Custom Script: set udg_TempTextTag = diesmessage -Destroy (TempTextTag) 开头的局 注意:不要利用同名覆盖的方法在GUI中使用局部变量~(即以udg_部变量与已定义全局变量名字相同) 该方法在触发内该类同名变量数量>=2时会出现严重Bug! Jass基础教程 第二章 语法篇 本章主要介绍Jass的语句和语法. 所有程序语言都是由特定的语句按语法规则组成, 基本和人类的自然语言没什么两样. 只是程序语言要有严谨的逻辑和语法, 而人类的语言可以是模糊不清不知所云的--就象我现 在写的可以离千里却蕴涵禅机, 让你费解一样. 1) 赋值语句: set 在第一章中我们已经接触过很多 set 语句了, 就是把 = 号右边的值赋个左边的变量 语法格式: set 变量 = 值(表达式) // (A) set 数组变量[index] = 值(表达式) // (B) (A)是非数组变量的赋值语句. (B)数组变量的赋值语句, 其中[]中的index是指第index + 1个数组元素, index必须是 integer类型的非负整数(可以是 0 ) 右边表达式的数据类型必须和左边的变量类型一致, 意思是说不能这样人类 = 猪2) 调用函数: call 用于调用函数. 当使用 call MyFunction(), 则运行了函数MyFunction 语法格式: call 函数名(参数1, 参数2, ...., 参数n) ()号内的的用逗号(,)分割开的参数表. 如果被调用的函数要求输入参数, 则 call 语句中 必须包含被调用函数要求输入参数类型相同数据类型或用空值. 这句另人费解的话用人类的模糊语言来说就是: 我(被调用的函数)要爱情(参数)才可以工作, 你(call 过程)就不要给我面包(传递的参数) 这个是用Jass写的要爱情和面包但什么也不做而且还不高兴的空函数: function isHappy takes unit whichunit, item needbread returns boolean return false //函数返回值为"假" endfunction 这个是用Jass写的总是高兴傻笑的空函数: function IamAlwaysHappy takes nothing returns boolean return true //函数返回值为(真) endfunction在函数中isHappy()要求传递2个参数, 参数数据类型分别是unit和item 而函数IamAlwaysHappy()没有要求传递任何参数, 就不要多此一举给它爱情和面包了 假设girl是unit类型变量, bread是item类型变量. 我们可这样调用: call isHappy(girl, bread) //给了爱情又给面包, 真是贴心人啊 call isHappy(null, bread) //不给爱情只给面包, 不要饿死他 call isHappy(girl, null) //给爱情不给面包, 为了爱情故, 我把面包抛 call isHappy(null, null) //两者皆不给, 反正给了也返回"假"值 call IamAlwaysHappy() //IamAlwaysHappy()没有要求任何参数 //把PickaGirl()返回的值(unit类型或null)作为参数 call isHappy(PickaGirl(), null)以下非法调用 call isHappy() //非法调用 call isHappy(girl) //非法调用 call IamAlwaysHappy(girl) //非法爱情(不要给我二奶)3) 条件分支: if then else 此语句效果就是: 如果条件成立, 那么做某事, 否则做另一件事 语法格式: if 条件表达式1 then 语句 语句 ... elseif 条件表达式2 then 语句 语句 ... elseif 条件表达式3 then ... else 语句 语句 ... endif其中条件表达式必须是布尔型(boolean)的值(真true和假false). 这是某人的论坛签名JASS版, 他企盼着当他进入论坛时就.... 事件:单位进入论坛时 if GetTriggerUnit() == 他 then call CreateNUnitsAtLoc( 1, GetUnitTypeId(美女), GetOwningPlayer(GetTriggerUnit()), GetUnitLoc(GetTriggeringUnit()), bj_UNIT_FACING ) else endif4) 循环语句 loop 和循环退出语句 exitwhen loop 是执行循环的语句, exitwhen 则是控制循环退出的条件 语法格式:loop exitwhen 条件表达式 //(A)在循环语句执行前检查循环条件 .... endloop 或 loop .... exitwhen 条件表达式 //(B)在循环语句执行后检查循环条件 endloop 同样的, 条件表达式必须布尔型的值 (A)和(B)的差别相当于先买票再猴戏和看玩猴戏再給钱 loop 语句可以不用exitwhen. 在没有exitwhen和return语句的情况下, loop ... endloop 将成为永久循环(也称死循环), 一般应该避免死循环的产生. 例:在Trigger Editor的GUI语句有: For Loop (Integer A) 的语句, 如 For each (Integer A) from 1 to 10, do (Set unit_temp[(Integer A)] = 恐龙) 转化成Jass就是: set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = 10 loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd set udg_unit_temp[bj_forLoopAIndex] = ‘A001’ set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop 5) 函数返回语句: return当执行到 return 语句时, 退出此函数, 程序运行点将返回到该函数的调用点. 语法格式: return //(A) 或 return 表达式 //(B)如果函数声明中没要求返回值, 则用(A), 如:function Iwanteverthing takes unit whichunitreturns nothingreturn //上面函数定义中为returns nothing, 即是没要求返回值 endfunction 如果函数声明中要求返回值, 则用(B). 注意, 返回值类型必须和函数声明中要 求返回值类 型一致.即是声明中要求返回美女, 执行函数后就不能返回恐龙.function IamAlwaysHappy takes nothingreturns booleanreturn true //函数定义要求返回布尔型的值 endfunction 有问有答 1) 本教程的表达式是指什么? 表达式可以是直观可见的值, 如: 数值型/真值型: 1, 3, 5565.33, ........ 字符串: "Xasfsfs", "Greedwind", ........ 布尔型: true, false 单位: ‘A001’, ‘Obla’, .... ........ 也可以是函数, 计算式等, 如 return GetTriggeringUnit() //返回触发单位 //将触发单位所在点赋值給udg_loc set udg_loc = GetUnitLoc(GetTriggeringUnit()) return a + b //返回 a + b 的值 2) Jass 有那些操作符? 数学计算: + 加 - 减 * 乘 / 除 比较符号: >, <, >=, <= 分别是大于,小于, 大于等于, 小于等于 == 等于 != 不等于 注意: 双=号(==)才是比较, 单=号是赋值, 不要搞错了!!!布尔条件 and 条件和 or 条件或 not 否定条件 使用://条件表达式1和2都是true, 则下式为true, 否则下式为false 条件表达式1 and 条件表达式2 //在条件表达式1或2中只要有一个是true, 则下式为true 条件表达式1 or 条件表达式2 //不是表达式的值, 如 return (not true)则返回false not 表达式 字符串操作符 + 字符串叠加, 如"Greed" + "wind"的结果"Greedwind" 3) Jass里还有什么特殊用途的字符和字串? // 注释, 以 //开头的语句将不执行 , 如 call myfunction() () 函数参数列表 [] 数组元素标记, 如 myarray[0] "" 字符串引用符, 如 "I love Greedwind" ‘‘ 单位/物品/技能代码引用符号, 如 ‘A001’, ‘Hpal’ 注意: Jass中可以用单引号括起4个字母表示数值型的值(integer) \ 跳脱符号(与Java/C一样), 如: 在字符串里使用双引号 set mystring = "This is a \"string\"" mystring 的值实际上是: This is a "string" 如果直接 set mystring = "This is a "string"" 将出错 因为""是字符串引用符0 用于数字前面, 则表示八进制的数, 如 016 0x 用于数字前面, 则表示十六进制的数, 如 0x1FA0 Jass基础教程 第四章 库函数 这章是Jass基础教程中最难的部分, 也是最实用的部分. Jass的关键字有26个, 跟英文字母一样多. 我们来回顾一下: and, array, call, constant, else, elseif, endfunction, endglobals, endif, endloop, exitwhen, extends, function, globals, if, local, loop, native, not, or, return, returns, set, takes, type, then以此看来, Jass是语法结构最简单的一种准计算机语言. Jass实现功能基本依靠调用 common.j, blizzad.j, common.ai中的库函数. 本章所述内容不属于Jass语法部分, 最主要讲述:触发器(Triggers) 跨脚本通讯(Inter-Script Communication) 队列(Enumerations) 队列过滤器(Filters) 线程(Threads) 1) 触发器(Triggers) 触发器用于地图触发器脚本(Trigger Jass), 用于响应特定事件. 它是种响应信号(callback), 触发器不能应用于AI, 即是说AI Jass中不能有触发器的语句. 触发器包含创建触发器, 设置触发条件, 设置动作.a)创建触发器 触发器的数据类型为trigger(触发器), 是handle(句柄)的子类型. 创建触发器的函数在common.j中的声明: native CreateTrigger takes nothing returns trigger 参数: nothing //无参数 返回: trigger //返回创建的触发器 使用格式: set 表达式 = CreateTrigger() 其中表达式是trigger类型的变量 新数据类型: trigger类型: 是handle的子类型, 用于调用和处理触发器 b)触发事件 触发事件的数据类型为event(事件). 可以引起触发响应的触发器必须先在游戏中注册触 发事件, 用于监视游戏事件发生. 注册触发事件的函数在common.j中的声明: native TriggerRegister*Event takes trigger whichTrigger, ... returns event 函数名: 根据事件对象的不同, 有不同的事件响应. TriggerRegister*Event中的 * 号为对象名, 如: TriggerRegisterUnitEvent, TriggerRegisterEnterRegion 等, 注册不同对象的事件要求传递相应指定对象作为参数, 有些事件注册要求传递下面所说的过滤器(Filters) 参数: trigger whichTrigger //触发器变量 ... //相应指定对象的变量 返回: event //返回该事件 使用方法(举注册单位事件的例子): call TriggerRegisterUnitEvent(哪个触发器, 哪个单位, 哪种类型的单位事件) 新数据类型: event //事件c)触发条件 触发条件是一组布尔表达式(boolexpr)数据, 它的数据类型为条件函数(conditionfunc), 是布尔表达式(boolexpr)类型的子类型. 建立触发条件的函数在common.j中的声明: native Condition takes code func returns conditionfunc 参数: code func //函数代码作为参数 返回: conditionfunc //返回建立的条件 其中takes code func是指需要函数代码func作为参数, 参数函数 func 必须的声明格式必须是: takes nothing returns boolean. 即是说, 用作参数的函数本身应该是无参数且 返回值为布尔型(boolean). 使用格式: set 表达式 = Condition(function 布尔型函数名) 其中表达式是条件函数(conditionfunc) 新数据类型: boolexpr 布尔表达式 conditionfunc 条件函数, 是布尔表达式的子类型 比如: function Girl1 takes nothing returns boolean ... return true endfunction function Girl2 takes integer i returns boolean ... return true endfunction function Girl3 takes nothing returns nothing ... return endfunction // 假设 c 为conditionfunc类型变量 set c = Condition(function Girl1) //(A) set c = Condition(function Girl2) //(B) 本身要求参数 set c = Condition(function Girl3) //(C) 返回值不是boolean类型 解释:Girl1() 是无参数且返回为boolean的函数, 可以用作 Condiction() 中的参数函数code func. 而Girl2() - 本身要求参数, Girl3() - 返回值不是boolean类型, 所以(B)(C) 函数不可作为Condiction()的参数. 在第一章变量篇中我没有详细说明code类型的数据, 因为怕读者不能理解. 现在我说明下 code类型数据. 我们用例子说明, 比如: call myfuction1(IsGirl()) //(A) call myfuction2(function IsGirl()) //(B)(A)和(B)之间有什么不同呢? 按我的理解: (A)(B)都把IsGirl()运行返回后的值当作myfunction1()/myfunction2()的参数. IsGirl()在(A)中是一次性的处理过程. 而(B)是创建了一个运行IsGirl()逻辑的监视线程, 只要线程没给清除/终止, IsGirl()将一直监视变 化. 注意这里所说的线程跟下面要说的AI线程是两码事. d) 增加触发条件: 触发条件可以用TriggerAddCondition()增加 增加触发条件的函数在common.j中的声明: native TriggerAddCondition takes trigger whichTrigger, boolexpr condition returns triggercondition 参数: trigger whichTrigger //触发器变量 boolexpr condition //触发条件变量 返回: triggercondition //返回该触发条件的handle(句柄) 使用格式: , 触发条件) set tc = TriggerAddCondition(触发器 其中 tc 为triggercondition类型变量 新数据类型: triggercondition 触发条件句柄 (注意: 触发条件和上面要说的触发事件是不一样的!!!) 例: 这是增加/移除/改变触发条件的例子 //文件头声明个全局变量tc globals ... triggercondition tc = null trigger mytrigger = null ... endglobals function Girl takes nothing returns boolean ... return true endfunction function notGirl takes nothing returns boolean ... return false endfunction //为 mytrigger 增加触发条件 function addcondition takes nothing returns nothing ... set mytrigger = CreateTrigger() set tc = TriggerAddCondition(mytrigger, Condition(function Girl)) ... endfunction //因为tc是mytrigger触发条件的句柄, 把tc清空便清除了指向的触发条件. function removecondition takes nothing returns nothing ... set tc = null .. endfunction ytrigger 的触发条件 //改变 m function modifycondition takes nothing returns nothing ... set tc = null //先把原来的触发条件移掉 set tc = TriggerAddCondition(mytrigger, Condition(function noGirl)) ... endfunction e)触发器动作 触发器动作是当指定事件发生并符合触发条件的执行的语句. 增加触发器动作的函数在common.j中的声明:native TriggerAddAction takes trigger whichTrigger, code actionFunc returns triggeraction 参数: trigger whichTrigger //触发器变量 code actionFunc //执行函数 注意: 执行函数必须是无参数无返回值(takes nothing returns nothing)的函数 返回: triggeraction //触发动作 新数据类型: triggeraction //触发动作, handle字类 把有关触发器主要函数糅合在一起, 我们来看个例子, 研究下触发器是怎么创建的: //文件头声明全局变量mytrigger //假设mytrigger是监视单位死亡事件的触发器 globals ... trigger mytrigger = null ... endglobals //判断是否掉物品 function isDrop takes nothing returns boolean local boolean conditcion ... if conditcion = true then return true else return false endif endfunction //掉物品 unction DropItems takes nothing returns nothing f //获得触发单位 local unit trigUnit = GetTriggerUnit() .... call UnitDropItem( trigUnit, ‘IC21’ ) ... endfunction function ThisIsMyTrigger takes nothing returns nothing local unit u //在-5630.5, -4723.1坐标为玩家5创建单位’n00I’, 面向90.260度 set u = CreateUnit(Player(5), ‘n00I’, -5630.5, -4723.1, 90.260 ) //创建触发器(相当于mytrigger的初始化) set mytrigger = CreateTrigger() //为mytrigger注册触发器事件, 让游戏系统监视所创建单位u的死亡事件 //EVENT_UNIT_DEATH是common.j中定义的常量 call TriggerRegisterUnitEvent( mytrigger, u, EVENT_UNIT_DEATH ) //为mytrigger增加触发条件 //isDrop是无参数返回为布尔值的函数 set tc = TriggerAddCondition(mytrigger, Condition(function isDrop)) //为mytrigger增加触发器动作 - 掉宝物 //DropItems是无参数无返回值的函数 call TriggerAddAction(mytrigger, function DropItems ) ... endfunction 可以看出, 创建触发器顺序是: 1. 触发器初始化 - CreateTrigger() 2. 触发器事件注册 - TriggerRegister*Event() 3. 定义触发条件(可选) - TriggerAddCondition() 4. 触发器动作 - TriggerAddAction() 注意: 1. 创建触发器必须先用CreateTrigger()初始化. 2. 没有注册事件的触发器只是个处理过程, 不会响应事件执行程序 3. 触发器可以不加触发条件, 因为可以用触发动作调用的函数来控制逻辑. 2)线程(Threads)(这部分属于AI部分, 作为入门者做一般性了解就行了, 因为AI都是纯JASS写的, 也没有真正好的AI EDITOR. 本人也对此一知半解, 关于AI的文章也不多, 没什么好参考的.) 线程只应用于AI脚本(AI JASS), 不能用于触发器脚本(Trigger Jass). 通常, 当AI脚本 开始运行时只创建一个线程, 创建更多的线程可以用comman.j的本地函数: native StartThread takes code func returns nothing 调用 call StartThread(function myfunc) 将创建一个从函数myfunc开始执行的线程. 每个玩家最多可以拥有6个线程, 包括一开始执行的主线程. 当一个玩家有6个线程数时, 调用StartThread()的语句将被忽略. 线程不能回收, 当你为某玩家创建了5个自定义线程, 将无法为该玩家创建更多的线程. 当新线程创建时, 线程立即生效. 当线程让步执行时, 创建此线程的父线程将继续执行. 在同一玩家中的所有线程都共享全局状态(包括变量). 即是修改某个全局变量, 修改后的 值在此玩家的所有线程中都是可见的. 线程在以下的情况让步执行, 返回父线程 a) 当线程中的操作码(opcode)超出限制, 线程会自动休眠 1 秒 b) 当线程中用使用 Sleep(n), 线程将休眠 n 秒, 然后继续执行. 线程在以下情况会中止, 返回父线程 a) 如果 call StartThread(null)中, 线程中止 b) 当线程的主函数返回, 线程中止. (StartThread()中之间调用的函数就是主函数.) c) 当线程中使用没有声明的变量, 线程中止. 在使用之前, 变量必须声明. d) 当线程中出现零为被除数时, 线程中止 e) 线程主函数出现语法错误. 注意: 虽然AI脚本可以使用大部分common.j的库函数, 但有些类型的函数在AI不能正常 工作, 如: a) 返回字符串类型(string)的本地函数, 如I2S(), SubString()等 b) 需要以code, trigger, boolexpr 等类型数据为参数的本地函数, 如触发器函数, 队列 函数(ForGroup, 等) 注意: AI中不可以使用Blizzard.j的函数, 触发器中也不可以使用common.ai的函数, AI 和触发器都可以使用common.j的函数(当然, 对于AI, 还受上面所说的限制) common.ai和common.j是写AI时可以调用和参考库文件, 要研究AI, 先去读这2个文件. 3) 跨脚本通讯(Inter-Script Communication)在游戏中, 可能会有多个独立的Jass脚 脑玩家的AI脚本的执行. 触发器脚本也不可以和AI脚本共享全局变量. 但可以用传递命令的方法进行脚本之间的数据交换. 命令由一对数值型数据(integer)组成: 命令值(command value)和数据值(data value). 从触发器脚本向AI脚本发出通讯命令, 可以使用common.j中定义的以下本地函数:native CommandAI takes player num, integer command, integer data returns nothing 参数: player num //玩家 integer command //命令 integer data //命令数据 以下是AI中使用的common.j函数, 注意: 每个电脑玩家都会有独立的AI脚本, 所以, 以 下函数都没有要求玩家作为函数参数. 每个电脑玩家都有命令堆来堆放接受到的命令. 想知道有多数个命令堆放在命令堆, 可以 用下面的函数: native CommandsWaiting takes nothing returns integer 参数: 无 返回: 命令堆的命令数(integer) 获得存放在命令堆中最顶端的命令(): //返回命令 native GetLastCommand takes nothing returns integer //返回命令数据 native GetLastData takes nothing returns integer : 上面2个函数都不会移除命令堆中的命令, 要移除堆中的命令, 可以用 native PopLastCommand takes nothing returns nothing 4) 队列(Enumerations)虽然JASS不能自定义数据结构(因为JASS缺少指针操 作符), 但API库中提供了一些实现队列操作的函数. 如一组单位为单位组 (group), 一组玩家为势力(force), 虽然一组可破坏 物没有明确定义它的数据类型, 但也可以用API函数来操作. 单位组和势力的操作函数很类似. 单位组处理函数 // 初始化单位组 native CreateGroup takes nothing returns group // 在指定单位组中增加指定单位 native GroupAddUnit takes group whichGroup, unit whichUnit returns nothing // 在指定单位组中移除指定单位 native GroupRemoveUnit takes group whichGroup, unit whichUnit returns nothing 势力处理函数 // 初始化势力 native CreateForce takes nothing returns force // 在指定势力中增加指定玩家 native ForceAddPlayer takes force whichForce, player whichPlayer returns nothing // 在指定势力中移除指定玩家 native ForceRemovePlayer takes force whichForce, player whichPlayer returns nothing JASS不能直接操作队列里面的元素, 它是通过callback类型的函数来 实现对队列的操作: // 对指定单位组中的每个单位都运行指定callback函数callback // (对应GUI语言的For Each Unit in ) native ForGroup takes group whichGroup, code callback returns nothing // 对指定势力中的每个玩家都运行指定callback函数callback // (对应GUI语言的For Each Player in ) native ForForce takes force whichForce, code callback returns nothing 输入上面两个函数的callback函数必须是无参数无返回值函数(takes nothing returns nothing) 同样, 操作可破坏物也可以用在区域内的可破坏物作为队列, 可以以用类似的 方法:// 在指定区域r内符合指定过滤器filter的都运行指定callback函数 actionFunc // (过滤器见下节的讲解) native EnumDestructablesInRect takes rect r, boolexpr filter, code actionFunc returns nothing在callback函数, 可以用下面的函 数获得队列中的下一个元素: // 获得单位组中的下一个单位 // (对应GUI语言的Pick Every Unit in ) constant native GetEnumUnit takes nothing returns unit // 获得势力中的下一个玩家 // (对应GUI语言的Pick Every Player in ) constant native GetEnumPlayer takes nothing returns player // 获得可破坏物组中的下一个可破坏物 // (对应GUI语言的Pick Every Destructables in ) constant native GetEnumDestructable takes nothing returns destructable注意: AI中 不支持队列函数的使用. 这是杀死单位组中所有单位的实例: // 这是callback函数, 无参数并无返回值 function KillGroupCallback takes nothing returns nothing // 获得单位组中的下一个单位 local unit nextUnit = GetEnumUnit() // 杀死该单位 call KillUnit(nextUnit) endfunction // 调用ForGroup // 对单位组groupToKill中的每个单位都运行函数KillGroupCallback call ForGroup(groupToKill, function KillGroupCallback)另一个经常是用的例子 是在队列中查找特定条件的元素. 不幸的是, 因为JASS只支持callback函数来处 理队列中的元素, 所以只有用全局变量来保存不同单位的属性. 下面是 找出单位组里生命最高的单位的例子://定义全局变量 globals //用于储存两单位比较后较高的生命值, 初始化为 0 real mostLifeSoFar //用于储存两单位比较后有较高生命值的单位, 初始化为 null unit unitWithMostLifeSoFar endglobals //比较单位生命值的callback函数 function MostLifeCallback takes nothing returns nothing //获得单位组中的下一个单位 local unit nextUnit = GetEnumUnit() //获得单位属性 - 生命 //UNIT_STATE_LIFE是common.j中定义的常量 local real life = GetUnitState(nextUnit, UNIT_STATE_LIFE) //比较生命值 if life > mostLifeSoFar then //把较大的生命值储存 set mostLifeSoFar = life //把有较大生命的单位储存 set unitWithMostLifeSoFar = nextUnit endif endfunction ... //初始化全局变量的值为空值 set mostLifeSoFar = 0 set unitWithMostLifeSoFar = null //调用ForGroup //对单位组myGroup中的每个单位都运行函数MostLifeCallback比较生命 call ForGroup(myGroup, function MostLifeCallback) //上句运行后, 全局单位类型变量unitWithMostLifeSoFar便指向单位组myGroup中最高生 命的单位, 或: //如果单位组myGroup是空组, 那么unitWithMostLifeSoFar便是空值null ... 当然, 实现队列操作, 也可以用数组的方法来处理. 但, 数组不能使用紧接着要说的队列过滤器, 也不能定义数组中包含数组. 这些都是队列所拥有的优势, 如可以有数组型的单 位组(相当于数组中包含数组), 也可以用队列过滤器. 5)队列过滤器(Filters)队列过滤器用于在队列中增加符合条件的元素. 比如, 在 创建一个法力小于20的单位组时, 便可以用队列过滤器(Filters)来创建. //在单位组中增加指定单位名为unitname, 并符合队列过滤器filter的单位 native GroupEnumUnitsOfType takes group whichGroup, string unitname, boolexpr filter returns nothing //在单位组中增加指定玩家为whichPlayer, 并符合队列过滤器filter的单位 native GroupEnumUnitsOfPlayer takes group whichGroup, player whichPlayer, boolexpr filter returns nothing //在单位组中增加指定玩家为whichPlayer, 并符合队列过滤器filter的单位 native GroupEnumUnitsOfTypeCounted takes group whichGroup, string unitname, boolexpr filter, integer countLimit returns nothing //在单位组中增加指定区域为r, 并符合队列过滤器filter的单位 native GroupEnumUnitsInRect takes group whichGroup, rect r, boolexpr filter returns nothing //在单位组中增加countLimit个指定区域为r, 并符合队列过滤器filter的单位 native GroupEnumUnitsInRectCounted takes group whichGroup, rect r, boolexpr filter, integer countLimit returns nothing //在单位组中增加在指定点坐标范围之native GroupEnumUnitsInRange takes group whichGroup, real x, real y, real radius, boolexpr filter returns nothing //在单位组中增加在指定点范围之native GroupEnumUnitsInRangeCounted takes group whichGroup, real x, real y, real radius, boolexpr filter, integer countLimit returns nothing //在单位组中增加指定个数, 在指定点范围之native GroupEnumUnitsInRangeOfLocCounted takes group whichGroup, location whichLocation, real radius, boolexpr filter, integer countLimit returns nothing //在单位组中增加被指定玩家选中, 并符合队列过滤器filter的单位 native GroupEnumUnitsSelected takes group whichGroup, player whichPlayer, boolexpr filter returns nothing 类似地, 对于势力也有相应的操作函数 //在势力中增加符合队列过滤器filter的玩家 native ForceEnumPlayers takes force whichForce, boolexpr filter returns nothing //在势力中增加指定个数, 并符合队列过滤器filter的玩家 native ForceEnumPlayersCounted takes force whichForce, boolexpr filter, integer countLimit returns nothing // Add all units that are allies of ‘whichPlayer’ that satisfy ‘filter’ //在势力中增加 和指定玩家同盟, 并符合队列过滤器filter的玩家 native ForceEnumAllies takes force whichForce, player whichPlayer, boolexpr filter returns nothing //在势力中增加和指定玩家敌对, 并符合队列过滤器filter的玩家 native ForceEnumEnemies takes force whichForce, player whichPlayer, boolexpr filter returns nothing 以上函数中boolexpr filter在本章第1)节触发器中有提到, 通常可以使用过滤器 (filterfunc).过滤器跟触发器的条件函数(conditionfunc)类似. 创建过滤器可以用以 下语句:native Filter takes code func returns filterfunc 其中参数函数code func必须是无参数返回值为布尔值的函数(takes nothing returns boolean), 过滤器用于在创建队列时增加额外的条件. 在过滤器中, 可以 使用下面的函数获得下一个待查的单位/玩家/不可破坏物: //获得下个待查单位 constant native GetFilterUnit takes nothing returns unit //获得下个待查玩家 constant native GetFilterPlayer takes nothing returns player //获得下个待查可破坏物 constant native GetFilterDestructable takes nothing returns destructable 我们来看 个创建一个法力小于20的单位组例子://过滤函数, 是无参数返回值为布尔值的 函数 function LessThan20ManaCallback takes nothing returns boolean //获得下个检查的单位 local unit nextUnit = GetFilterUnit() //检查待查单位的法力是否小于20 //小于20则返回true, 否则返回false return GetUnitState(nextUnit, UNIT_STATE_MANA) < 20 endfunction ... //创建过滤器, 过滤函数是LessThan20ManaCallback local filterfunc myFilter = Filter(function LessThan20ManaCallback) //在单位组中增加指定区域, 符合过滤条件的单位 call GroupEnumUnitsInRect(myGroup, someRect, myFilter) // Destroy the filter if we are not going to use it again //不再使用过滤器, 销毁过滤器, 避免内存泄漏 call DestroyFilter(myFilter) Jass 操作符数学计算: + 加 - 减 * 乘 / 除比较符号: >, <, >=, <= 分别是大于,小于, 大于等于, 小于等于 == 等于 != 不等于 注意: 双=号(==)才是比较, 单=号是赋值, 不要搞错了!!! 布尔条件and 条件和 or 条件或 not 否定条件 使用: //条件表达式1和2都是true, 则下式为true, 否则下式为false 条件表达式1 and 条件表达式2 //在条件表达式1或2中只要有一个是true, 则下式为true 条件表达式1 or 条件表达式2 //不是表达式的值, 如 return (not true)则返回false 字符串操作符+ 字符串叠加, 如"Greed" + "wind"的结果"Greedwind" Jass特殊字符 // 注释, 以 //开头的语句将不执行 () 函数参数列表, 如 call myfunction() [] 数组元素标记, 如 myarray[0] "" 字符串引用符, 如 "I love Greedwind" ‘‘ 单位/物品/技能代码引用符号, 如 ‘A001’, ‘Hpal’ 注意: Jass中可以用单引号括起4个字母表示数值型的值(integer) \ 跳脱符号(与Java/C一样), 如: 在字符串里使用双引号 set mystring = "This is a \"string\"" mystring 的值实际上是: This is a "string" 如果直接 set mystring = "This is a "string"" 将出错 因为""是字符串引用符0 用于数字前面, 则表示八进制的数, 如 016 0x 用于数字前面, 则表示十六进制的数, 如 0x1FA0、 声音编辑器允许用户输入和输出声音文件(.wav)和音乐文件(.mp3)。并且可以通过触发 器编辑器中的触发器进行播放。使用’F5’键或者模块菜单中的声音编辑器选项,打开声音编辑器。 你想在玩《魔兽争霸III》的时候听Beethoven’s Ninth Symphony,好的,你可以。但是要注意Battle.net不允许传送超过4M的地图文件。但是在地图中导入音乐很容易使地图文件超过这个大小,从而无法在Battle.net上传输。因为导入的音乐是打包在地图文件中的。(使用内部音乐和声音将不增加地图文件的大小)。 声音和音乐被分为两部分。左边的部分(就像地形编辑器画笔列表)列出了全部的内部声音。在触发器中使用内部声音只需要简单的选择文件并选择使用内部声音或者内部音乐就可以了。则这个声音或者音乐就会出现在右边部分。 右边的部分列出你所导入的声音或者正在使用的内部声音。 你可以通过双击文件或者在工具条上点击播放声音按钮播放内部声音列表上的声音或者音乐。并可以通过点击工具条上的停止播放所有声音按钮停止播放。 如果想编辑声音或者音乐的属性,可以在右侧的列表上双击该声音或者右键点击他,并选择声音属性。声音属性包括以下选项和信息。 文件 - 声音或者音乐的文件名。 格式 - 声音的最大千赫,Mp3文件的比特率或者WAV文件的采样率。以及WAV文件的声道数和Mp3文件的压缩方法。 长度 - 声音或者音乐播放时间。 变量名 - 在触发器编辑器列表中显示的声音的名称。这个选项只对Mp3文件有效。 选项- 循环 - 声音文件将重复播放,直到被命令停止。 3D音效 - 声音文件播放的时候具有3D效果。 超出范围则停止 - 在玩家离开有效范围的时候播放停止。 音量- 增加声音播放的音量。 淡入率 - 声音淡入的速度。数值越高,淡入速度越快。默认是直接。 淡出率 - 声音淡出的速度。数值越高,淡出速度越快。默认是直接。 播放速度 - 增加数值则会增加声音播放的速度。 效果 - 声音上还可以添加一些特殊的效果,这些效果只能对于特定的声卡有效。 最小距离 - 声音能够被听到的最小距离。 最大距离 - 声音能够被听到的最大距离。 淡出距离 - 声音开始淡出的距离。 使用这些声音必须通过触发器编辑器,当你导入声音或者音乐文件到右侧列表,或者选择内部声音或者音乐之后。进入触发器编辑器,选择’播放声音’或者’播放音乐’。 记住3D音效必须附加特殊的位置播放,如单位或者区域。必须在特定的区域内才能够听到。 战役编辑器允许用户自定义和管理通用战役选项。包括读入画面,屏幕界面,自定义对象和导入文件。 通用 名称 - 为你的战役命名。 推荐玩家数量 - 列出游戏类型和如何才能较好的使用。 作者 - 地图的作者信息。 描述 - 在这里你可以告诉玩家战役的内容。 使用不同难度 - 当这个选项可用时,你的战役可以通过触发器编辑器中设定的’游戏难度比较’选择不同的难度。 地图文件 - 显示战役中所包含的地图文件。 读入画面 用户可以设定战役地图之间的画面。可以设定背景画面和环境音效。并可以设定特殊的地图描述。 ID - 触发器编辑器中的’显示/隐藏自定义战役按钮’需要引用的数字。 可见度- 决定战役第一次访问时能否看到按钮。 读入的文件- 按钮引用的地图名称。 章节- 在这里可以命名章节的标题。 副标题- 这里可以命名章节的副标题。 背景屏幕- 选择读入战役时的背景屏幕。 环境音效- 选择读入战役时的环境音效。 自定义数据 战役中的每张地图都会集中访问对象编辑。这里的所有单位、物品、装饰物、能力和升级都可以在战役中随意使用。关于这部分内容请参看物体编辑器文档 Imported Files 战役中的每个地图都可以访问输入管理器中的输入文件。这里的每个文件在战役中也可以随意使用。关于这部分的详细内容请参看输入管理器文档。 因为在新的强大编辑器中会有太多的对象需要管理。因此就需要一个方便管理的方法。而这就需要对象管理器。 对象管理器将会集中概括地图上的所有对象。这些对象被整理到一个整洁的列表中。在这个列表中,用户可以编辑对象的属性,也可以查看到对象被放置的位置。想要知道你选择的是不是触发器中引用的农民,你只需要通过名称选择该对象,并通过查看对象了解它在地图上的位置就可以了。 如果你双击对象图标或者在选择对象之后点击编辑属性菜单。你就能够进入到该对象的属性对话框中。这在你创建一张大地图或者战役的时候非常的有效。 对象管理器也可以管理触发器。如果对象被触发器引用。你可以展开该项,查看到所有引用他的触发器。并通过双击触发器打开触发器编辑器进行管理。 选择一个触发器并展开,就可以看到这个触发器的代码和引用的每个对象。并可以看到引用对象的每个触发器。 在AI 编辑器中你可以创造人工智能来指挥部队的发展和进攻战略。 通用 名称 - 命名你的AI。 种族 - 选择你所要创建AI的种族。自定义种族选项允许综合使用自定义单位,技能和升级科技。记得要输入自定义数据。 选项 设置玩家名字 - 激活此项以设置游戏中玩家的名字为所输入的AI名字。 对战 - 为标准对战游戏使用混战AI。混战AI趋向于与同盟玩家共同进攻和防御。 目标英雄 - 激活此项后,AI将在战斗中以更高的优先权攻击英雄。 修理建筑 - 激活此项以使工人在需要的时候自动修理建筑。 英雄逃跑 - 激活此项后,英雄在受重伤或无法攻击时将会试图逃离战场。 单位逃跑 - 激活此项后,非英雄单位在受重伤或无法攻击时将会试图逃离战 场。 组队逃跑 - 激活此项后,攻击组在失去优势时将会试图撤离战场。 决不仁慈 - 激活此项后,AI会寻找敌人显得脆弱或劣势的机会发动进攻。这种进攻符合敌人-主攻进攻优先权。 受伤忽略 - 激活此项后,在集结进攻力量的时候,忽略生命值低于50%的单位 去除受伤者 -激活此项后,会周期性的把受伤的单位送回家(或者送到生命之泉)回复生命。 拾取物品 - 激活此项后,英雄会拾取他们碰到的任何有用的物品。 慢速采矿 - 激活此项后,一个工人一次只允许采集一个单位的金子或者木材,而不是通常的采集数量。这给AI的经济发展带来了巨大的障碍。 允许基地变换 -这个选项允许AI潜在的选择一个新的地点来作为采矿和部队撤退的基地。 聪明的炮火 - 激活此项后,炮火单位会在可能的情况下冲上前用攻城模式攻击敌人的基地。 自定义数据 输入 - 输入由对象编辑器输出的包含你的AI的自定义数据。 输出 - 输出自定义数据以检测对象编辑器中他人的自定义AI数据。 清除 - 从你的AI中清除所有自定义数据。 环境 - 环境可以在此配置,其形式与开关编辑器相似,但专用且仅用于AI编辑器。在此创建的环境可以通过AI编辑器使用。 在创建AI环境时一种有帮助的概念是AI首领,分为两种类型,进攻和防御。首领是无形的单位,扮演领导AI的角色。进攻AI首领停留在基本建筑处(城镇大厅等),等待一轮攻击的组建。一旦组建完毕,攻击AI首领领导攻击组进攻当前优先攻击目标,然后返回基地。防御首领停留在基地和首个金矿之间,除非基地遭到进攻。防御首领然后会领导防御力量进攻入侵者。 英雄 英雄使用 - 选择你想让AI训练的英雄。可用英雄基于你在一般标签中所选择的种族。 训练顺序 - 修改AI将运作的训练顺序。训练顺序与与英雄使用一项中所选的英雄相符。 技能选择 - 修改AI英雄将要学习技能的顺序。 建筑 基础建筑 - 选择哪个单位会被用来建造AI的基本建筑。在此可用的选项与在一般标签中所选的种族相符。 采矿建筑 - 选择哪个单位会被用来建造AI的采矿建筑。着通常只被不死族使用,但其他有废弃金矿技能的单位也可在此选择。 建筑优先 - AI的建造,研究和升级顺序在此指定。当一个单位死亡,它会被AI所代替,除非AI资源不足或是某种状况阻止了它。在此建造优先权共有五项: 建造 - 将会建造,研究和升级什么。 全部 - 同类型建筑的优先权数。没有括号的数字表示所有AI的总和。在括号内的数字 只表示指定城镇内的总和。 食物 - 记录食物数量以及食物上限。当一种优先使食物使用超过了食物上限,该优先权为红色。 城镇 - 指定建筑顺序执行的处所。 环境 - 如果没有遇到在此指定的环境,AI将会跳过该建造优先权而进行下一项。环境可以在一般标签下创建,或者自行创建为该优先权专用。 采钱工人 - 选择哪个单位被AI用做采矿单位。该此可用的选项符合一般标签中所选择的种族。 伐木工人 - 选择哪个单位被AI用做伐木单位。该此可用的选项符合一般标签中所选择的种族。 采集优先权 - AI的采集顺序在此指定。采集优先权有以下四项: 采集 - 你想让工人收集的资源。 工人 - 共享同一优先权的工人数量。 城镇 - 工人在哪采集。 环境 - 如果没有遇到在此指定的环境,AI将会跳过该采集优先权而进行下一项。环境可以在一般标签下创建,或者自行创建为该优先权专用。 攻击 攻击组 - AI的攻击组在此创建与列出。 当前组 - 攻击组在此得到定义。每个攻击组有3项条目。 单位类型 - 单位的类型。可用单位取决于一般标签中所选择的种族。 数量 - 匹配特定所选单位类型的单位数量。 环境 - 如果没有遇到在此指定的环境,当前组将不会包含此条目。环境可以在一般标签下创建,或者自行创建为该优先权专用。 攻击轮次 - 你的攻击轮次顺序在此指定。每个攻击组有3项条目。 # - 轮次数,这可以由整数对比环境中参考。 攻击组 - 被分配到该轮次的攻击组名称。 延迟 - 下一攻击轮次开始前间隔的时间。 最小力量 - 一次进攻轮次所必要的最少单位数。 初始化延迟 - 第一轮进攻所需要的时间。 重复轮次 - 从上一轮结束后,还会重复多少轮。 目标优先权 - 各轮进攻的目标。这里有两个项目。 目标 - 选择AI的进攻目标。列表中越高的目标就有越早的优先权。
/
本文档为【魔兽地图制作文档解释】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索