查看: 888|回复: 0
打印 上一主题 下一主题

[其他] C# 模拟魔兽争霸触发器 Trigger

[复制链接]
may    

8830

主题

81

听众

7万

积分

首席设计师

Rank: 8Rank: 8

纳金币
52336
精华
343

最佳新人 热心会员 灌水之王 活跃会员 突出贡献 荣誉管理 论坛元老

跳转到指定楼层
楼主
发表于 2018-8-23 20:40:12 |只看该作者 |倒序浏览

用过魔兽争霸编辑器的同学都知道 用 T 可以对魔兽争霸游戏进行触发事件
至于 Jass 就是纯代码了 这里不深究
例如 :
事件 : 单位被攻击
条件 : 被攻击者 的所有者 是 玩家 1
动作 : 攻击者的生命值 -10

这种思想我一直觉得在全局上的把控比较好 只需在另一个地方编辑事件 而不用在现有设计好的代码中添加或更改

这种触发器不用说 一定和事件有关 而且满地都是事件

所以为了运用这个思想 转换成了 c# 代码 简单的模拟

设计上吗 主体就是事件系统 在每个单位上绑定事件 每个单位都会发送事件到事件管理处 在事件管理处进行全局控制

其中 为了简化代码 在初始化中用了反射

话不多说 代码放上 模拟刚才的例子:
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. using System.Threading.Tasks;

  7. namespace TriggerTest
  8. {

  9.     class Program
  10.     {
  11.         static void Main(string[] args)
  12.         {

  13.             List<Trigger> triggerList = new List<Trigger>();

  14.             //模拟一个触发:主角被攻击的时候 如果主角生命值在 200 以下  那么对攻击者进行伤害 数值为真实伤害 10
  15.             EventStart eventS = new EventStart(0, EventStartType.Unit_BeHurt);
  16.             EventCondition eventC = new EventCondition(0, EventConditionType.Unit_Health, () =>
  17.             {
  18.                 Player p = eventS.eventSender as Player;
  19.                 return p.name == "player" && p.health < 200;

  20.             });
  21.             EventOperation eventO = new EventOperation(0, EventOperationType.Unit_DamageUnits, () =>
  22.             {
  23.                 (eventS.eventRelationer as Player).health -= 10;
  24.             });


  25.             TriggerManager.Instance.AddTrigger(new Trigger(eventS, eventC, eventO));

  26.             //designer
  27.             Player player = new Player("player", 11, 100);
  28.             Player enemy = new Player("enemy", 20, 100);


  29.             TriggerManager.Instance.BindEvent(player);

  30.             enemy.AttackTarget(player);

  31.             Console.WriteLine($"{enemy.health}");
  32.         }
  33.     }

  34.     public class Player
  35.     {
  36.         public event Action<object, object> Unit_BeHurt;
  37.         public string name;

  38.         public float attack;
  39.         public float health;

  40.         public Player(string name, float attack, float health)
  41.         {
  42.             this.name = name;

  43.             this.attack = attack;
  44.             this.health = health;
  45.         }

  46.         public void BeHurt(int damage, object attacker)
  47.         {
  48.             Unit_BeHurt?.Invoke(this, attacker);
  49.             this.health -= damage;

  50.         }
  51.         public void AttackTarget(Player emp)
  52.         {
  53.             emp.BeHurt((int)this.attack, this);
  54.         }

  55.     }

  56.     public class Trigger
  57.     {
  58.         public EventStart start;
  59.         public EventCondition condition;
  60.         public EventOperation operation;

  61.         public Trigger(EventStart start, EventCondition condition, EventOperation operation)
  62.         {
  63.             this.start = start;
  64.             this.condition = condition;
  65.             this.operation = operation;
  66.             start.trigger = this;
  67.             condition.trigger = this;
  68.             operation.trigger = this;

  69.         }
  70.     }


  71.     public enum EventStartType
  72.     {
  73.         Time_TimeOver,
  74.         Unit_BeHurt,

  75.     }

  76.     public enum EventConditionType
  77.     {
  78.         Unit_Health,

  79.     }

  80.     public enum EventOperationType
  81.     {
  82.         Unit_DamageUnits,
  83.         Unit_ChangeHealth,
  84.     }

  85.     public class EventStart
  86.     {
  87.         public Trigger trigger;
  88.         public int id;
  89.         public EventStartType type;
  90.         public object eventSender;//事件发起者
  91.         public object eventRelationer;//事件关系者

  92.         public EventStart(int id, EventStartType type)
  93.         {
  94.             this.id = id;
  95.             this.type = type;
  96.         }

  97.     }
  98.     public class EventCondition
  99.     {
  100.         public Trigger trigger;
  101.         public int id;
  102.         public EventConditionType type;
  103.         public Func<bool> conditionFunc;


  104.         public EventCondition(int id, EventConditionType type, Func<bool> func)
  105.         {
  106.             this.id = id;
  107.             this.type = type;
  108.             conditionFunc = func;
  109.         }

  110.         public bool IsTrue()
  111.         {
  112.             return conditionFunc == null ? false : conditionFunc();
  113.         }


  114.     }


  115.     public class EventOperation
  116.     {
  117.         public Trigger trigger;
  118.         public int id;
  119.         public EventOperationType type;



  120.         public Action action;
  121.         public EventOperation(int id, EventOperationType type, Action action)
  122.         {
  123.             this.id = id;
  124.             this.type = type;
  125.             this.action = action;
  126.         }


  127.         public object[] Run()
  128.         {
  129.             action?.Invoke() ;

  130.             return null;
  131.         }

  132.     }



  133.     public class TriggerManager
  134.     {

  135.         private static TriggerManager instance;
  136.         public Dictionary<EventStartType, List<Trigger>> dic = new Dictionary<EventStartType, List<Trigger>>();

  137.         public static TriggerManager Instance
  138.         {
  139.             get
  140.             {
  141.                 if (instance == null)
  142.                 {
  143.                     instance = new TriggerManager();
  144.                 }

  145.                 return instance;
  146.             }
  147.             set => instance = value;
  148.         }

  149.         private TriggerManager()
  150.         {
  151.             dic.Add(EventStartType.Time_TimeOver, new List<Trigger>());
  152.             dic.Add(EventStartType.Unit_BeHurt, new List<Trigger>());
  153.         }


  154.         public void AddTrigger(Trigger t)
  155.         {
  156.             dic[t.start.type].Add(t);

  157.         }

  158.         //监听 单位事件  只要是 Player 类 都可以绑定 (这里可以用反射 可以将所有类都可以用这个绑定函数 前提是保证这个类中有该事件)
  159.         public void BindEvent(Player player)
  160.         {
  161.             var events = player.GetType().GetEvents();

  162.             foreach (var child in events)
  163.             {

  164.                 child.AddEventHandler(player, new Action<object, object>((sender, relations) =>
  165.                 {
  166.                     var eventStartType = (EventStartType)Enum.Parse(typeof(EventStartType), child.Name);
  167.                     SendEvent(eventStartType, sender, relations);
  168.                 }));

  169.             }

  170.         }


  171.         public void SendEvent(EventStartType eventType, object sender, object relations)
  172.         {
  173.             List<Trigger> list = dic[eventType];
  174.             list.ForEach(e =>
  175.             {
  176.                 e.start.eventSender = sender;
  177.                 e.start.eventRelationer = relations;
  178.                 if (e.condition.IsTrue())
  179.                 {
  180.                     e.operation.Run();
  181.                 }
  182.             });
  183.         }

  184.     }
  185.    

  186. }
复制代码
在枚举中增加事件类型 在单位中事件也要创建 名称要一样
这样 几行代码就可以创建一个触发器
之后的时间里 可能会写一个运用这个模拟 简单AI战斗 的脚本 AI处只需写逻辑和事件 其他的都交由触发器来完成 先立个 flag 。。。


來自: 随幻Kaller
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-23 10:06 , Processed in 0.102698 second(s), 29 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部