当前位置: 首页 > news >正文

表达式树实战:Unity动态逻辑编程

目录

表达式树技术解析与应用

一、学习表达式树的必要性

二、核心应用场景

动态技能系统

MOD支持系统

三、实战演示:属性获取器

传统模式缺陷

表达式树实现

条件触发系统

行为链组合

执行结果

运行时状态机


表达式树技术解析与应用

一、学习表达式树的必要性

传统Unity开发存在三大核心痛点:

  1. 逻辑固化问题 - 编译后无法修改行为逻辑
  2. 组件强耦合 - GameObject间依赖关系复杂
  3. 动态性不足 - 难以实现运行时逻辑热替换

表达式树技术通过将代码转换为可操作的数据结构,提供以下优势:

  • 运行时动态构建逻辑
  • 实现组件间弱耦合通信
  • 支持可视化配置游戏行为

二、核心应用场景

动态技能系统

  • 通过JSON配置行为树
  • 运行时解析生成表达式
  • 实现无需重新编译的AI逻辑更新

MOD支持系统

  • 支持玩家自定义逻辑脚本
  • 在安全沙箱中运行表达式
  • 实时加载玩家创作内容

三、实战演示:属性获取器

传统模式缺陷

public int GetPlayerStat(Player p, string statName)
{switch(statName){case "Health": return p.Health;case "Mana": return p.Mana;// 每新增属性需修改此处}
}

表达式树实现

using System;
using System.Linq.Expressions;
using UnityEngine;public class ExpressionTreeDemo : MonoBehaviour 
{void Start() {Player player = new () { Health = 100 };Func<Player, int> healthProperty = CreatePropertyGetter<Player, int>("Health");Debug.Log($"Player Health: {healthProperty(player)}");}public int GetPlayerStat(Player player, string statName) {Func<Player, int> propertyGetter = CreatePropertyGetter<Player, int>(statName);return propertyGetter(player);}public Func<T, TProperty> CreatePropertyGetter<T, TProperty>(string propertyName) {ParameterExpression param = Expression.Parameter(typeof(T), "x");MemberExpression property = Expression.Property(param, propertyName);Expression<Func<T, TProperty>> lambda = Expression.Lambda<Func<T, TProperty>>(property, param);return lambda.Compile();}
}

应用场景:动态获取对象属性
技术要点:属性访问表达式(Expression.Property)

条件触发系统

public class ConditionTrigger : MonoBehaviour 
{public string ConditionExpression = "Player.Health.CurrentHP < 0.3";public GameObject ContextObject;private Func<GameObject, bool> _compiledCondition;private static Dictionary<string, Func<GameObject, bool>> _cache = new();void Start(){if (!_cache.TryGetValue(ConditionExpression, out _compiledCondition)){var elements = ConditionExpression.Split('.');var rootObj = Expression.Parameter(typeof(GameObject), "context");Expression accessChain = rootObj;foreach (var element in elements.Skip(1)){accessChain = Expression.PropertyOrField(accessChain, element);}var conditionExpr = BuildComparison(accessChain, "<", Expression.Constant(0.3f));_compiledCondition = Expression.Lambda<Func<GameObject, bool>>(conditionExpr, rootObj).Compile();_cache[ConditionExpression] = _compiledCondition;}}void Update(){if (_compiledCondition(ContextObject)){Debug.Log("触发条件!");}}private Expression BuildComparison(Expression left, string operatorStr, Expression right){return operatorStr switch{"<" => Expression.LessThan(left, right),">" => Expression.GreaterThan(left, right),"==" => Expression.Equal(left, right),"!=" => Expression.NotEqual(left, right),"<=" => Expression.LessThanOrEqual(left, right),">=" => Expression.GreaterThanOrEqual(left, right),_ => throw new NotSupportedException($"不支持的运算符: {operatorStr}")};}
}

应用场景:动态游戏事件触发

 

行为链组合

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using UnityEngine;// 示例用法
public class ComboExample : MonoBehaviour
{private ComboSystem _comboSystem;void Start(){_comboSystem = new ComboSystem();// 配置连招动作_comboSystem.ActionExpressions.Add(GetComboExpression(typeof(AttackAnimation), nameof(AttackAnimation.Play), Expression.Constant("SwordSwing")));_comboSystem.ActionExpressions.Add(GetComboExpression(typeof(EffectsManager), nameof(EffectsManager.Spawn), Expression.Constant("SwordHit")));_comboSystem.ActionExpressions.Add(GetComboExpression(typeof(AttackAnimation), nameof(AttackAnimation.Play), Expression.Constant("SwordSwing2")));_comboSystem.ActionExpressions.Add(GetComboExpression(typeof(DamageCalculator), nameof(DamageCalculator.Apply), Expression.Constant(new Vector3(0, 1, 0)), Expression.Constant(100f)));// 执行连招_comboSystem.ExecuteCombo();}Expression<Action> GetComboExpression(Type type, string methodName, params Expression[] args){return Expression.Lambda<Action>(Expression.Call(type, methodName, null, args));}
}public class ComboSystem
{public List<Expression<Action>> ActionExpressions = new();public void ExecuteCombo(){var comboBlock = Expression.Block(ActionExpressions.Select(exp => exp.Body));var finalExpr = Expression.Lambda<Action>(comboBlock);finalExpr.Compile().Invoke(); // 执行连招}
}// 示例动作类
public class AttackAnimation
{public static void Play(string animationName){Debug.Log($"播放动画: {animationName}");}
}public class EffectsManager
{public static void Spawn(string effectName){Debug.Log($"生成特效: {effectName}");}
}public class DamageCalculator
{public static void Apply(Vector3 position, float damage){Debug.Log($"应用伤害: {damage} 到位置: {position}");}
}

执行结果
播放动画: SwordSwing
生成特效: SwordHit
播放动画: SwordSwing2
应用伤害: 100 到位置: (0.00, 1.00, 0.00)

关于 Expression.Block: Expression.Block 允许将多个表达式组合成一个块,并按顺序执行这些表达式。

运行时状态机

 
using System;
using System.Linq.Expressions;
using System.Reflection;
using UnityEngine;
using Object = UnityEngine.Object;public class EnemyStateMachine : MonoBehaviour 
{// 状态评估器:根据敌人和英雄状态返回对应的行为函数private Func<Enemy, Hero, Action<Enemy, Hero>> stateEvaluator;private Action<Enemy, Hero> currentBehavior;private Enemy enemy;private Hero hero;void Start() {enemy = FindObjectOfType<Enemy>();hero = FindObjectOfType<Hero>();stateEvaluator = CreateDynamicStateMachine();}void Update() {// 获取并执行当前行为currentBehavior = stateEvaluator(enemy, hero);currentBehavior(enemy, hero);Debug.Log($"Enemy Aggression Level: {enemy.AggressionLevel}");}public Func<Enemy, Hero, Action<Enemy, Hero>> CreateDynamicStateMachine() {// 定义表达式参数ParameterExpression enemyParam = Expression.Parameter(typeof(Enemy), "enemy");ParameterExpression heroParam = Expression.Parameter(typeof(Hero), "hero");// 创建条件表达式BinaryExpression isHeroLowHealth = Expression.LessThan(Expression.Property(heroParam, "Health"),Expression.Constant(30));BinaryExpression isHeroNearby = Expression.LessThan(Expression.Property(heroParam, "Distance"),Expression.Constant(10f));Debug.Log($"Health Check: {isHeroLowHealth}");Debug.Log($"Distance Check: {isHeroNearby}");// 编译行为方法var attackBehavior = CreateActionExpression("Attack").Compile();var tauntBehavior = CreateActionExpression("Taunt").Compile();var patrolBehavior = CreateActionExpression("Patrol").Compile();// 构建行为选择逻辑ConditionalExpression chooseTauntOrPatrol = Expression.Condition(isHeroNearby, Expression.Constant(tauntBehavior), Expression.Constant(patrolBehavior));ConditionalExpression finalDecision = Expression.Condition(isHeroLowHealth, Expression.Constant(attackBehavior), chooseTauntOrPatrol);// 编译并返回状态机var stateMachine = Expression.Lambda<Func<Enemy, Hero, Action<Enemy, Hero>>>(finalDecision, enemyParam, heroParam);return stateMachine.Compile();}private Expression<Action<Enemy, Hero>> CreateActionExpression(string methodName) {ParameterExpression enemyParam = Expression.Parameter(typeof(Enemy), "enemy");ParameterExpression heroParam = Expression.Parameter(typeof(Hero), "hero");MethodInfo method = typeof(Enemy).GetMethod(methodName, new[] { typeof(Hero) });MethodCallExpression methodCall = Expression.Call(enemyParam, method, heroParam);return Expression.Lambda<Action<Enemy, Hero>>(methodCall, enemyParam, heroParam);}
}

CreateDynamicStateMachine 方法说明:
1. 参数定义:
   - enemyParam: 敌人实例参数
   - heroParam: 英雄实例参数

2. 条件检查:
   - 英雄生命值是否低于30 (heroLowHealth)
   - 英雄距离是否小于10单位 (heroNear)

3. 行为选择逻辑:
   - 优先检查英雄生命值,若低则执行攻击
   - 其次检查距离,近距离时嘲讽,否则巡逻

CreateActionExpression 方法说明:
1. 创建方法调用表达式
2. 通过反射获取指定方法
3. 返回编译后的行为Lambda表达式

http://www.xdnf.cn/news/1295911.html

相关文章:

  • tp5集成elasticsearch笔记
  • Unity中的神经网络遗传算法实战
  • 一篇文章读懂.Net的依赖注入
  • .NET 的 WebApi 项目必要可配置项都有哪些?
  • .Net4.0 WPF中实现下拉框搜索效果
  • 面试题之项目中git如何进行管理
  • 如何启动本机mysql数据库
  • 在mysql> 下怎么运行 .sql脚本
  • XCTF-warmup详细题解(含思考过程)
  • Morph Studio-一站式AI视频创作平台
  • Vue浅学
  • Elasticsearch 中如何配置 RBAC 权限-实现安全的访问控制
  • QT6(创建第一个QT项目)
  • Win10上Qt使用Libcurl库
  • Qt 实现Ymodem协议源码分享
  • MySQL工具包中的其他程序
  • 从概率填充到置信度校准:GPT-5如何从底层重构AI的“诚实”机制
  • 树莓派 4B 上部署 Minecraft PaperMC 1.20.x 的一键部署脚本
  • ASQA: 面向模糊性事实问题的长格式问答数据集与评估框架
  • C#WPF实战出真汁02--登录界面设计
  • 利用 Python 爬虫按图搜索 1688 商品(拍立淘)实战指南
  • Windows批处理脚本自动合并当前目录下由You-get下载的未合并的音视频文件
  • LeetCode 分类刷题:2302. 统计得分小于 K 的子数组数目
  • 我的第一个开源项目-jenkins集成k8s项目
  • 开疆智能Ethernet转ModbusTCP网关连接UR机器人配置案例
  • 区块链 + 域名Web3时代域名投资的新风口(上)
  • 《算法导论》第 25 章:所有结点对的最短路径问题
  • 常见的tls检测的绕过方案
  • Mybatis学习笔记(二)
  • Transformer之多头注意力机制和位置编码(二)