It has been 8 months I've been working on my metaball algorithm an the final technique I am trying out is writing magnets to which the sprite mesh edge vertices will update its position to, after finding the closest magnet point.
Code:
using HerminkasGams.SpriteSquash;
using UnityEngine;
[System.Serializable]
public class Vertex : MonoBehaviour // Game object which holds positions of vertex
{
public Vector3 currentPos;
public Vector3 initialPos;
public Vector3 revertingPos;
[HideInInspector]public GameObject _parentGameObject;
[HideInInspector]public SpriteMeshModifier _parentSpriteMeshModifier;
[HideInInspector]public ObjectManagerController _objectManagerController;
[HideInInspector]public int _index;
public void SetInitialPos(Vector3 pos, int index, GameObject parentGameObject, SpriteMeshModifier parentSpriteMeshModifier, ObjectManagerController objectManagerController) {
currentPos = pos;
initialPos = pos;
revertingPos = pos;
_index = index;
_parentGameObject = parentGameObject;
_parentSpriteMeshModifier = parentSpriteMeshModifier;
_objectManagerController = objectManagerController;
}
//While this update is necessary, because there are so many verticies, the game is super laggy
private void Update() {
//Debug.Log("Update for each slime mesh vertex!");
if (_objectManagerController.metaballEdgePointVertices.Count > 0) {
Vector3 nearestMagnetPoint = FindNearestMagnetPoint();
Debug.Log("Found nearest magnet point for current mesh vertex!");
Debug.Log(nearestMagnetPoint);
//UpdateCurrentVertex(nearestMagnetPoint, _index);
}
}
Vector3 FindNearestMagnetPoint() {
//Compute the nearest metaball edge magnet point by iterating through them if metaballEdgePointVertexGOs is not empty
if (_objectManagerController.metaballEdgePointVertices.Count > 0) {
int index = 0;
//Source, current mesh vertex of slime
Vector3 scp = _parentSpriteMeshModifier.gameObject.transform.rotation * currentPos;
Vector3 point = new Vector3(scp.x * _parentSpriteMeshModifier.gameObject.transform.localScale.x, scp.y * _parentSpriteMeshModifier.gameObject.transform.localScale.y, scp.z * _parentSpriteMeshModifier.gameObject.transform.localScale.z) + _parentSpriteMeshModifier.gameObject.transform.position;
float minDistance = 99999;
//Will iterate through metaballEdgePointVertexGOs to find closest
Vector3 scpMagnet = new Vector3(0,0,0);
Vector3 pointMagnet = new Vector3(0,0,0);
for (int i = 0; i < _objectManagerController.metaballEdgePointVertices.Count; i++)
{
scpMagnet = _objectManagerController.transform.rotation * _objectManagerController.metaballEdgePointVertices[i].currentPos;
pointMagnet = new Vector3(scpMagnet.x * _objectManagerController.transform.localScale.x, scpMagnet.y * _objectManagerController.transform.localScale.y, scpMagnet.z * _objectManagerController.transform.localScale.z) + _objectManagerController.transform.position;
var dis = Vector2.Distance(point, pointMagnet);
if (dis < minDistance)
{
index = i;
minDistance = dis;
}
}
return _objectManagerController.metaballEdgePointVertices[index].currentPos;
}
return new Vector3(0,0,-1);
}
void UpdateCurrentVertex(Vector3 moveTo, int index) {
_parentSpriteMeshModifier.UpdateVertecies(moveTo, index);
}
}
The problem, as you can see in the image below, is that there are many many vertices for each game object that needs call this logic in its Update(), and it's ridiculously laggy. Each of these yellow points are what needs to update its position based on how close it is to nearest magnet point.
I want to stretch these vertices with what is in the Update() logic to hit these magnets points:
Please help me achieve my close to 1 year dream of making color-respecting metaballs...
*Edit
So I asked Chat GPT the same question and got: Batch Processing: You can reduce the number of Update() calls by creating a manager object that handles the vertex updates in batch. This would be far more efficient than having an Update() method for each vertex GameObject.
So I added the update logic in the parent game object of these vertices.
private void Update()
{
UpdateMesh();
foreach (var vertex in vertices)
{
if (objectManagerController.metaballEdgePointVertices.Count > 0)
{
// Assume FindNearestMagnetPoint() is now a public method in Vertex
// Vector3 nearestMagnetPoint = vertex.FindNearestMagnetPoint();
Debug.Log("Current vertex position: ");
// Debug.Log(vertex.currentPos);
// Debug.Log("Found nearest magnet point for current mesh vertex!");
// Debug.Log(nearestMagnetPoint);
// Update the vertex position
//vertex.UpdateCurrentVertex(nearestMagnetPoint, vertex._index);
}
}
}
The problem is, it is still way tooooo laggy. Is there a best solution for my problem?