我用Lily快速启动器将我平时常用的一些魔兽工具做了整合。整个工具箱分为常用工具和非常用工具。常用工具常用工具是我平时汉化时，使用频率非常高的一类工具。下载解压，双击运行Lily.exe后就能看到这些工具。如下图：我从上到下从左到右一一做个简单的介绍Jass编辑4.2软件原名：EverEdit主要作用：汉化完war3map.j文件后，用这个软件菜单栏-Jass下的2个工具校验下，就知道哪里的jass语法有问题。很是方便。其他作用：使用Jass语法高亮修改war3map.j。火龙拆图2.05软件原名：HkeW3mModifier主要作用：能解压和替换90%的外国地图。但是有一些韩图加密就无能为力了。地图信息修改0.8软件原名：ShadowEditor主要作用：修改房间列表的地图名称，以及载入图时的信息模型查看1.05软件原名：War3ModelEditor（俗称绿苹果）主要作用：有时俄语有写生僻词，光看翻译完全不知道是个啥，那就用这个软件去查看单位模型或者物品图标，就能知道大概造个什么名字字符串转哈希值这个我用的多，新手可能用的不是太多。用途就是字面意思。SLK优化软件原名：w3x2lni主要作用：当你有源图时，或者有完整的文件列表时，你就可以用这个软件把地图优化为slk。这样地图的加载速度就会变快。MPQEditor主要作用：把地图丢进去，通过这个软件启动魔兽分析地图，有时可以获取到完整的文件列表。这样就可以执行slk优化了。魔兽分析2.5主要作用：一些头部信息加密的地图，如果用火龙解压或者修改，地图体积会从几兆变成几百兆。那么就可以用这个软件重建，再用火龙解压替换。下载地址回复可见：(抱歉，隐藏内容评论后可见)如果以上链接点击无效，可以访问下载页：(抱歉，隐藏内容评论后可见)下载注意事项：1、安装了杀毒软件的小伙伴，解压完后务必将解压后的文件件加入杀毒软件信任区。不加入的多半火龙会误报有毒。2、Lily快速启动器完全免费，无联网，无自动更新，纯绿色，设置开机自启动后不写注册表。一些你们使用频率低的软件也可以新建一个标签再拖进去。可以有效让桌面干净整洁。不常用工具<未完待续>
2025年太阳编辑器_V6.35学思笔记6：太阳编辑器框架介绍
想要使用太阳编辑器制作魔兽地图，在粗略掌握TS语言基础语法之后，必须了解太阳编辑器的框架有哪些功能。太阳编辑器框架是一个专门为魔兽地图开发设计的完整解决方案，它通过提供各种标准化的模块和工具，大大简化了地图开发的复杂度，提高了开发效率，同时保证了代码质量和游戏性能。框架的主要优势降低开发难度提供高层封装简化复杂操作标准化的接口提高开发效率丰富的工具类现成的功能模块可复用的组件代码质量保证统一的编码规范类型安全(TypeScript)模块化设计游戏性能优化统一的资源管理优化的数据结构性能监控机制扩展性与维护性松耦合设计插件化架构易于扩展太阳编辑器框架(Solar Framework)结构介绍1. Actor(演员)系统这是框架的核心系统之一,位于 solar/solar-common/actor/ 目录下:- Actor.ts - 基础演员类,是所有演员类型的父类 - ActorAbility.ts - 技能演员 - ActorBuff.ts - Buff演员 - ActorItem.ts - 物品演员 - ActorUnit.ts - 单位演员演员系统提供了一个统一的数据结构来模拟游戏中的各种对象(单位、物品、技能、buff等)。主要优点是:统一的数据结构和接口方便对象之间的转换(如物品可以转化为buff)提供标准的事件系统2. 状态(State)系统位于 solar/solar-common/actor/state/ 目录:- SolarActorState.ts - 演员系统的状态管理 - SolarActorBuffState.ts - Buff状态管理 - SolarActorFrameState.ts - UI框架状态管理 - SolarActorItemState.ts - 物品状态管理 - SolarActorUnitState.ts - 单位状态管理状态系统负责管理各种游戏对象的状态变化,处理状态之间的转换和同步。3. 工具(Util)类位于 solar/solar-common/actor/util/ 目录:- ActorUtil.ts - 通用演员工具类 - ActorAbilityUtil.ts - 技能工具类 - ActorBuffUtil.ts - Buff工具类 - ActorItemUtil.ts - 物品工具类 - ActorUnitUtil.ts - 单位工具类 - ActorFrameUtil.ts - UI框架工具类提供了各种辅助方法来操作演员对象。4. 属性(Attribute)系统位于 solar/solar-common/attribute/ 目录:- BigAttributeCompatibleState.ts - 大数值属性兼容 - BigAttributeUICompatibleState.ts - 大数值UI显示兼容 - ItemAttributeState.ts - 物品属性系统属性系统负责:管理游戏对象的各种属性(攻击、防御、生命等)处理属性的叠加、消除支持大数值模式处理UI显示主要特点模块化设计各个系统之间相对独立便于维护和扩展统一的接口使用演员系统统一各种游戏对象提供标准的事件系统完善的工具类提供丰富的工具方法简化开发流程灵活的属性系统支持复杂的属性计算支持大数值模式这个框架的设计理念是提供一个统一的、易于使用的接口来处理游戏中的各种对象,同时保持足够的灵活性以适应不同的游戏需求。Actor(演员)系统详细介绍1. 基本概念Actor(演员)系统是一个统一的数据结构,用来模拟游戏中的各种对象:单位(ActorUnit)物品(ActorItem)技能(ActorAbility)Buff(ActorBuff)2. 主要类型// 基础演员类型 interface AppActorType { id: string; // 演员类型ID name?: string; // 名称 icon?: string; // 图标 describe?: string; // 描述 class?: string; // 分类 // ... 其他基础属性 } // 物品演员类型 interface AppActorItemType extends AppActorType { pawnable?: boolean; // 是否可抵押 droppable?: boolean; // 是否可丢弃 uses?: number; // 使用次数 stackMax?: number; // 最大堆叠数 } // 技能演员类型 interface AppActorAbilityType extends AppActorType { lumberCost?: number; // 魔法消耗 // ... 技能相关属性 }3. 使用示例3.1 注册演员类型// 注册一个物品类型 ActorTypeUtil.registerActorType({ id: "神圣剑", name: "神圣之剑", icon: "ReplaceableTextures\\CommandButtons\\BTNSword.blp", describe: "增加100点攻击力", class: "武器", // 物品属性 pawnable: true, droppable: true, // 事件处理 onCreated: (actor) => { // 创建时的逻辑 }, onUnitPickupItem: (actor, unit) => { // 单位拾取时的逻辑 } });3.2 创建演员实例// 创建物品 let sword = ActorItemUtil.createActorItem("神圣剑", x, y); // 创建单位 let hero = ActorUnitUtil.createActorUnit(player, "英雄", x, y); // 创建技能 let skill = ActorAbilityUtil.createActorAbility("技能ID", unit); // 创建Buff let buff = ActorBuffUtil.addActorBuff(unit, "BuffID");3.3 事件处理// 在注册类型时定义事件处理 { // 创建时触发 onCreated: (actor: Actor) => { // ... }, // 单位获得此演员时触发 onUnitAddActor: (actor: Actor, addedActor: Actor) => { // ... }, // 单位失去此演员时触发 onUnitRemoveActor: (actor: Actor, removedActor: Actor) => { // ... }, // 单位死亡时触发 onUnitDeath: (actor: Actor, killingUnit: unit) => { // ... } }3.4 属性系统集成// 设置物品属性 AttributeUtil.setItemTypeAttribute("神圣剑", { attack: 100, armor: 10 }); // 获取单位所有演员属性 let attributes = ActorUtil.getUnitAllActorAttributes(unit);3.5 实际应用示例以下是一个双击物品交换的示例:ActorTypeUtil.registerActorType({ id: "可交换物品", class: "物品", onLocalClick: (actor, btn) => { if(actor.tempNum == null) { actor.tempNum = _g_time; } else { // 判断是否双击 if(_g_time - actor.tempNum < 0.5) { // 交换物品逻辑 let unit = actor.unit; let targetUnit = GetSpellTargetUnit(); if(IsHandle(targetUnit)) { UnitAddItem(targetUnit, actor.item); } } actor.tempNum = null; } } });4. 主要优点统一接口所有游戏对象使用相同的接口方便处理对象之间的转换事件系统提供标准的事件处理机制方便监听和响应游戏事件属性系统集成与属性系统无缝集成方便处理属性的叠加和移除扩展性易于添加新的演员类型易于扩展现有功能5. 使用建议优先使用 ActorUtil 而不是具体的工具类,保持代码的通用性合理使用事件系统,避免直接修改对象状态注意演员的生命周期管理,及时销毁不需要的演员使用属性系统来处理数值相关的逻辑通过这个系统,你可以用统一的方式处理游戏中的各种对象,大大简化开发流程。我来详细介绍状态(State)系统的使用。状态(State)系统详细介绍1. 基本概念状态系统主要负责:管理游戏对象的状态变化处理状态之间的转换同步状态更新响应状态变化的事件2. 主要状态类1. SolarActorState - 演员系统总状态管理 2. SolarActorBuffState - Buff状态管理 3. SolarActorFrameState - UI框架状态管理 4. SolarActorItemState - 物品状态管理 5. SolarActorUnitState - 单位状态管理3. 使用示例3.1 创建自定义状态// 创建一个双击物品交换状态 export default class 类双击物品时英雄宝宝交换该物品 { constructor() { // 注册状态 ActorTypeUtil.registerActorType({ id: "双击交换物品", class: "物品", // 本地点击事件 onLocalClick: (actor, btn) => { if(actor.tempNum == null) { // 记录第一次点击时间 actor.tempNum = _g_time; } else { // 判断是否双击(间隔小于0.5秒) if(_g_time - actor.tempNum < 0.5) { // 执行交换逻辑 let unit = actor.unit; let targetUnit = GetSpellTargetUnit(); if(IsHandle(targetUnit)) { UnitAddItem(targetUnit, actor.item); } } actor.tempNum = null; } } }); } }3.2 Buff状态管理// 创建一个持续性Buff状态 ActorTypeUtil.registerActorType({ id: "持续回血Buff", class: "Buff", // 创建时触发 onCreated: (actor) => { // 设置持续时间 actor.set("dur", 10); // 设置间隔 actor.setTimerInterval(1); }, // 间隔触发 onInterval: (actor) => { // 每秒恢复生命值 let unit = actor.unit; if(IsHandle(unit)) { SetUnitState(unit, UNIT_STATE_LIFE, GetUnitState(unit, UNIT_STATE_LIFE) + 100); } } });3.3 物品状态管理// 创建一个可升级物品状态 ActorTypeUtil.registerActorType({ id: "升级物品", class: "物品", // 物品属性 level: 1, maxLevel: 5, // 使用物品时触发 onAction: (actor) => { if(actor.get("level") < actor.get("maxLevel")) { // 升级物品 actor.set("level", actor.get("level") + 1); // 更新属性 actor.attribute = { attack: 100 * actor.get("level") }; } } });3.4 单位状态管理// 创建一个单位状态 ActorTypeUtil.registerActorType({ id: "英雄单位", class: "单位", // 单位属性 maxLife: 1000, maxMana: 500, // 创建时触发 onCreated: (actor) => { // 初始化单位属性 SetUnitState(actor.unit, UNIT_STATE_MAX_LIFE, actor.get("maxLife")); SetUnitState(actor.unit, UNIT_STATE_MAX_MANA, actor.get("maxMana")); }, // 单位升级时触发 onUnitLevelUp: (actor) => { // 升级时增加属性 actor.set("maxLife", actor.get("maxLife") + 100); actor.set("maxMana", actor.get("maxMana") + 50); } });3.5 UI状态管理// 创建一个UI状态 ActorTypeUtil.registerActorType({ id: "物品UI", class: "物品", // UI相关属性 icon: "xxx.blp", // 创建时触发 onCreated: (actor) => { // 创建UI框架 let frame = actor.getRootFrameControl(); frame.setIcon(actor.get("icon")); }, // 状态改变时触发 onUpdate: (actor) => { // 更新UI显示 let frame = actor.getRootFrameControl(); frame.setText(actor.getName()); } });4. 状态系统的特点状态隔离每个状态独立管理避免状态之间的相互干扰事件驱动通过事件触发状态变化方便响应游戏中的各种变化数据同步确保多个玩家之间的状态同步处理网络延迟问题UI集成与UI系统紧密集成自动更新界面显示5. 使用建议状态定义清晰定义状态的属性和行为避免状态之间的耦合事件处理合理使用事件系统注意事件的触发顺序性能优化避免频繁的状态更新合理使用缓存机制调试支持添加必要的日志方便问题定位通过状态系统,你可以更好地管理游戏对象的生命周期和行为,使代码更加清晰和易于维护。我来详细介绍工具(Util)类的使用。工具(Util)类详细介绍1. 主要工具类1. ActorUtil - 通用演员工具类 2. ActorAbilityUtil - 技能工具类 3. ActorBuffUtil - Buff工具类 4. ActorItemUtil - 物品工具类 5. ActorUnitUtil - 单位工具类 6. ActorFrameUtil - UI框架工具类 7. ActorTypeUtil - 演员类型工具类2. 常用工具类详解2.1 ActorUtil (通用演员工具)// 获取单位所有演员列表 let actors = ActorUtil.getUnitAllActorList(unit); // 遍历单位所有演员 ActorUtil.forUnitAllActorList(unit, (actor) => { // 处理每个演员 }); // 判断单位是否拥有某个演员 if(ActorUtil.isUnitHasActor(unit, "演员ID")) { // ... } // 获取单位所有演员属性 let attributes = ActorUtil.getUnitAllActorAttributes(unit);2.2 ActorItemUtil (物品工具)// 创建演员物品 let item = ActorItemUtil.createActorItem("物品ID", x, y); // 给单位添加演员物品 let actorItem = ActorItemUtil.addActorItemForUnit("物品ID", unit); // 获取单位指定类型的演员物品列表 let items = ActorItemUtil.getUnitActorItemList(unit, "物品ID"); // 判断单位是否拥有某个演员物品 if(ActorItemUtil.isUnitHasActorItem(unit, "物品ID")) { // ... }2.3 ActorBuffUtil (Buff工具)// 添加Buff let buff = ActorBuffUtil.addActorBuff(unit, "BuffID", creator); // 获取单位的Buff let buff = ActorBuffUtil.getUnitActorBuff(unit, "BuffID"); // 清除单位的Buff ActorBuffUtil.clearUnitActorBuff(unit, "BuffID"); // 清除单位所有Buff ActorBuffUtil.clearUnitActorBuffs(unit); // 添加Buff事件监听 ActorBuffUtil.addAnyActorBuffCreatedListener((buff) => { // 处理Buff创建事件 });2.4 ActorTypeUtil (类型工具)// 注册演员类型 ActorTypeUtil.registerActorType({ id: "自定义类型", name: "测试类型", class: "物品", // ... 其他属性 }); // 获取演员类型 let actorType = ActorTypeUtil.getActorType("类型ID"); // 遍历所有演员类型 ActorTypeUtil.forAllActorTypes((actorType) => { // 处理每个类型 }); // 从基础物品注册演员类型 ActorTypeUtil.registerActorTypeFromBaseItemType("物品ID", { // 额外属性 });2.5 ActorFrameUtil (UI工具)// 显示提示文本 ActorFrameUtil.showTipText(actor, "提示信息", 1.0); // 显示警告文本 ActorFrameUtil.showWarnText(actor, "警告信息"); // 显示成功文本 ActorFrameUtil.showSuccessText(actor, "成功信息"); // 显示工具提示 ActorFrameUtil.showTooltip(actor);3. 实际应用示例3.1 物品升级系统// 创建可升级物品 function createUpgradeableItem(itemId: string, unit: unit) { // 创建物品 let item = ActorItemUtil.createActorItem(itemId, 0, 0); // 添加到单位 UnitAddItem(unit, item.item); // 设置初始属性 item.attribute = { attack: 100, level: 1 }; return item; } // 升级物品 function upgradeItem(item: ActorItem) { let level = item.attribute.level + 1; item.attribute = { attack: 100 * level, level: level }; }3.2 Buff管理系统// Buff管理器 class BuffManager { // 添加Buff static addBuff(unit: unit, buffId: string) { // 检查是否已有此Buff let existBuff = ActorBuffUtil.getUnitActorBuff(unit, buffId); if(existBuff) { // 刷新持续时间 existBuff.update(); return; } // 添加新Buff ActorBuffUtil.addActorBuff(unit, buffId); } // 清理过期Buff static cleanExpiredBuffs(unit: unit) { ActorBuffUtil.forUnitActorBuffs(unit, (buff) => { if(buff.getRemainingTime() <= 0) { buff.destroy(); } }); } }3.3 物品交换系统// 物品交换助手 class ItemExchangeHelper { // 交换两个单位的物品 static exchangeItems(unit1: unit, unit2: unit, itemId: string) { // 获取物品 let items1 = ActorItemUtil.getUnitActorItemList(unit1, itemId); let items2 = ActorItemUtil.getUnitActorItemList(unit2, itemId); // 执行交换 if(items1 && items1.length > 0) { UnitAddItem(unit2, items1[0].item); } if(items2 && items2.length > 0) { UnitAddItem(unit1, items2[0].item); } } }4. 使用建议选择合适的工具类优先使用 ActorUtil 处理通用逻辑特殊需求使用专门的工具类性能考虑避免频繁创建和销毁对象合理使用缓存机制错误处理添加必要的参数检查处理异常情况代码组织按功能模块组织代码保持代码清晰简洁工具类提供了丰富的功能来简化开发,合理使用可以大大提高开发效率。我来详细介绍属性(Attribute)系统的使用。属性(Attribute)系统详细介绍1. 基本概念属性系统主要包含三个部分:// 1. 基础属性接口 interface SolarAttribute { attack?: number; // 攻击力 armor?: number; // 护甲 maxLife?: number; // 最大生命 maxMana?: number; // 最大魔法 strength?: number; // 力量 agility?: number; // 敏捷 intelligence?: number; // 智力 // ... 其他属性 } // 2. 大数值属性支持 // BigAttributeCompatibleState.ts - 处理超过魔兽默认上限的属性值 // 3. 属性UI显示 // BigAttributeUICompatibleState.ts - 处理大数值的UI显示2. 主要功能2.1 基础属性设置// 设置物品类型属性 AttributeUtil.setItemTypeAttribute("神圣剑", { attack: 100, armor: 10, strength: 20 }); // 设置单位属性 AttributeUtil.setUnitAttribute(unit, { maxLife: 1000, maxMana: 500 }); // 设置Buff属性 AttributeUtil.setBuffAttribute(buff, { attack: 50, agility: 30 });2.2 大数值支持// 开启大数值支持 new BigAttributeCompatibleState(); // 设置超大数值 SetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD, 999999999); SetUnitState(unit, UNIT_STATE_MAX_LIFE, 100000000); // 获取真实属性值 let realGold = GetPlayerState(player, PLAYER_STATE_RESOURCE_GOLD); let realLife = GetUnitState(unit, UNIT_STATE_MAX_LIFE);2.3 属性UI显示// 开启大数值UI支持 new BigAttributeUICompatibleState(); // 配置UI显示 BigAttributeUICompatibleState.config = { isShowGreenAttack: false, // 是否显示绿字攻击力 isShowGreenArmor: false // 是否显示绿字护甲 };3. 实际应用示例3.1 创建带属性的物品// 注册物品类型 ActorTypeUtil.registerActorType({ id: "力量之剑", name: "力量之剑", class: "武器", // 设置基础属性 onCreated: (actor) => { actor.attribute = { attack: 100, strength: 20 }; }, // 升级时增加属性 onLevelUp: (actor) => { let level = actor.level; actor.attribute = { attack: 100 * level, strength: 20 * level }; } });3.2 属性叠加系统// 创建属性叠加管理器 class AttributeStackManager { // 叠加属性 static stackAttribute(unit: unit, attribute: SolarAttribute) { let currentAttr = AttributeUtil.getUnitAttribute(unit, true); // 叠加各项属性 AttributeUtil.add(currentAttr, attribute); // 刷新单位属性 UnitAttributeState.refreshUnitSolarAttribute(unit); } // 移除属性 static removeAttribute(unit: unit, attribute: SolarAttribute) { let currentAttr = AttributeUtil.getUnitAttribute(unit); // 移除属性 AttributeUtil.subtract(currentAttr, attribute); // 刷新单位属性 UnitAttributeState.refreshUnitSolarAttribute(unit); } }3.3 Buff属性系统// 创建属性Buff ActorTypeUtil.registerActorType({ id: "力量Buff", class: "Buff", // 设置Buff属性 onCreated: (actor) => { actor.attribute = { strength: 50 }; // 设置持续时间 actor.set("dur", 10); }, // Buff层数变化时 onLevelChange: (actor, delta) => { // 根据层数调整属性 actor.attribute = { strength: 50 * actor.level }; } });3.4 装备属性系统// 装备属性管理器 class EquipmentAttributeManager { // 装备物品 static equipItem(unit: unit, item: ActorItem) { // 获取物品属性 let itemAttr = item.attribute; if(!itemAttr) return; // 应用装备属性 let unitAttr = AttributeUtil.getUnitAttribute(unit, true); AttributeUtil.add(unitAttr, itemAttr); // 刷新属性 UnitAttributeState.refreshUnitSolarAttribute(unit); } // 卸下物品 static unequipItem(unit: unit, item: ActorItem) { let itemAttr = item.attribute; if(!itemAttr) return; // 移除装备属性 let unitAttr = AttributeUtil.getUnitAttribute(unit); AttributeUtil.subtract(unitAttr, itemAttr); // 刷新属性 UnitAttributeState.refreshUnitSolarAttribute(unit); } }4. 使用建议属性定义明确定义需要的属性类型合理设置属性值范围大数值处理需要大数值时开启相应支持注意性能影响属性计算使用工具类进行属性计算注意属性叠加顺序UI显示合理配置UI显示方式处理数值格式化性能优化避免频繁的属性计算合理使用缓存机制属性系统是游戏中的重要组成部分,合理使用可以实现复杂的属性计算和效果。通过与其他系统(如演员系统、状态系统)的配合,可以实现更加丰富的游戏功能。其他重要且常用的模块1. 事件系统 (Solar Event System)// 使用示例 se.onUnitDeath((e) => { // 单位死亡事件处理 }); se.playerChat("command", () => { // 玩家聊天命令处理 });这是一个统一的事件分发系统，用于处理游戏中的各种事件。2. 数据管理系统 (DataBase)// 使用示例 let solarData = DataBase.getUnitSolarData(unit); let playerData = DataBase.getPlayerSolarData(player);用于管理和存储游戏对象(单位、玩家等)的数据。3. UI框架系统// 使用示例 class MyUI { constructor() { // 创建UI元素 let frame = Frame.createTEXTBUTTON(); frame.setText("按钮文本"); frame.setSize(0.1, 0.02); // 设置点击事件 frame.setOnClick(() => { // 处理点击事件 }); } }提供了丰富的UI创建和管理功能。4. 存档系统 (Archive System)// 使用示例 ArchiveUtil.set(player, "key", value); let data = ArchiveUtil.get(player, "key");用于处理游戏存档和读档功能。5. 同步系统 (Sync System)// 使用示例 SyncUtil.syncData("eventName", data); SyncUtil.onSyncData("eventName", (player, data) => { // 处理同步数据 });处理多人游戏中的数据同步。6. 基础工具类 (BaseUtil)// 使用示例 BaseUtil.runLater(1.0, () => { // 延迟执行 }); BaseUtil.onTimer(1.0, () => { // 定时执行 return true; });提供了大量常用的工具方法。7. 伤害系统 (Damage System)// 使用示例 SolarDamageState.addEventHandler(event => { // 处理伤害事件 if(event.isAttack) { // 处理攻击伤害 } });处理游戏中的伤害计算和效果。8. 玩家系统 (Player System)// 使用示例 PlayerUtil.forUsers(player => { // 处理每个玩家 }); PlayerUtil.addGoldState(player, amount);提供了玩家相关的功能。这些模块在项目中经常配合使用，例如：// 综合使用示例 class GameSystem { constructor() { // 注册事件 se.onUnitDeath((e) => { // 获取数据 let unitData = DataBase.getUnitSolarData(e.trigUnit); let playerData = DataBase.getPlayerSolarData(e.trigUnitOwner); // 更新属性 AttributeUtil.setUnitAttribute(e.trigUnit, { attack: 100, armor: 10 }); // 同步数据 SyncUtil.syncData("unitDeath", { unit: e.trigUnit, player: e.trigUnitOwner }); // 存档 ArchiveUtil.set(e.trigUnitOwner, "deathCount", (ArchiveUtil.get(e.trigUnitOwner, "deathCount") || 0) + 1); }); } }这些模块都是紧密关联的，共同构成了一个完整的游戏开发框架。每个模块都有其特定的职责，但又能很好地协同工作。选择使用哪些模块主要取决于具体的游戏需求。
TypeScript 的函数基本函数定义// 普通函数 function createHero(player: player, x: number, y: number): unit { return CreateUnit(player, HERO_ID, x, y, 0); } // 带有多个参数的函数 function dealDamage(source: unit, target: unit, amount: number): void { let finalDamage = amount; if (IsUnitType(target, UNIT_TYPE_HERO)) { finalDamage *= 0.8; // 英雄受到的伤害降低 } UnitDamageTarget(source, target, finalDamage, true); }构造函数class Hero { unit: unit; level: number; items: item[]; // 构造函数 constructor(player: player, heroId: number, x: number, y: number) { // 创建英雄单位 this.unit = CreateUnit(player, heroId, x, y, 0); this.level = 1; this.items = []; // 初始化英雄属性 this.initializeHero(); } private initializeHero(): void { // 设置初始属性 SetHeroLevel(this.unit, 1, false); SetUnitState(this.unit, UNIT_STATE_MANA, 100); } } // 使用构造函数创建英雄 let myHero = new Hero(Player(0), PALADIN_ID, 0, 0);箭头函数// 基础箭头函数 let calculateDamage = (base: number, multiplier: number): number => { return base * multiplier; }; // 简写形式（单行返回） let getUnitHealth = (unit: unit): number => GetUnitState(unit, UNIT_STATE_LIFE); // 在事件回调中使用箭头函数 let trigger = CreateTrigger(); TriggerAddAction(trigger, () => { let unit = GetTriggerUnit(); let damage = calculateDamage(100, 1.5); dealDamage(unit, GetTriggerUnit(), damage); });函数作为参数class BuffSystem { // 函数类型定义 type BuffEffect = (unit: unit) => void; // 使用函数作为参数 applyBuff(target: unit, duration: number, effect: BuffEffect): void { // 立即应用效果 effect(target); // 设置定时器移除效果 TimerStart(CreateTimer(), duration, false, () => { effect(target); DestroyTimer(GetExpiredTimer()); }); } } // 使用示例 let buffSystem = new BuffSystem(); buffSystem.applyBuff(hero, 10, (unit) => { // 增加移动速度 SetUnitMoveSpeed(unit, GetUnitMoveSpeed(unit) * 1.5); });方法函数（类中的函数）class ItemSystem { private items: Map<number, item>; constructor() { this.items = new Map(); } // 实例方法 addItem(itemId: number, x: number, y: number): item { let newItem = CreateItem(itemId, x, y); this.items.set(GetHandleId(newItem), newItem); return newItem; } // 静态方法 static isValidItem(item: item): boolean { return item != null && GetHandleId(item) > 0; } // 私有方法 private cleanupItem(item: item): void { this.items.delete(GetHandleId(item)); RemoveItem(item); } }异步函数class SpellSystem { // 异步施法函数 async castDelayedSpell(caster: unit, target: unit, delay: number): Promise<void> { // 开始施法动作 SetUnitAnimation(caster, "spell"); // 等待延迟 await new Promise(resolve => { TimerStart(CreateTimer(), delay, false, () => { resolve(); DestroyTimer(GetExpiredTimer()); }); }); // 施放法术效果 this.applySpellEffect(target); } }函数重载class DamageSystem { // 函数重载声明 dealDamage(source: unit, target: unit, amount: number): void; dealDamage(source: unit, target: unit, amount: number, damageType: number): void; // 函数实现 dealDamage(source: unit, target: unit, amount: number, damageType?: number): void { if (damageType === undefined) { // 默认物理伤害 UnitDamageTarget(source, target, amount, true); } else { // 特定类型伤害 BlzSetUnitDamage(source, amount, damageType); UnitDamageTarget(source, target, amount, true); } } }闭包函数class BuffManager { createBuff(baseEffect: number) { // 返回一个新函数，它记住了baseEffect的值 return (unit: unit) => { let currentLevel = GetHeroLevel(unit); let totalEffect = baseEffect * (1 + currentLevel * 0.1); return totalEffect; }; } // 使用闭包 let strengthBuff = this.createBuff(50); let actualBonus = strengthBuff(hero); // 根据英雄等级计算实际加成 }实际应用示例class SpellSystem { constructor() { // 在构造函数中初始化 this.initializeSpells(); } private initializeSpells(): void { // 使用箭头函数注册技能效果 this.registerSpell("火球术", (caster, target) => { let damage = 100 + GetHeroInt(caster, true) * 2; this.dealSpellDamage(caster, target, damage); }); this.registerSpell("治疗术", (caster, target) => { let healing = 150 + GetHeroInt(caster, true) * 1.5; this.healUnit(target, healing); }); } // 异步施法函数 async castSpell(spellName: string, caster: unit, target: unit): Promise<void> { let spellEffect = this.spellEffects.get(spellName); if (!spellEffect) return; // 检查施法条件 if (!this.canCastSpell(caster)) return; try { await this.startCasting(caster); spellEffect(caster, target); } catch (error) { print("施法失败：" + error); } } }关键点总结：构造函数用于初始化类实例箭头函数提供更简洁的语法和词法作用域的this函数可以作为参数传递异步函数处理需要等待的操作函数重载提供多种调用方式闭包可以记住其词法作用域延伸阅读：构造函数构造函数是一个特殊的函数，用于创建和初始化对象。它在创建对象时自动调用，通常用于设置对象的初始状态或属性。下面是一些通俗易懂的解释和示例：1. 什么是构造函数？定义：构造函数是一个类中的方法，用于初始化新创建的对象。自动调用：当你使用 new 关键字创建一个对象时，构造函数会被自动调用。2. 构造函数的作用初始化属性：构造函数可以设置对象的初始属性值。执行启动逻辑：可以在对象创建时执行一些必要的逻辑，比如分配资源或设置状态。3. 构造函数的基本语法在 TypeScript 中，构造函数的定义通常在类中，使用 constructor 关键字。class ClassName { constructor(parameters) { // 初始化代码 } }4. 示例假设我们要创建一个表示“英雄”的类，构造函数可以用来初始化英雄的名称、等级和生命值。class Hero { name: string; // 英雄名称 level: number; // 英雄等级 health: number; // 英雄生命值 // 构造函数 constructor(name: string, level: number, health: number) { this.name = name; // 设置名称 this.level = level; // 设置等级 this.health = health; // 设置生命值 } } // 使用构造函数创建一个新的英雄对象 let myHero = new Hero("战士", 1, 100); // 访问英雄的属性 console.log(myHero.name); // 输出: 战士 console.log(myHero.level); // 输出: 1 console.log(myHero.health); // 输出: 1005. 关键点this 关键字：在构造函数中，this 代表当前正在创建的对象。通过 this 可以访问和设置对象的属性。参数：构造函数可以接受参数，以便在创建对象时传入初始值。自动调用：构造函数在使用 new 关键字创建对象时自动调用，无需手动调用。6. 总结构造函数是创建对象时的“启动器”，它帮助我们设置对象的初始状态。通过构造函数，我们可以确保每个对象在创建时都有合理的初始值和状态。延伸阅读：箭头函数箭头函数是 JavaScript 和 TypeScript 中的一种简化函数定义的语法。它们提供了一种更简洁的方式来编写函数，同时还具有一些独特的特性。下面是对箭头函数的通俗易懂的介绍：1. 什么是箭头函数？定义：箭头函数是一种使用 => 符号定义的函数。它可以用来替代传统的函数表达式。语法：箭头函数的基本语法如下：(参数1, 参数2, ...) => { // 函数体 }2. 箭头函数的特点简洁性：箭头函数的语法比传统函数更简洁，尤其是在处理简单的逻辑时。没有自己的 this：箭头函数不会创建自己的 this，它会从外部上下文中继承 this 的值。这在处理回调函数时非常有用。3. 示例传统函数 vs 箭头函数传统函数定义：function add(a, b) { return a + b; }箭头函数定义：const add = (a, b) => { return a + b; };简化的箭头函数如果函数体只有一行代码，可以省略大括号和 return 关键字：const add = (a, b) => a + b; // 省略了大括号和 return4. 使用场景1. 数组操作箭头函数常用于数组的 map、filter 和 reduce 等方法中：const numbers = [1, 2, 3, 4, 5]; // 使用箭头函数进行平方计算 const squares = numbers.map(num => num * num); console.log(squares); // 输出: [1, 4, 9, 16, 25]2. 事件处理在事件处理函数中，箭头函数可以避免 this 的问题：class Counter { count = 0; increment = () => { this.count++; // 这里的 this 指向 Counter 实例 console.log(this.count); } } const counter = new Counter(); const button = document.createElement('button'); button.innerText = '增加'; button.addEventListener('click', counter.increment); // 使用箭头函数 document.body.appendChild(button);5. 总结简洁性：箭头函数提供了一种更简洁的函数定义方式，特别适合用于简单的逻辑。this 绑定：箭头函数不会创建自己的 this，而是从外部上下文中继承，这在处理回调时非常有用。适用场景：常用于数组操作、事件处理等场景。
TypeScript 中的模块系统1. 模块基础概念模块是一种组织和复用代码的方式，可以把相关的代码组织在一起，并控制其访问范围。// 文件: src/systems/HeroSystem.ts export class HeroSystem { createHero() { /* ... */ } levelUp() { /* ... */ } } // 文件: src/App.ts import { HeroSystem } from "./systems/HeroSystem"; let heroSystem = new HeroSystem();2. 导出（Export）有几种不同的导出方式：// 1. 默认导出 (src/systems/ItemSystem.ts) export default class ItemSystem { createItem() { /* ... */ } removeItem() { /* ... */ } } // 2. 命名导出 (src/config/GameConfig.ts) export const HERO_STATS = { baseHealth: 500, baseMana: 300 }; export function calculateDamage() { // ... } // 3. 多个导出 (src/utils/GameUtils.ts) export class MathUtils { static random(min: number, max: number) { /* ... */ } } export class StringUtils { static format(text: string, ...args: any[]) { /* ... */ } }3. 导入（Import）对应的导入方式：// 1. 导入默认导出 import ItemSystem from "./systems/ItemSystem"; // 2. 导入命名导出 import { HERO_STATS, calculateDamage } from "./config/GameConfig"; // 3. 导入多个内容 import { MathUtils, StringUtils } from "./utils/GameUtils"; // 4. 重命名导入 import { HERO_STATS as HeroConfig } from "./config/GameConfig"; // 5. 导入所有内容 import * as Utils from "./utils/GameUtils";4. 实际项目示例让我们看看这个项目中的一些实际例子：// src/solar/common/GlobalVars.ts export default class GlobalVars { static isDebug: boolean; static init(debug: boolean) { this.isDebug = debug; } } // src/systems/AbilitySystem.ts import GlobalVars from "../solar/common/GlobalVars"; import { DamageUtils } from "../utils/CombatUtils"; export class AbilitySystem { castSpell(caster: unit, target: unit) { // 使用导入的工具 if (GlobalVars.isDebug) { console.log("施放技能"); } let damage = DamageUtils.calculateSpellDamage(caster, target); // ... } }5. 模块组织示例// src/config/index.ts // 集中导出配置 export * from "./HeroConfig"; export * from "./ItemConfig"; export * from "./SpellConfig"; // src/systems/index.ts // 集中导出系统 export * from "./HeroSystem"; export * from "./ItemSystem"; export * from "./CombatSystem"; // src/App.ts // 统一导入 import { HeroSystem, ItemSystem, CombatSystem } from "./systems"; import { HERO_CONFIG, ITEM_CONFIG, SPELL_CONFIG } from "./config";6. 模块的优势代码组织// 相关功能组织在一起 // src/systems/CombatSystem.ts export class CombatSystem { private damageCalculator: DamageCalculator; private effectManager: EffectManager; constructor() { this.damageCalculator = new DamageCalculator(); this.effectManager = new EffectManager(); } }代码复用// src/utils/CommonUtils.ts export function delay(seconds: number): Promise<void> { return new Promise(resolve => { TimerStart(CreateTimer(), seconds, false, () => { DestroyTimer(GetExpiredTimer()); resolve(); }); }); } // 在其他文件中复用 import { delay } from "../utils/CommonUtils"; async function castDelayedSpell() { await delay(1.0); // 继续施法逻辑 }依赖管理// src/systems/SpellSystem.ts import { SPELL_CONFIG } from "../config"; import { EffectUtils } from "../utils/EffectUtils"; import { CombatUtils } from "../utils/CombatUtils"; export class SpellSystem { castFireball(caster: unit, target: unit) { let damage = SPELL_CONFIG.FIREBALL.damage; CombatUtils.dealDamage(caster, target, damage); EffectUtils.playSpellEffect("fireball", target); } }7. 最佳实践相关功能组织在一起// src/systems/HeroSystem/ // index.ts export * from "./HeroCreator"; export * from "./HeroStats"; export * from "./HeroAbilities"; // HeroCreator.ts export class HeroCreator { /* ... */ } // HeroStats.ts export class HeroStats { /* ... */ } // HeroAbilities.ts export class HeroAbilities { /* ... */ }清晰的导入导出// 明确导入需要的内容 import { HeroCreator, HeroStats } from "./systems/HeroSystem"; import { ItemManager } from "./systems/ItemSystem"; import { GAME_CONFIG } from "./config";避免循环依赖// 好的做法：明确的依赖方向 // HeroSystem 依赖 ItemSystem import { ItemSystem } from "./ItemSystem"; // ItemSystem 不依赖 HeroSystem export class ItemSystem { // 通过参数传递 hero，而不是导入 HeroSystem useItem(hero: unit, item: item) { /* ... */ } }默认导出(default export)和命名导出(named export)的区别1. 默认导出 (Default Export)每个模块只能有一个默认导出导入时可以使用任意名称通常用于导出模块的主要功能例如在 App.ts 中的默认导出:export default class App { start() { //先打印一个文本 让我们知道已运行到了TS入口代码 // DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, 'TS:App.start!'); //状态初始化 StateConfigInit(); StateInit(); abilitysss() //测试区 new AppTest().start() // if(idAndNum&&idAndNum.length>1&&idAndNum[0]&&idAndNum[1]){ // material[idAndNum[0]] = parseInt(idAndNum[1]) // } } }导入默认导出:import App from "./App"; // 可以使用任意名称 import MyApp from "./App"; // 同样有效2. 命名导出 (Named Export)一个模块可以有多个命名导出导入时必须使用相同的名称(除非使用 as 重命名)通常用于导出多个相关但独立的功能例如:// 命名导出 export const HERO_STATS = { baseHealth: 500, baseMana: 300 }; export function calculateDamage() { // ... } export class HeroSystem { // ... }导入命名导出:import { HERO_STATS, calculateDamage, HeroSystem } from "./HeroSystem"; // 使用 as 重命名 import { HERO_STATS as HeroConfig } from "./HeroSystem";3. 使用场景使用默认导出的情况：模块主要提供一个功能模块代表一个类/组件希望导入时有更灵活的命名例如在你的代码中:export default class GameStart { static is: unit static shangxian: number static i: number = 0; static j: number = 0; static k: number = 0; static l: number = 0; static z1: number = 0; static z2: number = 0; static z3: number = 0; static z4: number = 0; static addmoster = 0 static chuangkou: string[] = []; static zhuangbei: string[] = [ "a204", "a205", "a206", "a207", "a208", "a209", "a20a", "a20b", "a20c", "a20d", "a20e", ] static config: { start_text: string//初始文本 start_CreateUnitType: string//初始创建单位类型 pen_gives_bounty: number[]//获得奖励 } = { start_text: "",//初始文本 start_CreateUnitType: "jz01",//初始创建单位类型 pen_gives_bounty: [], } constructor() { this.Passive_trigger(); };使用命名导出的情况：模块提供多个相关但独立的功能需要导出常量、工具函数等希望强制使用特定的命名4. 最佳实践一个文件通常只应该有一个默认导出相关的功能可以使用命名导出组织在一起可以同时使用默认导出和命名导出，但要注意保持代码清晰例如:// 命名导出工具函数 export function delay(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } // 默认导出主类 export default class GameSystem { // ... }导入时:import GameSystem, { delay } from "./GameSystem";这样的组织方式使代码结构更清晰，更易于维护和使用。是的，在同一个 TypeScript 文件（模块）中只能有一个默认导出（export default）。让我用例子来说明：1. 正确的用法// 正确：一个文件只有一个默认导出 export default class Hero { // ... } // 可以有多个命名导出 export const HERO_STATS = { /* ... */ }; export function calculateDamage() { /* ... */ }; export class Equipment { /* ... */ };2. 错误的用法// ❌ 错误：不能有多个默认导出 export default class Hero { // ... } export default class Weapon { // 这会导致编译错误 // ... }3. 实际项目中的例子从你的项目代码中可以看到正确的使用方式：// 正确：只有一个默认导出 export default class App { start() { StateConfigInit(); StateInit(); abilitysss() new AppTest().start() } } // 其他代码...4. 如果需要导出多个内容，可以：使用命名导出// hero/index.ts export class Hero { /* ... */ } export class Weapon { /* ... */ } export class Armor { /* ... */ }将多个相关项组合成一个对象或类后默认导出// hero/index.ts class Hero { /* ... */ } class Weapon { /* ... */ } class Armor { /* ... */ } // 将相关内容组合后默认导出 export default { Hero, Weapon, Armor }使用命名导出和默认导出的组合// hero/index.ts export class Weapon { /* ... */ } export class Armor { /* ... */ } // 主要的类作为默认导出 export default class Hero { /* ... */ }5. 导入方式的区别// 导入默认导出 import Hero from './hero'; // 导入命名导出 import { Weapon, Armor } from './hero'; // 同时导入默认导出和命名导出 import Hero, { Weapon, Armor } from './hero'; // 导入组合的默认导出 import HeroSystem from './hero'; const { Hero, Weapon, Armor } = HeroSystem;记住：一个文件只能有一个 export default一个文件可以有任意数量的命名导出（export）默认导出和命名导出可以共存在同一个文件中选择使用默认导出还是命名导出应该基于模块的用途和组织结构
TypeScript 的类1. 基本类的定义和使用// 定义一个基础的英雄类 class Hero { // 属性定义 private unit: unit; // 英雄单位 private name: string; // 英雄名称 private level: number; // 英雄等级 private experience: number; // 经验值 // 构造函数 constructor(player: player, heroId: number, x: number, y: number) { // 创建英雄单位 this.unit = CreateUnit(player, heroId, x, y, 0); this.name = GetUnitName(this.unit); this.level = 1; this.experience = 0; // 初始化英雄 this.initialize(); } // 私有方法：初始化 private initialize(): void { // 设置初始属性 SetHeroLevel(this.unit, this.level, false); SetUnitState(this.unit, UNIT_STATE_MANA, 100); } // 公共方法：获取经验值 public gainExperience(amount: number): void { this.experience += amount; // 检查是否可以升级 this.checkLevelUp(); } // 私有方法：检查升级 private checkLevelUp(): void { let expNeeded = this.level * 100; // 简单的升级经验计算 if (this.experience >= expNeeded) { this.levelUp(); } } // 私有方法：升级 private levelUp(): void { this.level++; this.experience = 0; SetHeroLevel(this.unit, this.level, true); // 显示升级特效 let effect = AddSpecialEffect("Abilities\\Spells\\Other\\LevelUp\\LevelUpTarget.mdl", GetUnitX(this.unit), GetUnitY(this.unit)); DestroyEffect(effect); } }2. 继承和多态// 基础英雄类 abstract class BaseHero { protected unit: unit; protected mana: number = 100; // 抽象方法：每个英雄都必须实现的技能 abstract castSpell(target: unit): void; // 共享方法：所有英雄都可以使用的方法 protected consumeMana(cost: number): boolean { if (this.mana >= cost) { this.mana -= cost; return true; } return false; } } // 战士英雄类 class WarriorHero extends BaseHero { // 实现战士的技能 public castSpell(target: unit): void { if (this.consumeMana(50)) { // 战士的旋风斩 let damage = 150; let effect = AddSpecialEffect("Abilities\\Spells\\Human\\Whirlwind\\WhirlwindTarget.mdl", GetUnitX(target), GetUnitY(target)); UnitDamageTarget(this.unit, target, damage, true); DestroyEffect(effect); } } } // 法师英雄类 class MageHero extends BaseHero { // 实现法师的技能 public castSpell(target: unit): void { if (this.consumeMana(80)) { // 法师的火球术 let damage = 200; let effect = AddSpecialEffect("Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl", GetUnitX(target), GetUnitY(target)); UnitDamageTarget(this.unit, target, damage, true); DestroyEffect(effect); } } }3. 物品系统示例// 物品类 class Item { private item: item; private charges: number; constructor(itemId: number, x: number, y: number) { this.item = CreateItem(itemId, x, y); this.charges = 1; } public use(target: unit): void { if (this.charges > 0) { this.applyEffect(target); this.charges--; if (this.charges <= 0) { RemoveItem(this.item); } } } protected applyEffect(target: unit): void { // 基础物品效果 } } // 治疗药水类 class HealingPotion extends Item { protected applyEffect(target: unit): void { // 恢复生命值 let healing = 150; SetUnitState(target, UNIT_STATE_LIFE, GetUnitState(target, UNIT_STATE_LIFE) + healing); // 显示治疗特效 let effect = AddSpecialEffect("Abilities\\Spells\\Items\\HealingSalve\\HealingSalveTarget.mdl", GetUnitX(target), GetUnitY(target)); DestroyEffect(effect); } }4. 游戏管理器类class GameManager { private static instance: GameManager; private heroes: Map<player, Hero>; private items: Item[]; private constructor() { this.heroes = new Map(); this.items = []; this.initialize(); } // 单例模式获取实例 public static getInstance(): GameManager { if (!GameManager.instance) { GameManager.instance = new GameManager(); } return GameManager.instance; } // 初始化游戏 private initialize(): void { // 为每个玩家创建英雄 for (let i = 0; i < bj_MAX_PLAYERS; i++) { let player = Player(i); if (GetPlayerController(player) == MAP_CONTROL_USER) { this.createHeroForPlayer(player); } } // 创建初始物品 this.spawnInitialItems(); } // 为玩家创建英雄 private createHeroForPlayer(player: player): void { // 让玩家选择英雄类型 let heroType = this.getPlayerHeroChoice(player); let hero: Hero; if (heroType === "warrior") { hero = new WarriorHero(player, WARRIOR_ID, 0, 0); } else { hero = new MageHero(player, MAGE_ID, 0, 0); } this.heroes.set(player, hero); } // 生成初始物品 private spawnInitialItems(): void { // 在地图上生成一些治疗药水 for (let i = 0; i < 5; i++) { let x = GetRandomReal(-500, 500); let y = GetRandomReal(-500, 500); this.items.push(new HealingPotion(POTION_ID, x, y)); } } }5. 使用示例// 游戏开始时初始化 function initGame(): void { let game = GameManager.getInstance(); // 注册物品使用触发器 let trigger = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trigger, EVENT_PLAYER_UNIT_USE_ITEM); TriggerAddAction(trigger, () => { let unit = GetTriggerUnit(); let item = GetManipulatedItem(); // 处理物品使用 if (item instanceof HealingPotion) { item.use(unit); } }); }关键点总结：类可以封装相关的数据和行为继承允许创建专门化的类私有成员（private）可以保护数据不被外部直接访问公共方法（public）提供了与类交互的接口静态成员可以在不创建实例的情况下使用抽象类和方法可以定义通用行为TypeScript 的对象1. 基本对象的创建和使用// 创建一个英雄属性对象 let heroStats = { strength: 20, agility: 15, intelligence: 18, health: 550, mana: 300, // 对象方法 calculateDamage(): number { return this.strength * 2; }, calculateArmor(): number { return this.agility * 0.2; } }; // 使用对象属性 console.log(heroStats.strength); // 访问属性 console.log(heroStats.calculateDamage()); // 调用方法2. 游戏配置对象// 游戏常量配置对象 const GameConfig = { // 英雄相关 HERO: { START_LEVEL: 1, MAX_LEVEL: 25, BASE_HEALTH: 500, BASE_MANA: 200, HEALTH_PER_LEVEL: 50, MANA_PER_LEVEL: 25 }, // 物品相关 ITEMS: { POTION_HEAL: 150, POTION_MANA: 100, SWORD_DAMAGE: 25, ARMOR_DEFENSE: 5 }, // 游戏机制 MECHANICS: { EXP_PER_LEVEL: 100, GOLD_BOUNTY: 50, RESPAWN_TIME: 30 } }; // 使用配置对象 let heroHealth = GameConfig.HERO.BASE_HEALTH + (level - 1) * GameConfig.HERO.HEALTH_PER_LEVEL;3. 物品系统对象// 物品模板对象 interface ItemTemplate { id: number; name: string; cost: number; icon: string; description: string; effect: (unit: unit) => void; } // 物品数据对象 const ItemData = { // 治疗药水 healingPotion: { id: FourCC('hpot'), name: "治疗药水", cost: 100, icon: "ReplaceableTextures\\CommandButtons\\BTNHealingPotion.blp", description: "恢复150点生命值", effect: (unit: unit) => { SetUnitState(unit, UNIT_STATE_LIFE, GetUnitState(unit, UNIT_STATE_LIFE) + 150); } }, // 魔法药水 manaPotion: { id: FourCC('mpot'), name: "魔法药水", cost: 100, icon: "ReplaceableTextures\\CommandButtons\\BTNManaPotion.blp", description: "恢复100点魔法值", effect: (unit: unit) => { SetUnitState(unit, UNIT_STATE_MANA, GetUnitState(unit, UNIT_STATE_MANA) + 100); } } };4. 技能系统对象// 技能效果对象 const SpellEffects = { // 火球术 fireball: { damage: 200, manaCost: 80, range: 600, cooldown: 8, effect: "Abilities\\Spells\\Other\\Incinerate\\FireLordDeathExplode.mdl", cast: (caster: unit, target: unit) => { let damage = 200 + GetHeroInt(caster, true) * 2; UnitDamageTarget(caster, target, damage, true); // 创建特效 let effect = AddSpecialEffect(SpellEffects.fireball.effect, GetUnitX(target), GetUnitY(target)); DestroyEffect(effect); } }, // 治疗术 heal: { healing: 250, manaCost: 100, range: 500, cooldown: 12, effect: "Abilities\\Spells\\Human\\Heal\\HealTarget.mdl", cast: (caster: unit, target: unit) => { let healing = 250 + GetHeroInt(caster, true) * 1.5; SetUnitState(target, UNIT_STATE_LIFE, GetUnitState(target, UNIT_STATE_LIFE) + healing); // 创建特效 let effect = AddSpecialEffect(SpellEffects.heal.effect, GetUnitX(target), GetUnitY(target)); DestroyEffect(effect); } } };5. 游戏状态对象// 游戏状态管理对象 const GameState = { // 游戏状态数据 data: { isGameStarted: false, currentWave: 0, totalScore: 0, activePlayers: new Set<player>(), heroUnits: new Map<player, unit>() }, // 状态更新方法 startGame(): void { this.data.isGameStarted = true; this.data.currentWave = 1; this.initializePlayers(); }, initializePlayers(): void { for (let i = 0; i < bj_MAX_PLAYERS; i++) { let player = Player(i); if (GetPlayerController(player) == MAP_CONTROL_USER) { this.data.activePlayers.add(player); this.createHeroForPlayer(player); } } }, createHeroForPlayer(player: player): void { let hero = CreateUnit(player, FourCC('Hpal'), 0, 0, 0); this.data.heroUnits.set(player, hero); }, // 获取游戏状态 getGameStatus(): string { return `当前波数: ${this.data.currentWave}\n` + `总分: ${this.data.totalScore}\n` + `活跃玩家: ${this.data.activePlayers.size}`; } };6. 实际使用示例// 初始化游戏系统 function initializeGame(): void { // 使用游戏配置 SetMapFlag(MAP_FOG_ALWAYS_VISIBLE, true); // 创建物品 let potion = CreateItem(ItemData.healingPotion.id, 0, 0); // 注册物品使用事件 let trigger = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trigger, EVENT_PLAYER_UNIT_USE_ITEM); TriggerAddAction(trigger, () => { let unit = GetTriggerUnit(); let item = GetManipulatedItem(); let itemId = GetItemTypeId(item); // 查找并使用物品效果 for (let itemKey in ItemData) { if (ItemData[itemKey].id === itemId) { ItemData[itemKey].effect(unit); break; } } }); // 开始游戏 GameState.startGame(); } // 技能释放示例 function onSpellCast(): void { let caster = GetTriggerUnit(); let target = GetSpellTargetUnit(); let spellId = GetSpellAbilityId(); // 火球术 if (spellId === FourCC('fire')) { SpellEffects.fireball.cast(caster, target); } // 治疗术 else if (spellId === FourCC('heal')) { SpellEffects.heal.cast(caster, target); } }关键点总结：对象可以组织相关的数据和功能对象属性可以存储数据对象方法可以定义行为对象可以用于配置管理对象可以实现模块化设计对象可以方便地共享数据和功能
TypeScript 的运算符算术运算符// 基础运算 let damage: number = 50 + 25; // 加法: 75 let totalGold: number = 1000 - 100; // 减法: 900 let critDamage: number = damage * 2; // 乘法: 100 let splitGold: number = 1000 / 4; // 除法: 250 let remainder: number = 100 % 30; // 取余: 10 // 在游戏中的实际应用 let heroHealth: number = 1000; heroHealth = heroHealth - damage; // 扣血 let expNeeded: number = level * 100; // 计算升级所需经验 let bonusDamage: number = baseDamage * 1.5; // 计算暴击伤害赋值运算符// 基础赋值 let gold: number = 100; // 基本赋值 gold += 50; // 等同于 gold = gold + 50 gold -= 30; // 等同于 gold = gold - 30 gold *= 2; // 等同于 gold = gold * 2 gold /= 4; // 等同于 gold = gold / 4 // 在游戏中的应用 let mana: number = 100; mana -= 40; // 使用技能消耗魔法值 exp += killExp; // 获得经验值 attackSpeed *= 1.3; // 提升攻击速度比较运算符// 基础比较 let isMaxLevel: boolean = (level >= 25); // 大于等于 let canBuyItem: boolean = (gold >= 500); // 大于等于 let isDead: boolean = (health <= 0); // 小于等于 let isHero: boolean = (unitType === 'hero'); // 严格相等 let isNotFull: boolean = (hp !== maxHp); // 不相等 // 在游戏中的应用 if (heroLevel >= 6) { // 英雄达到6级可以学习大招 EnableUltimateSkill(); } if (currentGold < itemCost) { // 金币不足无法购买物品 DisplayError("金币不足"); }逻辑运算符// 与运算 && let canCastUltimate: boolean = (mana >= 100 && skillCooldown <= 0); // 或运算 || let shouldRetreat: boolean = (health <= 100 || isStunned); // 非运算 ! let isNotStunned: boolean = !isStunned; // 在游戏中的实际应用 if (health > 0 && mana >= skillCost && !isStunned) { // 单位存活、有足够魔法值且未被眩晕时可以施放技能 CastSpell(); } if (health <= 0 || isRemoved) { // 单位死亡或被移除时执行 RemoveUnit(); }三元运算符// 基础用法 let message: string = (gold >= itemCost) ? "可以购买" : "金币不足"; // 在游戏中的应用 let damageText: string = isDead ? "致命一击" : damage.toString(); let healAmount: number = isHero ? 100 : 50; // 英雄回复更多生命值位运算符// 在游戏中通常用于标志位 const BUFF_STUN: number = 1 << 0; // 眩晕: 1 const BUFF_SILENCE: number = 1 << 1; // 沉默: 2 const BUFF_DISARM: number = 1 << 2; // 缴械: 4 // 检查状态 let unitState: number = GetUnitState(unit); let isStunned: boolean = (unitState & BUFF_STUN) !== 0;字符串运算符// 字符串连接 let playerName: string = "玩家1"; let levelText: string = "等级"; let displayText: string = playerName + " " + levelText + " " + level; // 在游戏中的应用 let tooltipText: string = itemName + "\n" + // \n 表示换行 "价格: " + cost + " 金币\n" + "说明: " + description;可选链运算符 (?.)// 安全地访问可能为空的对象 let damage: number = hero?.weapon?.damage ?? 0; // 在游戏中的应用 let itemCount: number = inventory?.items?.length ?? 0;空值合并运算符 (??)// 提供默认值 let startingGold: number = configValue ?? 100; // 在游戏中的应用 let respawnTime: number = hero.respawnConfig ?? defaultRespawnTime;实际应用示例：class HeroSystem { calculateDamage(attacker: unit, target: unit): number { // 基础伤害计算 let baseDamage: number = GetUnitDamage(attacker); let armor: number = GetUnitArmor(target); // 暴击判定 let isCritical: boolean = (Math.random() < 0.2); // 20%暴击率 let finalDamage: number = isCritical ? baseDamage * 2 : baseDamage; // 护甲减免 finalDamage *= (1 - (armor * 0.06) / (1 + armor * 0.06)); // 状态检查 if (IsUnitStunned(target) || IsUnitDisarmed(target)) { finalDamage *= 1.5; // 目标被控制时伤害提升 } return Math.max(finalDamage, 1); // 确保最少造成1点伤害 } }这些运算符在魔兽地图开发中经常用于：伤害计算状态判断资源检查等级和经验值计算技能效果判定物品系统逻辑TypeScript 的条件语句if 语句// 基础 if 语句 if (heroLevel >= 6) { // 英雄达到6级可以学习大招 EnableUltimateSkill(); } // if-else 语句 if (playerGold >= itemCost) { BuyItem(); DisplayText("购买成功！"); } else { DisplayText("金币不足！"); } // if-else if-else 语句 if (unitHealth <= 0) { KillUnit(); DisplayText("单位已阵亡"); } else if (unitHealth < 100) { DisplayText("单位生命值危急"); } else { DisplayText("单位状态正常"); }嵌套的 if 语句// 技能释放判断 if (isAlive) { if (mana >= skillCost) { if (!isStunned) { if (!isSilenced) { CastSpell(); } else { DisplayText("单位被沉默"); } } else { DisplayText("单位被眩晕"); } } else { DisplayText("魔法值不足"); } }使用逻辑运算符简化条件// 使用 && 简化多重条件 if (isAlive && mana >= skillCost && !isStunned && !isSilenced) { CastSpell(); } else { DisplayText("无法释放技能"); } // 使用 || 简化多重条件 if (health <= 0 || isRemoved || isDestroyed) { RemoveUnit(); }switch 语句// 根据物品类型执行不同效果 switch (itemType) { case "Potion": RestoreHealth(100); break; case "Scroll": RestoreMana(50); break; case "Weapon": IncreaseAttack(30); break; default: DisplayText("未知物品类型"); break; } // 处理不同的单位类型 switch (GetUnitType(unit)) { case HERO_TYPE: // 英雄单位特殊处理 ApplyHeroBuffs(); break; case CREEP_TYPE: // 野怪单位处理 ApplyCreepAI(); break; case BUILDING_TYPE: // 建筑单位处理 UpdateBuildingState(); break; }条件（三元）运算符// 简单条件判断 let healAmount: number = isHero ? 200 : 100; // 状态文本显示 let statusText: string = isAlive ? "存活" : "死亡"; // 伤害计算 let finalDamage: number = isCritical ? baseDamage * 2 : baseDamage;实际应用示例class ItemSystem { useItem(unit: unit, item: item) { // 检查使用条件 if (!this.canUseItem(unit, item)) { return; } // 获取物品类型 let itemType = GetItemType(item); // 处理不同类型的物品效果 switch (itemType) { case ITEM_TYPE_INSTANT: if (IsHealingItem(item)) { // 治疗物品 let healAmount = IsHero(unit) ? 500 : 200; HealUnit(unit, healAmount); } else if (IsManaItem(item)) { // 魔法物品 RestoreMana(unit, 200); } break; case ITEM_TYPE_EQUIPMENT: if (this.hasEmptySlot(unit)) { EquipItem(unit, item); } else { DisplayText("装备栏已满"); } break; case ITEM_TYPE_CONSUMABLE: if (GetItemCharges(item) > 0) { UseConsumable(unit, item); RemoveCharge(item); } break; } } private canUseItem(unit: unit, item: item): boolean { // 多重条件检查 if (!IsUnitAlive(unit)) { DisplayText("单位已死亡"); return false; } if (IsUnitStunned(unit)) { DisplayText("单位被眩晕"); return false; } let itemLevel = GetItemLevel(item); let unitLevel = GetUnitLevel(unit); if (itemLevel > unitLevel) { DisplayText("等级不足"); return false; } return true; } }最佳实践// 1. 使用提前返回减少嵌套 function processUnit(unit: unit) { if (!unit) return; if (!IsUnitAlive(unit)) return; if (IsUnitStunned(unit)) return; // 处理正常单位逻辑... } // 2. 使用条件对象替代复杂的if-else const damageMultiplier = { 'hero': 1.5, 'creep': 1.0, 'building': 0.5 }; let finalDamage = baseDamage * (damageMultiplier[unitType] || 1.0); // 3. 使用布尔值简化条件 let canCastSpell = isAlive && hasMana && !isStunned && !isSilenced; if (canCastSpell) { CastSpell(); }条件语句的关键点：选择合适的条件语句类型避免过度嵌套使用逻辑运算符简化条件注意条件的顺序和优先级考虑代码的可读性和维护性TypeScript 的循环语句for 循环// 基础for循环 // 创建多个单位 for (let i = 0; i < 5; i++) { let x = -500 + i * 100; // 计算位置 CreateUnit(player, FOOTMAN_ID, x, 0, 0); } // 遍历物品栏 for (let slot = 0; slot < 6; slot++) { let item = UnitItemInSlot(hero, slot); if (item) { // 处理每个物品 CheckItemDuration(item); } }for...of 循环// 遍历数组 let heroes: unit[] = GetPlayerHeroes(); for (let hero of heroes) { // 给所有英雄加buff AddHeroBuff(hero); } // 遍历物品列表 let items: item[] = GetGroundItems(); for (let item of items) { // 检查地上的物品 if (IsItemExpired(item)) { RemoveItem(item); } }for...in 循环// 遍历对象属性 let heroStats = { strength: 20, agility: 15, intelligence: 18 }; for (let stat in heroStats) { // 打印英雄属性 DisplayText(`${stat}: ${heroStats[stat]}`); }while 循环// 基础while循环 let remainingTime = 30; while (remainingTime > 0) { // 倒计时逻辑 DisplayTimer(remainingTime); remainingTime--; Wait(1.0); } // 条件判断的while循环 while (IsUnitAlive(boss)) { // boss战循环 UpdateBossAI(); Wait(0.5); }do...while 循环// 至少执行一次的循环 let attempts = 3; do { let success = TrySpawnUnit(); if (success) break; attempts--; } while (attempts > 0);实际应用示例class WaveSystem { private spawnPoints: point[] = []; private currentWave: number = 0; private maxWaves: number = 10; spawnWave() { // 增加当前波数 this.currentWave++; // 使用for循环在每个刷怪点生成怪物 for (let point of this.spawnPoints) { let count = this.getWaveUnitCount(); // 在每个点生成多个单位 for (let i = 0; i < count; i++) { let unitType = this.getRandomUnitType(); CreateUnit(computer, unitType, GetPointX(point), GetPointY(point), GetRandomReal(0, 360)); } } } checkWaveComplete(): boolean { let remainingUnits = 0; // 使用while循环检查所有单位 let unit = FirstOfGroup(this.waveUnits); while (unit) { if (IsUnitAliveBJ(unit)) { remainingUnits++; } unit = NextOfGroup(this.waveUnits); } return remainingUnits === 0; } async startWaveTimer() { // 使用do-while循环进行波次控制 do { // 显示波次信息 DisplayText(`第 ${this.currentWave + 1} 波即将开始！`); // 倒计时 let countdown = 10; while (countdown > 0) { DisplayText(`${countdown}...`); await Wait(1.0); countdown--; } // 生成这一波 this.spawnWave(); // 等待这一波结束 while (!this.checkWaveComplete()) { await Wait(1.0); } } while (this.currentWave < this.maxWaves); } }循环控制语句// break 语句 for (let i = 0; i < items.length; i++) { if (items[i].type === "legendary") { DisplayText("发现传说物品！"); break; // 找到后立即退出循环 } } // continue 语句 for (let unit of allUnits) { if (!IsUnitAlive(unit)) { continue; // 跳过死亡单位 } // 处理活着的单位 ProcessUnit(unit); }嵌套循环class MapSystem { createGrid(width: number, height: number) { // 创建地形网格 for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { // 在每个格子执行操作 this.processGridCell(x, y); } } } findPath(start: point, end: point) { // 寻路算法中的嵌套循环 let openList: point[] = [start]; while (openList.length > 0) { let current = openList[0]; // 检查周围8个方向 for (let dx = -1; dx <= 1; dx++) { for (let dy = -1; dy <= 1; dy++) { if (dx === 0 && dy === 0) continue; // 处理每个相邻点 this.checkNeighbor(current, dx, dy); } } } } }循环使用的关键点：选择合适的循环类型注意循环条件和终止条件避免无限循环合理使用循环控制语句考虑性能影响，特别是在嵌套循环中
使用 let 声明变量// 基础变量声明 let playerName: string = "玩家1"; // 声明字符串变量 let goldCount: number = 100; // 声明数字变量 let isHeroAlive: boolean = true; // 声明布尔变量 // 魔兽相关变量声明 let myHero: unit; // 声明单位变量 let currentPlayer: player; // 声明玩家变量 let weapon: item; // 声明物品变量 // 不指定初始值的变量声明 let damage: number; // 稍后会赋值的伤害值 let targetUnit: unit; // 稍后会赋值的目标单位使用 const 声明常量// 基础常量声明 const MAX_LEVEL: number = 25; // 最大等级 const GAME_VERSION: string = "1.0.0"; // 游戏版本号 // 魔兽相关常量声明 const HERO_INIT_X: number = 0; // 英雄初始X坐标 const HERO_INIT_Y: number = 0; // 英雄初始Y坐标 // 从项目中实际的例子: const ORIGIN_FRAME_GAME_UI: number; // 游戏UI框架常量 const FRAMEEVENT_CONTROL_CLICK: number; // 框架点击事件常量数组变量声明// 简单数组 let heroList: unit[] = []; // 英雄单位数组 let itemArray: item[] = []; // 物品数组 let damageValues: number[] = [100, 200, 300]; // 伤害值数组 // 从项目中的实际例子: let idAndNum: string[]; // 用于存储ID和数量的数组对象变量声明// 从项目中的对象类型声明 let unitConfig: uobj = { Art: "units/human/footman/footman.mdl", Name: "步兵", HP: "100", spd: "270", armor: "2" }; let itemConfig: iobj = { Art: "ReplaceableTextures/CommandButtons/BTNSteelMelee", Name: "铁剑", goldcost: "500", Description: "基础武器" };类型推断的变量声明// TypeScript 可以自动推断类型 let gold = 100; // 自动推断为 number let name = "圣骑士"; // 自动推断为 string let alive = true; // 自动推断为 boolean复杂类型的变量声明// 函数类型变量 let damageCallback: (source: unit, target: unit) => number; // 对象类型变量 let playerData: { name: string; hero: unit; level: number; items: item[]; }; // 从项目中的实际例子: let frameEventCallback: () => void; // UI框架事件回调特殊变量声明// 可选属性 let heroStats: { strength: number; agility: number; intelligence: number; armor?: number; // 可选的护甲属性 }; // 联合类型 let resourceType: "gold" | "lumber"; // 只能是这两个字符串之一 let value: number | string; // 可以是数字或字符串全局变量声明// 在类型定义文件中声明全局变量 declare let isDebug: boolean; // 全局调试标志 declare let tempGroup: group; // 全局临时单位组使用变量的一些最佳实践:选择合适的声明方式// 对于不会改变的值使用 const const MAX_PLAYERS: number = 12; // 对于会改变的值使用 let let currentGold: number = 0;明确的类型声明// 虽然可以类型推断，但在重要变量上最好明确声明类型 let mainHero: unit; let playerGold: number = 0;有意义的变量名// 好的命名 let heroAttackDamage: number = 50; let isPlayerAlive: boolean = true; // 避免这样的命名 let x: number = 50; let flag: boolean = true;这些是在魔兽地图开发中最常用的变量声明方式。let 和 const 的主要区别：可变性区别// let 声明的变量可以重新赋值 let heroGold: number = 100; heroGold = 200; // ✅ 正确，可以修改 heroGold = heroGold + 50; // ✅ 正确，可以修改 // const 声明的常量不能重新赋值 const MAX_GOLD: number = 1000000; MAX_GOLD = 2000000; // ❌ 错误！常量不能重新赋值 MAX_GOLD = MAX_GOLD + 100; // ❌ 错误！常量不能重新赋值初始化要求// let 可以先声明后赋值 let playerHero: unit; playerHero = CreateUnit(...); // ✅ 正确，可以后续赋值 // const 必须在声明时就初始化 const playerHero: unit; // ❌ 错误！const声明必须初始化 const MAX_LEVEL: number = 25; // ✅ 正确，声明时就赋值对象属性的修改// 使用 let 声明的对象 let hero = { name: "圣骑士", level: 1, gold: 100 }; hero.level = 2; // ✅ 正确，可以修改对象的属性 hero = { // ✅ 正确，可以重新赋值整个对象 name: "法师", level: 1, gold: 100 }; // 使用 const 声明的对象 const HERO_INIT = { name: "圣骑士", level: 1, gold: 100 }; HERO_INIT.level = 2; // ✅ 正确，可以修改对象的属性 HERO_INIT = { // ❌ 错误！不能重新赋值整个对象 name: "法师", level: 1, gold: 100 };使用场景// let 适用于需要改变的值 let currentGold: number = 0; // 玩家当前金币 let heroLevel: number = 1; // 英雄当前等级 let isAlive: boolean = true; // 单位存活状态 // const 适用于固定不变的值 const GOLD_BOUNTY: number = 50; // 击杀奖励金币 const HERO_INIT_X: number = -500; // 英雄出生点X坐标 const GAME_VERSION: string = "1.0"; // 游戏版本号在循环中的使用// let 可以在循环中使用 for(let i = 0; i < 5; i++) { let unit = CreateUnit(...); } // const 不适合在循环中作为计数器 for(const i = 0; i < 5; i++) { // ❌ 错误！i不能递增 const unit = CreateUnit(...); }最佳实践建议// 1. 优先使用 const const TRIGGER_REGION = CreateRegion(); // 固定的触发区域 const MAX_INVENTORY = 6; // 物品栏大小上限 // 2. 需要修改时才使用 let let playerGold = 0; // 会变化的玩家金币 let heroLevel = 1; // 会升级的英雄等级 // 3. 对于配置类数据使用 const const GAME_CONFIG = { startingGold: 100, maxLevel: 25, respawnTime: 60 };总结：let 用于声明可能会改变的变量const 用于声明不会改变的常量const 声明的对象虽然不能重新赋值，但其属性可以修改建议优先使用 const，只有在需要修改变量值的时候才使用 let这样的区分可以：提高代码的可读性防止意外修改重要数值帮助其他开发者理解代码意图有利于代码维护和调试
2022年太阳编辑器_v4.81学思笔记6：太阳自定义值、太阳中心事件
一、前言今天主要学习太阳编辑器TS框架架构。solar //太阳TS框架 都包括在此目录下atrribute //属性系统（阅读优先级5）common //游戏基础 ，如：全局变量、玩家基础属性、多面板、胜利失败等（阅读优先级2，重点DataBase.ts）constant //常量（阅读优先级1，重点）lib //第三方库tool //类对象型 工具（阅读优先级3，重点）types //类型声明util //类静态方法型 工具（阅读优先级4，重点）w3ts //基础框架 里面封装了各个handle类型的对象形式（阅读优先级6）二、太阳自定义值YDWE的逆天自定义值，让我们能以一种简单直观的方式给单位、物品等任何类型的物体数据设置自定义值，自定义值可以理解为给它贴上了某种类型的标签。 我们都知道逆天局部变量只在当前触发生效，且不用销毁，那么逆天自定义值就是方便我们在其他触发器中调用。 实例1：初始化时设置太阳自定义值，然后在其他触发里打印它。1、在太阳编辑器的入口文件App.ts的constructor里写上一段太阳自定义值DataBase.getUnitTypeSolarData('Hamg').名字 = '狗蛋'; db.getItemTypeSolarData('rat3 ').攻击力 = 10000;2、新建Zi_Dy.ts文件，写上： import DataBase from "solar/common/DataBase"; import PlayerUtil from "solar/util/game/PlayerUtil"; import { Trigger } from "solar/w3ts/handles/trigger"; export default class Zi_Dy { constructor() { let trigger = new Trigger() trigger.registerTimerEvent(1, false) trigger.addAction(this.action) } action(this: void) { PlayerUtil.text(Player(0), DataBase.getUnitTypeSolarData('Hamg').名字, 5, 0, 0) PlayerUtil.text(Player(0), db.getItemTypeSolarData('rat3 ').攻击力, 20, 0, 0) } }3、运行效果： **知识点： 1、getUnitTypeSolarData是设置单位类型的自定义值，getItemTypeSolarData是设置物品类型的自定义值，其他类型的可以访问太阳编辑器框架"solar/common/DataBase"查看。 2、db是DataBase的缩写。 3、PlayerUtil.text = DisplayTextToPlayer，它是来自太阳编辑器框架的玩家工具，路径："solar/util/game/PlayerUtil"。**三、太阳中心事件逆天触发器可以在同一个触发的触发动作中新建逆天触发器，逆天触发器可以设置参数，参数属于局部变量，可以避免变量冲突。有人形象的说：逆天触发器，其实就是让不会JASS的T使用者用T来写JASS。 实例：Zi_Dy.ts文件的触发动作里用太阳中心事件，实现单位死亡事件——山丘Kill大法师，提示死亡单位名字。SetHeroStr(gg\_unit\_Hmkg\_0000, 1000, true) se.unitDeath((du, ku) => { if (du == gg\_unit\_Hamg\_0004 && ku == gg\_unit\_Hmkg\_0000){ PlayerUtil.text(Player(0), '死亡单位:' + GetUnitName(du), 20, 0, 0) return true; } return false; })**知识点： 1、SetHeroStr是设置英雄的力量属性。了解更多可以访问太阳编辑器框架：“\solar\atrribute\BigAttributeCompatibleState.ts” 2、se是指太阳中心事件，了解更多可以访问太阳编辑器框架：“solar\common\SolarEvent.ts”** 太阳中心事件关键词玩家输入聊天信息playerChat任意单位伤害事件unitDamaged单位进入区域enterRect任意单位事件 - 获得物品unitPickupItem任意单位事件 - 获得物品onUnitPickupItem任意单位事件 - 丢弃物品unitDropItem任意单位事件 - 丢弃物品onUnitDropItem任意单位事件 - 使用物品unitUseItem任意单位事件 - 使用物品onUnitUseItem玩家单位事件 - 完成建造unitConstructFinish玩家单位事件 - 完成建筑升级unitUpgradeFinish任意玩家单位事件 - 选择单位unitSelected任意玩家单位事件 - 选择单位onUnitSelected任意单位事件 - 开始施放技能unitSpellCast任意单位事件 - 开始施放技能onUnitSpellCast任意单位事件 - 发动技能效果unitSpellEffect任意单位事件 - 发动技能效果onUnitSpellEffect任意单位事件 - 死亡unitDeath任意单位事件 - 死亡onUnitDeath任意单位事件 - 被攻击unitAttacked任意单位事件 - 被攻击onUnitAttacked任意单位事件anyUnitEvent任意单位释放技能总事件anyUnitSpellEvent
2022年太阳编辑器_v4.81学思笔记5：单位组、计时器
一、单位组实例1：事件：玩家输入dwz 动作： 创建1个牧师添加进单位组danweizu 创建1个女巫添加进单位组danweizu 创建1个魔法破坏者添加进单位组danweizu 选取单位组的所有单位做动作：移动到地图区域的随机点（一）被弃用的ForGroup/ForGroupBJ老规矩，先上JASS转TS的写法：import BianLiang from 'BianLiang'; export default class Dan_Weizu { constructor() { let t = CreateTrigger(); TriggerRegisterPlayerChatEvent(t, Player(0), "dwz", true); TriggerAddAction(t, Dan_Weizu.action); } static action(this: void) { let g: group; let u: unit; GroupAddUnitSimple(CreateUnitAtLoc(Player(0), FourCC('hmpr'), GetRectCenter(GetPlayableMapRect()), 0), BianLiang.danweizu); GroupAddUnitSimple(CreateUnitAtLoc(Player(0), FourCC('hsor'), GetRectCenter(GetPlayableMapRect()), 0), BianLiang.danweizu); GroupAddUnitSimple(CreateUnitAtLoc(Player(0), FourCC('hspt'), GetRectCenter(GetPlayableMapRect()), 0), BianLiang.danweizu); ForGroupBJ(BianLiang.danweizu, Dan_Weizu.action1); GroupClear(BianLiang.danweizu); g = null; u = null; } static action1(this: void): void { IssuePointOrderLoc(GetEnumUnit(), "move", GetRandomLocInRect(GetPlayableMapRect())); } }[success]知识点：1、我们在BianLiang.ts里定义了danweizu，所以直接import BianLiang from 'BianLiang';后引用它。2、在太阳编辑器中ForGroup和ForGroupBJ已经被弃用了！作者推荐我们使用GroupUnit.for3、运行上面的代码并不会执行单位组内的单位移动到地图随机点的动作，原因：《太阳编辑器学思笔记2：全局变量》最后我们提到，单位组类型的变量声明后要初始化，即新建空的单位组。否则无法将单位添加进一个不存在的、具体的单位组中。[/success]（二）GroupUnit.for太阳编辑器目前推荐的单位组语法表达，实例如下：import GroupUtil from 'solar/util/unit/GroupUtil'; import { MapPlayer } from 'solar/w3ts/handles/player'; import { Trigger } from 'solar/w3ts/handles/trigger'; export default class Dan_Weizu { constructor() { let t = new Trigger(); t.registerPlayerChatEvent(MapPlayer.fromIndex(0), 'dwz', true) t.addAction(this.action); } action(this: void) { let g = CreateGroup(); GroupAddUnitSimple(CreateUnitAtLoc(Player(0), FourCC('hmpr'), GetRectCenter(GetPlayableMapRect()), 0), g); GroupAddUnitSimple(CreateUnitAtLoc(Player(0), FourCC('hsor'), GetRectCenter(GetPlayableMapRect()), 0), g); GroupAddUnitSimple(CreateUnitAtLoc(Player(0), FourCC('hspt'), GetRectCenter(GetPlayableMapRect()), 0), g); GroupUtil.for(g, (u) = { IssuePointOrderLoc(u, "move", GetRandomLocInRect(GetPlayableMapRect())); }) } }[success]知识点：1、用let局部声明单位组变量g后直接初始化，弃用全局变量的单位组BianLiang.danweizu；2、单位变量u在 GroupUtil.for中作为参数直接声明，不需要赋值是因为已在import的GroupUtil模块中完成。3、不需要自己清空单位组，同样也是因为遍历完清空单位组的动作在import的GroupUtil模块中完成。综上大大简化了代码！[/success]二、计时器（一）注册计时器事件：registerTimerEvent实例2： 事件：游戏计时（单次）——当时间逝去1秒 动作：给红色玩家创建1个血魔法师在地图中心点import { Trigger } from "solar/w3ts/handles/trigger"; export default class Ji_Shiqi { constructor() { let trigger = new Trigger() trigger.registerTimerEvent(1, false) trigger.addAction(this.action) } action(this: void) { CreateUnitAtLoc(Player(0), FourCC('Hblm'), GetRectCenter(GetPlayableMapRect()), 0) } }实例3： 事件：游戏计时（循环）——每当时间逝去1秒 动作：给红色玩家创建1个血魔法师在地图中心点import { Trigger } from "solar/w3ts/handles/trigger"; export default class Ji_Shiqi { constructor() { let trigger = new Trigger() trigger.registerTimerEvent(1, true) trigger.addAction(this.action) } action(this: void) { CreateUnitAtLoc(Player(0), FourCC('Hblm'), GetRectCenter(GetPlayableMapRect()), 0) } }[warning]学习笔记： 1、单次计时器还是循环计时器，对于注册计时器事件registerTimerEvent来说，就是：false和true的差别。 2、如果我们需要控制实例中单位创建的次数，还需要设置一个整数变量作为条件。[/warning]（二）太阳中心计时器：BaseUtil.onTimerBaseUtil.onTimer(参数1,参数2)指计时器延迟x秒后执行动作。参数1是整数，表示x秒；参数2是布尔值，返回true 代表继续执行，返回false 代表不再执行。实例4：间隔1秒创建1个单位就停止创建 事件：红色玩家输入jsq 动作： 运行（新建计时器），周期1秒，模式：1次 给红色玩家创建1个血魔法师在地图中心点 export default class Ji_Shiqi { constructor() { let trigger = new Trigger() trigger.registerPlayerChatEvent(MapPlayer.fromIndex(0), 'jsq', true) trigger.addAction(this.action) } action(this: void) { BaseUtil.onTimer(1, () = { CreateUnitAtLoc(Player(0), FourCC('Hblm'), GetRectCenter(GetPlayableMapRect()), 0) return false; }) } }[info]笔记：参数2处不带参数，执行完创建动作后，直接返回false就可以不再执行。[/info]实例5：每间隔1秒创建1个单位，创建10个后停止创建。 事件：红色玩家输入jsq1 动作： 运行（新建计时器），周期1秒，模式：10次 给红色玩家创建1个血魔法师在地图中心点 export default class Ji_Shiqi { constructor() { let trigger = new Trigger() trigger.registerPlayerChatEvent(MapPlayer.fromIndex(0), 'jsq1', true) trigger.addAction(this.action) } action(this: void) { BaseUtil.onTimer(1, (n) = { CreateUnitAtLoc(Player(0), FourCC('Hblm'), GetRectCenter(GetPlayableMapRect()), 0) if (n <= 9) { return true; } return false; }) } }[info]笔记：参数2处设置参数n，执行完创建动作后，判断条件真假，返回true 代表继续执行，返回false 代表不再执行。这里需要特别注意n默认是整数0。[/info]（三）太阳中心计时器：BaseUtil.runLaterBaseUtil.runLater(参数1,参数2,参数3)指计时器间隔x秒后执行动作y，执行z次。参数1是整数，表示x秒；参数2是空值；参数3是循环次数。实例6：每间隔1秒创建1个单位，执行5次。 事件：红色玩家输入jsq2 动作： 运行（新建计时器），周期1秒 给红色玩家创建1个血魔法师在地图中心点 执行5次export default class Ji_Shiqi { constructor() { let trigger = new Trigger() trigger.registerPlayerChatEvent(MapPlayer.fromIndex(0), 'jsq2', true) trigger.addAction(this.action) } action(this: void) { BaseUtil.runLater(1, () = { CreateUnitAtLoc(Player(0), FourCC('Hblm'), GetRectCenter(GetPlayableMapRect()), 0) }, 5) } }总结1、对比我们不难发现，BaseUtil.runLater使用起来更简洁。2、无论是BaseUtil.onTimer还是BaseUtil.runLater，两者都是基于太阳计时器STimer模块。三、演示地图下载(已过期)
一、条件实例：事件：玩家输入任意数字 动作：如果大于100，则显示“V我50！”，如果不足100，则显示“金钱不足！”。（一）if语句JASS转TS语法表达如下：export default class Gold { constructor() { let t = CreateTrigger(); TriggerRegisterPlayerChatEvent(t, Player(0), "", true); TriggerAddAction(t, Gold.action); } static action(this: void) { if ((S2I(GetEventPlayerChatString()) = 100)) DisplayTextToPlayer(Player(0), 0, 0, "V我50疯狂星期四！"); if ((S2I(GetEventPlayerChatString()) < 100)) DisplayTextToPlayer(Player(0), 0, 0, "金钱不足！"); } }太阳编辑器框架语法表达：import { MapPlayer } from "solar/w3ts/handles/player" import { Trigger } from "solar/w3ts/handles/trigger" export default class Gold { constructor() { let t = new Trigger() t.registerPlayerChatEvent(MapPlayer.fromIndex(0), '', false) t.addAction(this.action) } action(this: void) { if (S2I(GetEventPlayerChatString()) = 100) DisplayTextToPlayer(Player(0), 0, 0, 'V我50疯狂星期四！') if (S2I(GetEventPlayerChatString()) < 100) DisplayTextToPlayer(Player(0), 0, 0, '金钱不足！') } }[info]知识点：使用太阳编辑器的registerPlayerChatEvent的第一个参数是MapPlayer类型，而这个类型需要从"solar/w3ts/handles/player"中导入。我们Ctrl+鼠标左键这个相对地址，查看player.ts文件会发现MapPlayer是Handle<player的子类。进一步查找会发现类似JASS转TS的Player(0)对应的是fromIndex。由于我们刚开始用太阳编辑器，代码还不太熟悉，相信将来能熟能生巧！[/info]（二）if……else语句import { MapPlayer } from "solar/w3ts/handles/player" import { Trigger } from "solar/w3ts/handles/trigger" export default class Gold { constructor() { let t = new Trigger() t.registerPlayerChatEvent(MapPlayer.fromIndex(0), '', false) t.addAction(this.action) } action(this: void) { if (S2I(GetEventPlayerChatString()) = 100) DisplayTextToPlayer(Player(0), 0, 0, 'V我50疯狂星期四！') else DisplayTextToPlayer(Player(0), 0, 0, '金钱不足！') } }二、循环实例：事件：玩家输入数字xh 动作：循环12次创建1个步兵单位。（一）for循环老规矩，我们先来看看JASS转TS语法表达如下：export default class Gold { constructor() { let t = CreateTrigger(); TriggerRegisterPlayerChatEvent(t, Player(0), "xh", true); TriggerAddAction(t, Gold.action); } static action(this: void) { bj_forLoopAIndex = 1; bj_forLoopAIndexEnd = 12; while (true) { if (bj_forLoopAIndex bj_forLoopAIndexEnd) break; CreateNUnitsAtLoc(1, FourCC('hfoo'), Player(0), GetRectCenter(GetPlayableMapRect()), bj_UNIT_FACING); bj_forLoopAIndex = bj_forLoopAIndex + 1; } } }太阳编辑器框架语法表达：import { MapPlayer } from "solar/w3ts/handles/player" import { Trigger } from "solar/w3ts/handles/trigger" export default class Gold { constructor() { let t = new Trigger() t.registerPlayerChatEvent(MapPlayer.fromIndex(0), 'xh', false) t.addAction(this.action) } action(this: void) { for (let i = 1; i < 13; i++) { CreateNUnitsAtLoc(1, FourCC('hfoo'), Player(0), GetRectCenter(GetPlayableMapRect()), 270); } } }[info]知识点：从上面我们可以再一次感受到TypeScript 语言的简洁，2行代码实现了JASS语言6行代码的效果。温习TypeScript 循环语法可以访问菜鸟教程：TypeScript 循环 | 菜鸟教程 (runoob.com)[/info]（二）while循环while循环和for循环最大的不同就是条件语句的写法。当条件为 false 时，会跳过循环主体，直接执行紧接着 while 循环的下一条语句。import { MapPlayer } from "solar/w3ts/handles/player" import { Trigger } from "solar/w3ts/handles/trigger" export default class Gold { constructor() { let t = new Trigger() t.registerPlayerChatEvent(MapPlayer.fromIndex(0), 'xh', false) t.addAction(this.action) } action(this: void) { let i = 1; while (i < 13) { CreateNUnitsAtLoc(1, FourCC('hfoo'), Player(0), GetRectCenter(GetPlayableMapRect()), 270); i++; } } }三、演示地图下载(已过期)
一、数组这玩意其实没什么讲的，因为在大部分编程语言里意义是一样的：使用单独的变量名来存储一系列的值。 1、我们接着之前的演示图，在BianLiang.ts里自定义一个字符串数组。保存BianLiang.ts。static mingzi:string[] = [];2、我们在Move.ts里添加一些触发动作。保存Move.ts。BianLiang.mingzi[0]='张三'; BianLiang.mingzi[1]='李四'; BianLiang.mingzi[2]='王麻子'; DisplayTextToPlayer(Player(0), 0, 0,BianLiang.mingzi[0]); DisplayTextToPlayer(Player(0), 0, 0,BianLiang.mingzi[1]); DisplayTextToPlayer(Player(0), 0, 0,BianLiang.mingzi[2]);3、运行查看效果。[danger]注意事项：数组变量在获取属性前要加上对空值判断！[/danger]二、触发（一）太阳编辑器的触发语法其实我们在《太阳编辑器学思笔记2：全局变量》三、太阳编辑器调用war3map.d.ts中的全局变量中已经学习过一次。我们再温习一次。export default class 类名 { constructor() { let trigger = new Trigger() trigger.registerTimerEvent(1, false) trigger.addAction(this.action) } action(this: void) { } }export default class 类名 //创建1个名为Move的类并导出constructor() { } //构造函数【为什么使用构造函数的扩展阅读可以访问《太阳编辑器学思笔记1：TypeScript编程语言》】let trigger = new Trigger()//新建触发trigger.registerTimerEvent(1, false) //触发事件.注册计时器事件(秒,是否循环)，registerTimerEvent是TS的表达方式，相当于JASS的TriggerRegisterTimerEvent。 //【扩展阅读可以访问左侧树形栏的solar/w3ts/handles/trigger】trigger.addAction(this.action) //添加触发器动作，addAction是TS的表达方式，相当于JASS的TriggerAddActionaction(this: void) { } //执行触发动作。所以触发动作是写这里面。（二）太阳编辑器的触发事件上面我们解释了trigger.registerTimerEvent是注册计时器事件，那么其他触发事件怎么写呢？ 答：查看太阳编辑器的触发框架：位于solar/w3ts/handles/trigger 如果你是用VScode打开的实例Move2.ts，那么右键点击文件内容上方的导入模块代码“import {Trigger} from "solar/w3ts/handles/trigger";”，选择“转到定义”，可以快速跳转到trigger.ts 下面我们来用个实例说明下： [info]实例目标：新建一个Move3.ts并改写其中的触发模块，触发事件：单位进入区域[R]，触发条件：判断触发单位是否为蒸汽车，触发动作：摧毁神秘宝藏室[/info] 有了前两章的学习，我们省略如何新建Move3.ts，如何在App.ts里调用Move3.ts，直接上触发代码：import { Trigger } from "solar/w3ts/handles/trigger"; export default class Move3 { constructor() { let t = new Trigger() t.registerEnterRect(gg_rct_jihe) t.addCondition(Condition(this.condition)) t.addAction(this.action) } condition(this: void) { return (IsUnit(GetTriggerUnit(), gg_unit_hmtt_0002) == true) } action(this: void) { KillUnit(gg_unit_hvlt_0001); DisplayTextToPlayer(Player(0), 0, 0, '神秘宝藏室被摧毁1') } }上面是太阳编辑器的写法，导入了一个trigger的框架，从而语法更加的简洁。下面是JASS转TS的写法。export default class Move3 { constructor() { let t = CreateTrigger(); TriggerRegisterEnterRectSimple(t, gg_rct_jihe) TriggerAddCondition(t, Condition(Move3.Conditions)); TriggerAddAction(t, Move3.action); } static Conditions(this: void): boolean { return (IsUnit(GetTriggerUnit(), gg_unit_hmtt_0002) == true); } static action(this: void) { KillUnit(gg_unit_hvlt_0001); DisplayTextToPlayer(Player(0), 0, 0, '神秘宝藏室被摧毁') } }（二）太阳编辑器的触发条件结合上面的案例，这里展示下触发条件更为简洁的箭头函数写法。太阳编辑器写法：t.addCondition(Condition(() = { return(IsUnit(GetTriggerUnit(), gg_unit_hmtt_0002) == true) })) JASS转TS写法： TriggerAddCondition(t, Condition(() = { return(IsUnit(GetTriggerUnit(), gg_unit_hmtt_0002) == true) })) （三）太阳编辑器的触发动作如果触发动作要写成箭头函数，则如下：t.addAction(() => { KillUnit(gg_unit_hvlt_0001); DisplayTextToPlayer(Player(0), 0, 0, '神秘宝藏室被摧毁2.5') })四、演示地图下载（已过期）