Я хочу «вырастить» PreFab в единое целое, используя некоторые параметры, которые являются численным решением системы ODE. У меня есть два сценария: один буквально увеличивает префаб, а другой - решение ODE с использованием численного метода Рунге-Кутты 4-го порядка.
Вот код для решения ODE:
using System;
namespace RungeKutta4
{
class Program
{
static void Main(string[] args)
{
//Incrementers to pass into the known solution
double t = 0.0;
double T = 1.0;
double dt = 0.1;
// Assign the number of elements needed for the arrays
int n = (int)(((T - t) / dt)) + 1;
// Initialize the arrays for the time index 's' and estimates 'annualGrowth' at each index 'i'
double[] annualGrowth = new double[n]; //y
double[] s = new double[n]; //t
// RK4 Variables
double dy1;
double dy2;
double dy3;
double dy4;
// RK4 Initializations condizioni iniziali
int i = 0;
s[i] = 0.0; //t0 = 0
annualGrowth[i] = 1.0; //y(t0) = y(0) = 1
// Iterate and implement the Rk4 Algorithm
while (i < annualGrowth.Length - 1)
{
dy1 = dt * equation(s[i], annualGrowth[i]);
dy2 = dt * equation(s[i] + dt / 2, annualGrowth[i] + dy1 / 2);
dy3 = dt * equation(s[i] + dt / 2, annualGrowth[i] + dy2 / 2);
dy4 = dt * equation(s[i] + dt, annualGrowth[i] + dy3);
s[i + 1] = s[i] + dt;
annualGrowth[i + 1] = annualGrowth[i] + (dy1 + 2 * dy2 + 2 * dy3 + dy4) / 6;
double t_rounded = Math.Round(t + dt, 2);
if (t_rounded % 1 == 0)
{
Console.WriteLine(" y(" + t_rounded + ")" + " " .PadRight(10) + annualGrowth[i + 1]);
}
i++;
t += dt; //t = t + dt
};//End Rk4
Console.ReadLine();
}
// Differential Equation
public static double equation(double t, double annualGrowth)
{
double y_prime;
double k = 0.1;
double maxHeight = 5.0;
return y_prime = k * annualGrowth * (1-(annualGrowth/maxHeight));
}
}
}
Затем у меня есть «растущий» сценарий в единстве:
public class Growth : MonoBehaviour
{
SetupScene setup;
TimeManager timeManager;
float currentLenght;
float currentWidth;
Genetic geneticInfo;
bool isMaxLenght;
bool isMaxWeigth;
GameObject newInternode;
float annualLengthGrowth = 0.05f;
float annualWidthGrowth = 0.01f;
Vector3 annualGrowth;
bool hasChild;
// Start is called before the first frame update
void Awake()
{
annualGrowth = new Vector3(annualWidthGrowth, annualLengthGrowth, annualWidthGrowth);
setup = GameObject.Find("Setup").GetComponent<SetupScene>();
timeManager = GameObject.Find("Time Manager").GetComponent<TimeManager>();
currentLenght = 0f;
currentWidth = 0f;
geneticInfo = new Genetic(1);
}
// Update is called once per frame
void Update()
{
Debug.Log("ciao, sono nato " + gameObject.name);
Debug.Log(timeManager.IsYearElapsed + " " + gameObject.name);
if (timeManager.IsYearElapsed)
{
float scaleFactorXZ = 1f;
float scaleFactorY = 1f;
if (gameObject.name != "Seed")
{
scaleFactorXZ = geneticInfo.InternodeMaxWidtht;
scaleFactorY = geneticInfo.InternodeMaxLenght;
}
currentLenght = (gameObject.transform.lossyScale.y + annualGrowth.y);
currentWidth = (gameObject.transform.lossyScale.x + annualGrowth.x);
if(currentWidth > geneticInfo.InternodeMaxWidtht)
{
currentWidth = geneticInfo.InternodeMaxWidtht;
isMaxWeigth = true;
}
if(currentLenght > geneticInfo.InternodeMaxLenght)
{
currentLenght = geneticInfo.InternodeMaxLenght;
isMaxLenght = true;
}
gameObject.transform.localScale = new Vector3(currentWidth/scaleFactorXZ, currentLenght/scaleFactorY, currentWidth/scaleFactorXZ);
if (isMaxLenght)
{
if (!hasChild && setup.Manager.InternodeNumber < geneticInfo.MaxInternodeNumber)
{
setup.Manager.InternodeNumber++;
Debug.Log("nuovo internodo creato");
setup.LastInternodePosition = gameObject.transform.position + new Vector3(0f, geneticInfo.InternodeMaxLenght, 0f);
newInternode = Instantiate(setup.Prefab, new Vector3(setup.LastInternodePosition.x, setup.LastInternodePosition.y, setup.LastInternodePosition.z), Quaternion.identity);
newInternode.transform.localScale = Vector3.zero;
newInternode.transform.parent = setup.LastInternode.transform;
setup.LastInternode = newInternode;
newInternode.AddComponent<Growth>();
hasChild = true;
}
if (isMaxWeigth)
{
gameObject.GetComponent<Growth>().enabled = false;
}
}
}
}
}
Я хочу связать численное решение сценария ODE со значением float annualLengthGrowth = 0.05f;
в сценарии единства, который на данный момент жестко закодирован. Проблема заключается в том, что при каждом обновлении (или временном шаге) начальное значение системы ODE должно быть окончательным численным расчетным значением предыдущего шага.
Например, учитывая, что на первом временном шаге начальное значение yearGrowth в Сценарий ODE равен 1.0, окончательное вычисленное значение (например) annualGrowthT1 = 2.35f
, я должен использовать это значение в сценарии Unity на первом этапе как annualLengthGrowth
. На следующем временном шаге начальное значение для сценария ODE должно быть annualGrowthT1 = 2.35f
, затем рассчитанное конечное значение должно быть (например) annualGrowthT2 = 3.56f
, и это значение должно использоваться на втором временном шаге в сценарии единицы как новое annualLengthGrowth
, И так далее.
Это должно быть понятно благодаря этой картинке: