using System;
using System.Linq.Expressions;
using System.Reflection;
using UnityEngine;
using Object = UnityEngine.Object;
public class EnemyStateMachine : MonoBehaviour {
//Define the state machine delegate, take Enemy and Hero as parameters, and return an empty method with Enemy and Hero as parameters
//It will return a corresponding behavior function based on the hero's state (such as health and distance).
Func<Enemy, Hero, Action<Enemy, Hero>> stateEvaluator;
//Storing the current behavior function
Action<Enemy, Hero> behavior;
Enemy enemy;
Hero hero;
void Start() {
enemy = FindObjectOfType<Enemy>();
hero = FindObjectOfType<Hero>();
stateEvaluator = CreateDynamicStateMachine();
}
void Update() {
//Get the current behavior
behavior = stateEvaluator(enemy, hero);
//Execute the current behavior
behavior(enemy, hero);
Debug.Log("Enemy Aggression Level:", enemy.AggressionLevel);
}
public Func<Enemy, Hero, Action<Enemy, Hero>> CreateDynamicStateMachine() {
//Define parameter expression
ParameterExpression enemyParam = Expression.Parameter(typeof(Enemy), "enemy");
ParameterExpression heroParam = Expression.Parameter(typeof(Hero), "hero");
//Define a binary expression
BinaryExpression heroLowHealth = Expression.LessThan(
Expression.Property(heroParam, "Health"),
Expression.Constant(30)
);
BinaryExpression heroNear = Expression.LessThan(
Expression.Property(heroParam, "Distance"),
Expression.Constant(10f)
);
Debug.Log($"HeroLowHealth{heroLowHealth}");
Debug.Log($"HeroNear{heroNear}");
var attack = CreateActionExpression("Attack").Compile();
var taunt = CreateActionExpression("Taunt").Compile();
var patrol = CreateActionExpression("Patrol").Compile();
// Conditional expression, if heroNear is true, execute taunt, otherwise execute patrol
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);
}
}