262 lines
8.7 KiB
C#
262 lines
8.7 KiB
C#
using System;
|
|
using UnityEditor.TextCore.Text;
|
|
using UnityEngine;
|
|
using static UnityEngine.GraphicsBuffer;
|
|
using static UnityEngine.UIElements.UxmlAttributeDescription;
|
|
|
|
public class NutrientController : MonoBehaviour
|
|
{
|
|
private float[,] nutrientMap;
|
|
[SerializeField, Range(10, 256)] int sizeX;
|
|
[SerializeField, Range(10, 256)] int sizeY;
|
|
[SerializeField] MeshRenderer meshRenderer;
|
|
|
|
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
|
void Start()
|
|
{
|
|
nutrientMap = new float[sizeX, sizeY];
|
|
for(int r = 0; r < sizeX; r ++)
|
|
{
|
|
for(int c = 0; c < sizeY; c++)
|
|
{
|
|
nutrientMap[r, c] = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
|
|
}
|
|
|
|
public void Step(float dTime)
|
|
{
|
|
for (int r = 0; r < sizeX; r++)
|
|
{
|
|
for (int c = 0; c < sizeY; c++)
|
|
{
|
|
if (nutrientMap[r,c] < 1)
|
|
{
|
|
nutrientMap[r, c] += (0.1f * dTime);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public float PlantNutrientUse(float x, float y, float radius, float nutrientsNeeded)
|
|
{
|
|
int locX = Mathf.FloorToInt(x * sizeX);
|
|
int locY = Mathf.FloorToInt(y * sizeY);
|
|
|
|
int flooredRadius = Mathf.FloorToInt(radius);
|
|
float totalNutrients = nutrientMap[locX, locY];
|
|
|
|
float[,] nutrientsAvailable;
|
|
|
|
try
|
|
{
|
|
nutrientsAvailable = new float[flooredRadius * 2 + 1, flooredRadius * 2 + 1];
|
|
} catch (Exception e)
|
|
{
|
|
Debug.Log($"x : {x} y : {y} radius : {radius} nutrients needed : {nutrientsNeeded}");
|
|
return 2000000;
|
|
}
|
|
|
|
// Calculate total amount of nutrients available to the plant, at a 1/ (2 * steps from origin) ratio.
|
|
for (int r = -flooredRadius; r <= flooredRadius; r++)
|
|
{
|
|
int currentLocX = locX + r;
|
|
|
|
for(int c = -flooredRadius; c <= flooredRadius; c++)
|
|
{
|
|
int currentLocY = locY + c;
|
|
if (currentLocX < 0 || currentLocX >= nutrientMap.GetLength(0) || currentLocY < 0 || currentLocY >= nutrientMap.GetLength(1))
|
|
{
|
|
nutrientsAvailable[flooredRadius, flooredRadius] = 0;
|
|
}
|
|
else
|
|
{
|
|
if (r == 0 && c == 0)
|
|
{
|
|
nutrientsAvailable[flooredRadius, flooredRadius] = nutrientMap[currentLocX, currentLocY];
|
|
}
|
|
else
|
|
{
|
|
nutrientsAvailable[flooredRadius + r, flooredRadius + c] = nutrientMap[currentLocX, currentLocY] / ((Mathf.Abs(r) + Mathf.Abs(c)) * 2);
|
|
totalNutrients += nutrientMap[currentLocX, currentLocY] / ((Mathf.Abs(r) + Mathf.Abs(c)) * 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If not enough nutrients are available to the plant to sustain it, return false.
|
|
// Can be changed to returning a float value indicating the deficit in nutrients with the plant taking that much in health damage
|
|
if (totalNutrients < nutrientsNeeded)
|
|
{
|
|
for (int r = -flooredRadius; r <= flooredRadius; r++)
|
|
{
|
|
int currentLocX = locX + r;
|
|
|
|
for (int c = -flooredRadius; c <= flooredRadius; c++)
|
|
{
|
|
int currentLocY = locY + c;
|
|
if (currentLocX >= 0 && currentLocX < nutrientMap.GetLength(0) && currentLocY >= 0 && currentLocY < nutrientMap.GetLength(1))
|
|
{
|
|
nutrientMap[currentLocX, currentLocY] -= (nutrientsAvailable[flooredRadius + r, flooredRadius + c]);
|
|
}
|
|
}
|
|
}
|
|
return nutrientsNeeded - totalNutrients;
|
|
}
|
|
|
|
for (int r = -flooredRadius; r <= flooredRadius; r++)
|
|
{
|
|
int currentLocX = locX + r;
|
|
|
|
for (int c = -flooredRadius; c <= flooredRadius; c++)
|
|
{
|
|
int currentLocY = locY + c;
|
|
if (currentLocX >= 0 && currentLocX < nutrientMap.GetLength(0) && currentLocY >= 0 && currentLocY < nutrientMap.GetLength(1))
|
|
{
|
|
nutrientMap[currentLocX, currentLocY] -= (nutrientsAvailable[flooredRadius + r, flooredRadius + c] / totalNutrients) * nutrientsNeeded;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public float GetAvailNutrients(float x, float y, float radius)
|
|
{
|
|
int locX = Mathf.FloorToInt(x * sizeX);
|
|
int locY = Mathf.FloorToInt(y * sizeY);
|
|
|
|
int flooredRadius = Mathf.FloorToInt(radius);
|
|
float totalNutrients = nutrientMap[locX, locY];
|
|
|
|
// Calculate total amount of nutrients available to the plant, at a 1/ (2 * steps from origin) ratio.
|
|
for (int r = -flooredRadius; r <= flooredRadius; r++)
|
|
{
|
|
int currentLocX = locX + r;
|
|
|
|
for (int c = -flooredRadius; c <= flooredRadius; c++)
|
|
{
|
|
int currentLocY = locY + c;
|
|
if (currentLocX < 0 || currentLocX >= nutrientMap.GetLength(0) || currentLocY < 0 || currentLocY >= nutrientMap.GetLength(1))
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
if (r == 0 && c == 0)
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
totalNutrients += nutrientMap[currentLocX, currentLocY] / ((Mathf.Abs(r) + Mathf.Abs(c)) * 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return totalNutrients;
|
|
}
|
|
|
|
public void UseNutrients(float x, float y, float radius, float used)
|
|
{
|
|
int locX = Mathf.FloorToInt(x * sizeX);
|
|
int locY = Mathf.FloorToInt(y * sizeY);
|
|
|
|
nutrientMap[locX, locY] -= used;
|
|
}
|
|
|
|
public void AddNutrients(float x, float y, float added, float radius)
|
|
{
|
|
int locX = Mathf.FloorToInt(x * sizeX);
|
|
int locY = Mathf.FloorToInt(y * sizeY);
|
|
|
|
int flooredRadius = Mathf.FloorToInt(radius);
|
|
float totalDistro = 0;
|
|
|
|
for (int r = -flooredRadius; r <= flooredRadius; r++)
|
|
{
|
|
int currentLocX = locX + r;
|
|
|
|
for (int c = -flooredRadius; c <= flooredRadius; c++)
|
|
{
|
|
int currentLocY = locY + c;
|
|
if (currentLocX >= 0 && currentLocX < nutrientMap.GetLength(0) && currentLocY >= 0 && currentLocY < nutrientMap.GetLength(1))
|
|
{
|
|
if (r == 0 && c == 0)
|
|
{
|
|
totalDistro += 1;
|
|
}
|
|
else
|
|
{
|
|
totalDistro += 1.0f / ((Mathf.Abs(r) + Mathf.Abs(c)) * 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int r = -flooredRadius; r <= flooredRadius; r++)
|
|
{
|
|
int currentLocX = locX + r;
|
|
|
|
for (int c = -flooredRadius; c <= flooredRadius; c++)
|
|
{
|
|
int currentLocY = locY + c;
|
|
if (currentLocX >= 0 && currentLocX < nutrientMap.GetLength(0) && currentLocY >= 0 && currentLocY < nutrientMap.GetLength(1))
|
|
{
|
|
if(r == 0 && c == 0)
|
|
{
|
|
nutrientMap[currentLocX, currentLocY] += (added / totalDistro);
|
|
}
|
|
else
|
|
{
|
|
nutrientMap[currentLocX, currentLocY] += (added / totalDistro) / ((Mathf.Abs(r) + Mathf.Abs(c)) * 2);
|
|
}
|
|
|
|
if(nutrientMap[currentLocX, currentLocY] > 1)
|
|
{
|
|
nutrientMap[currentLocX, currentLocY] = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Render()
|
|
{
|
|
Texture2D texture = new Texture2D(sizeX, sizeY);
|
|
for (int r = 0; r < sizeX; r++)
|
|
{
|
|
for (int c = 0; c < sizeY; c++)
|
|
{
|
|
float colorValue = nutrientMap[r, c];
|
|
texture.SetPixel(r, c, new Color(colorValue, colorValue, colorValue, 0.5f));
|
|
}
|
|
}
|
|
|
|
texture.Apply();
|
|
meshRenderer.material.mainTexture = texture;
|
|
meshRenderer.gameObject.SetActive(true);
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
[UnityEditor.CustomEditor(typeof(NutrientController))]
|
|
|
|
public class NutrientControllerEditor: UnityEditor.Editor
|
|
{
|
|
public override void OnInspectorGUI()
|
|
{
|
|
base.OnInspectorGUI();
|
|
if (GUILayout.Button("Sample Button"))
|
|
{
|
|
(target as NutrientController).Render();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|