There’re a few components to this. Obviously your own architecture takes preference over how I might imagine it, but let’s say you have a class something like
class FoodPortion
{
public float carbCalories;
public float proteinCalories;
public float fatPerc;
public float cost;
}
And as above, you’ve got a few needs for the character. Let’s say they look like this:
const float CALORIES_REQD_PER_DAY = 2000;
const float CARB_PERC = 0.5f;
const float PROTEIN_PERC = 0.2f;
const float FAT_PERC = 0.3f;
float myCurrentDailyCarbCount;
float myCurrentDailyProteinCount;
float myCurrentDailyFatCount;
We’ll also assume in this instance that the EatFood function looks something like this:
void EatFood(FoodPortion food)
{
myCurrentDailyCarbCount += food.carbCalories;
myCurrentDailyProteinCount += food.proteinCalories;
myCurrentDailyFatCount += food.fatPerc;
}
What you want is to be able to evaluate based on different factors, and weight according to those. Stuff like the nutritional value to the character, the cost, as well other factors like the distance to the food (we don’t want the character walking all the way across town because something was marginally cheaper than something right next to them. Or do we? That’s where the weighting comes in).
For the nutrition value, the characters will want to keep track of what they need so that we can compare the benefits of a food portion.
// 0 - 1 values
float myCarbNeedPerc;
float myProteinNeedPerc;
float myFatNeedPerc;
void EvaluateMyFoodNeeds()
{
//Will be zero if we're full on carbs, or 1 if we have none
myCarbNeedPerc = CALORIES_REQD_PER_DAY * CARB_PERC - myCurrentDailyCarbCount;
myProteinNeedPerc = CALORIES_REQD_PER_DAY * PROTEIN_PERC - myCurrentDailyProteinCount;
myFatNeedPerc = CALORIES_REQD_PER_DAY * FAT_PERC - myCurrentDailyFatCount;
}
Then, we can take a hypothetical food portion and output a float based on our requirements.
float EvaluateFoodBasedOnNeed(FoodPortion food)
{
EvaluateMyFoodNeeds();
//Will return a smaller number if we don't need this or a larger number if we do
float nutritionDesire = (food.carbCalories * myCarbNeedPerc + food.proteinCalories * myProteinNeedPerc + food.fatPerc * myFatNeedPerc);
return nutritionDesire;
}
We can evaluate based on other factors too, like the aforementioned cost
float EvaluateFoodBasedOnCost(FoodPortion food)
{
//Will return a smaller number for a higher cost or a larger number for a lower cost
float costDesire = (1f / Mathf.Min(food.cost, 1f));
return costDesire;
}
We’ll also want some weights for these evaluations based on how you want the behaviour to manifest itself. Do characters prefer cheaper, or more nutritious food? Will they travel for miles to eat a snack if it means they’ll gain a better nutritional benefit? These can be easily tweaked, or even dynamic based on the characters resources. Ultimately you’ll be adding up all these factors and simply choosing the best one for the character.
void ChooseFood(FoodPortion[] allAvailableFoods)
{
int bestFoodIndex = -1;
float bestFoodValue = 0f;
for (int i = 0; i < allAvailableFoods.Length; i++)
{
float foodValue =
EvaluateFoodBasedOnCost(allAvailableFoods[i]) * COST_WEIGHTING
+ EvaluateFoodBasedOnNeed(allAvailableFoods[i]) * NUTRITION_WEIGHTING
+ EvaluateFoodBasedOnDistance(allAvailableFoods[i]) * DISTANCE_WEIGHTING;
if (foodValue > bestFoodValue)
{
bestFoodValue = foodValue;
bestFoodIndex = i;
}
}
FoodPortion chosenFood = allAvailableFoods[bestFoodIndex];
}
TL;DR: It depends on the needs of your game. Usually you’ll want some weighting to whatever factors you need that can be easily tweaked to affect behaviour. The choice algorithm just takes all these weights and decides which one is best overall.