纳金网
标题:
C# 模拟魔兽争霸触发器 Trigger
[打印本页]
作者:
may
时间:
2018-8-23 20:40
标题:
C# 模拟魔兽争霸触发器 Trigger
用过魔兽争霸编辑器的同学都知道 用 T 可以对魔兽争霸游戏进行触发事件
至于 Jass 就是纯代码了 这里不深究
例如 :
事件 : 单位被攻击
条件 : 被攻击者 的所有者 是 玩家 1
动作 : 攻击者的生命值 -10
这种思想我一直觉得在全局上的把控比较好 只需在另一个地方编辑事件 而不用在现有设计好的代码中添加或更改
这种触发器不用说 一定和事件有关 而且满地都是事件
所以为了运用这个思想 转换成了 c# 代码 简单的模拟
设计上吗 主体就是事件系统 在每个单位上绑定事件 每个单位都会发送事件到事件管理处 在事件管理处进行全局控制
其中 为了简化代码 在初始化中用了反射
话不多说 代码放上 模拟刚才的例子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace TriggerTest
{
class Program
{
static void Main(string[] args)
{
List<Trigger> triggerList = new List<Trigger>();
//模拟一个触发:主角被攻击的时候 如果主角生命值在 200 以下 那么对攻击者进行伤害 数值为真实伤害 10
EventStart eventS = new EventStart(0, EventStartType.Unit_BeHurt);
EventCondition eventC = new EventCondition(0, EventConditionType.Unit_Health, () =>
{
Player p = eventS.eventSender as Player;
return p.name == "player" && p.health < 200;
});
EventOperation eventO = new EventOperation(0, EventOperationType.Unit_DamageUnits, () =>
{
(eventS.eventRelationer as Player).health -= 10;
});
TriggerManager.Instance.AddTrigger(new Trigger(eventS, eventC, eventO));
//designer
Player player = new Player("player", 11, 100);
Player enemy = new Player("enemy", 20, 100);
TriggerManager.Instance.BindEvent(player);
enemy.AttackTarget(player);
Console.WriteLine($"{enemy.health}");
}
}
public class Player
{
public event Action<object, object> Unit_BeHurt;
public string name;
public float attack;
public float health;
public Player(string name, float attack, float health)
{
this.name = name;
this.attack = attack;
this.health = health;
}
public void BeHurt(int damage, object attacker)
{
Unit_BeHurt?.Invoke(this, attacker);
this.health -= damage;
}
public void AttackTarget(Player emp)
{
emp.BeHurt((int)this.attack, this);
}
}
public class Trigger
{
public EventStart start;
public EventCondition condition;
public EventOperation operation;
public Trigger(EventStart start, EventCondition condition, EventOperation operation)
{
this.start = start;
this.condition = condition;
this.operation = operation;
start.trigger = this;
condition.trigger = this;
operation.trigger = this;
}
}
public enum EventStartType
{
Time_TimeOver,
Unit_BeHurt,
}
public enum EventConditionType
{
Unit_Health,
}
public enum EventOperationType
{
Unit_DamageUnits,
Unit_ChangeHealth,
}
public class EventStart
{
public Trigger trigger;
public int id;
public EventStartType type;
public object eventSender;//事件发起者
public object eventRelationer;//事件关系者
public EventStart(int id, EventStartType type)
{
this.id = id;
this.type = type;
}
}
public class EventCondition
{
public Trigger trigger;
public int id;
public EventConditionType type;
public Func<bool> conditionFunc;
public EventCondition(int id, EventConditionType type, Func<bool> func)
{
this.id = id;
this.type = type;
conditionFunc = func;
}
public bool IsTrue()
{
return conditionFunc == null ? false : conditionFunc();
}
}
public class EventOperation
{
public Trigger trigger;
public int id;
public EventOperationType type;
public Action action;
public EventOperation(int id, EventOperationType type, Action action)
{
this.id = id;
this.type = type;
this.action = action;
}
public object[] Run()
{
action?.Invoke() ;
return null;
}
}
public class TriggerManager
{
private static TriggerManager instance;
public Dictionary<EventStartType, List<Trigger>> dic = new Dictionary<EventStartType, List<Trigger>>();
public static TriggerManager Instance
{
get
{
if (instance == null)
{
instance = new TriggerManager();
}
return instance;
}
set => instance = value;
}
private TriggerManager()
{
dic.Add(EventStartType.Time_TimeOver, new List<Trigger>());
dic.Add(EventStartType.Unit_BeHurt, new List<Trigger>());
}
public void AddTrigger(Trigger t)
{
dic[t.start.type].Add(t);
}
//监听 单位事件 只要是 Player 类 都可以绑定 (这里可以用反射 可以将所有类都可以用这个绑定函数 前提是保证这个类中有该事件)
public void BindEvent(Player player)
{
var events = player.GetType().GetEvents();
foreach (var child in events)
{
child.AddEventHandler(player, new Action<object, object>((sender, relations) =>
{
var eventStartType = (EventStartType)Enum.Parse(typeof(EventStartType), child.Name);
SendEvent(eventStartType, sender, relations);
}));
}
}
public void SendEvent(EventStartType eventType, object sender, object relations)
{
List<Trigger> list = dic[eventType];
list.ForEach(e =>
{
e.start.eventSender = sender;
e.start.eventRelationer = relations;
if (e.condition.IsTrue())
{
e.operation.Run();
}
});
}
}
}
复制代码
在枚举中增加事件类型 在单位中事件也要创建 名称要一样
这样 几行代码就可以创建一个触发器
之后的时间里 可能会写一个运用这个模拟 简单AI战斗 的脚本 AI处只需写逻辑和事件 其他的都交由触发器来完成 先立个 flag 。。。
來自:
随幻Kaller
欢迎光临 纳金网 (http://go.narkii.com/club/)
Powered by Discuz! X2.5