Created
November 17, 2024 08:57
-
-
Save adammyhre/13c3685f48016e5b197322113082e418 to your computer and use it in GitHub Desktop.
Expression Trees in Unity Examples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq.Expressions; | |
using UnityEngine; | |
public class DamageCalculator : MonoBehaviour { | |
void Start() { | |
Func<int, int, int> damageExpression = CreateDamageEvaluator(); | |
int damage = damageExpression(10, 2); | |
Debug.Log($"Calculated Damage: {damage}"); | |
} | |
public Func<int, int, int> CreateDamageEvaluator() { | |
ParameterExpression baseDamage = Expression.Parameter(typeof(int), "baseDamage"); | |
ParameterExpression multiplier = Expression.Parameter(typeof(int), "multiplier"); | |
BinaryExpression body = Expression.Multiply(baseDamage, multiplier); | |
return Expression.Lambda<Func<int, int, int>>(body, baseDamage, multiplier).Compile(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using UnityEngine; | |
public class EnemyStateMachine : MonoBehaviour { | |
Func<Enemy, Hero, Action<Enemy, Hero>> stateEvaluator; | |
Action<Enemy, Hero> behavior; | |
Enemy enemy; | |
Hero hero; | |
void Start() { | |
enemy = FindFirstObjectByType<Enemy>(); | |
hero = FindFirstObjectByType<Hero>(); | |
stateEvaluator = CreateDynamicStateMachine(); | |
} | |
void Update() { | |
behavior = stateEvaluator(enemy, hero); | |
behavior(enemy, hero); | |
Logwin.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 heroLowHealth = Expression.LessThan( | |
Expression.Property(heroParam, "Health"), | |
Expression.Constant(30) | |
); | |
BinaryExpression heroNear = Expression.LessThan( | |
Expression.Property(heroParam, "Distance"), | |
Expression.Constant(10f) | |
); | |
Logwin.Log("HeroLowHealth", heroLowHealth); | |
Logwin.Log("HeroNear", heroNear); | |
var attack = CreateActionExpression("Attack").Compile(); | |
var taunt = CreateActionExpression("Taunt").Compile(); | |
var patrol = CreateActionExpression("Patrol").Compile(); | |
ConditionalExpression tauntOrPatrol = Expression.Condition(heroNear, Expression.Constant(taunt), Expression.Constant(patrol)); | |
ConditionalExpression finalCondition = Expression.Condition(heroLowHealth, Expression.Constant(attack), tauntOrPatrol); | |
var lambda = Expression.Lambda<Func<Enemy, Hero, Action<Enemy, Hero>>>(finalCondition, enemyParam, heroParam); | |
return lambda.Compile(); | |
} | |
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 call = Expression.Call(enemyParam, method, heroParam); | |
return Expression.Lambda<Action<Enemy, Hero>>(call, enemyParam, heroParam); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
using UnityEngine; | |
public class MethodInvocationDemo : MonoBehaviour { | |
void Start() { | |
Action<Player, object> action = CreateMethodInvoker<Player>("TakeDamage"); | |
Player player = new Player(); | |
action(player, 25); | |
} | |
public Action<T, object> CreateMethodInvoker<T>(string methodName) { | |
ParameterExpression instance = Expression.Parameter(typeof(T), "instance"); | |
ParameterExpression argument = Expression.Parameter(typeof(object), "arg"); | |
MethodInfo method = typeof(T).GetMethod(methodName) | |
?? throw new ArgumentException($"Method {methodName} not found on type {typeof(T).Name}"); | |
MethodCallExpression call = Expression.Call(instance, method, Expression.Convert(argument, method.GetParameters()[0].ParameterType)); | |
return Expression.Lambda<Action<T, object>>(call, instance, argument).Compile(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq.Expressions; | |
using UnityEngine; | |
public class NPCBehaviorDemo : MonoBehaviour { | |
void Start() { | |
Func<int, string> aggressionEvaluator = CreateBehaviorEvaluator(); | |
int playerHealth = 50; | |
string aggressionLevel = aggressionEvaluator(playerHealth); | |
Debug.Log($"Aggression Level: {aggressionLevel}"); | |
} | |
public Func<int, string> CreateBehaviorEvaluator() { | |
ParameterExpression health = Expression.Parameter(typeof(int), "health"); | |
BinaryExpression condition = Expression.LessThan(health, Expression.Constant(30)); | |
ConstantExpression ifTrue = Expression.Constant("High"); | |
ConstantExpression ifFalse = Expression.Constant("Low"); | |
ConditionalExpression body = Expression.Condition(condition, ifTrue, ifFalse); | |
return Expression.Lambda<Func<int, string>>(body, health).Compile(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment