Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved membranes #74

Merged
merged 3 commits into from Jan 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 47 additions & 30 deletions src/microbe_stage/Membrane.cs
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Godot;
using Array = Godot.Collections.Array;
using System.Linq;

/// <summary>
/// Membrane for microbes
Expand Down Expand Up @@ -284,17 +285,16 @@ public Vector3 GetVectorTowardsNearestPointOfMembrane(float x, float y)
/// <summary>
/// Return the position of the closest organelle to the target point if it is less then a certain threshold away.
/// </summary>
public Vector2 FindClosestOrganelles(Vector2 target)
public Vector2 FindClosestOrganelleInRange(Vector2 origin, float range)
{
// The distance we want the membrane to be from the organelles squared.
float closestSoFar = 4;
float closestSoFar = range;
Vector2 closest = new Vector2(INVALID_FOUND_ORGANELLE, INVALID_FOUND_ORGANELLE);

foreach (var pos in OrganellePositions)
{
float lenToObject = (target - pos).LengthSquared();
float lenToObject = (origin - pos).LengthSquared();

if (lenToObject < 4 && lenToObject < closestSoFar)
if (lenToObject < closestSoFar)
{
closestSoFar = lenToObject;
closest = pos;
Expand All @@ -304,6 +304,15 @@ public Vector2 FindClosestOrganelles(Vector2 target)
return closest;
}

public Vector2 FindCenterOfOrganellesInRange(Vector2 origin, float range)
{
List<Vector2> points = new List<Vector2>() { origin };

points.AddRange(OrganellePositions.Where(x => (origin - x).LengthSquared() < range));

return new Vector2(points.Sum(x => x.x) / points.Count(), points.Sum(x => x.y) / points.Count());
}

public bool MatchesCacheParameters(ICacheableData cacheData)
{
if (cacheData is IComputedMembraneData data)
Expand All @@ -320,16 +329,16 @@ public long ComputeCacheHash()
/// <summary>
/// Decides where the point needs to move based on the position of the closest organelle.
/// </summary>
private static Vector2 GetMovement(Vector2 target, Vector2 closestOrganelle)
private Vector2 GetMovement(Vector2 target, Vector2 closestOrganelle)
{
float power = Mathf.Pow(2.7f, -(target - closestOrganelle).Length() / 10) / 50;
float power = Mathf.Pow(2.7f, -(target - closestOrganelle).Length() / 10) / 250;

return (closestOrganelle - target) * power;
}

private static Vector2 GetMovementForCellWall(Vector2 target, Vector2 closestOrganelle)
private Vector2 GetMovementForCellWall(Vector2 target, Vector2 closestOrganelle)
{
float power = Mathf.Pow(10.0f, -(target - closestOrganelle).Length()) / 50;
float power = Mathf.Pow(3.1f, -(target - closestOrganelle).Length() / 3) / 250;

return (closestOrganelle - target) * power;
}
Expand Down Expand Up @@ -459,6 +468,8 @@ private void InitializeMesh()
// Half the side length of the original square that is compressed to make the membrane.
int cellDimensions = 10;

var nodeLength = cellDimensions / membraneResolution;

foreach (var pos in OrganellePositions)
{
if (Mathf.Abs(pos.x) + 1 > cellDimensions)
Expand All @@ -475,37 +486,41 @@ private void InitializeMesh()
previousWorkBuffer.Capacity = vertices2D.Capacity;
nextWorkBuffer.Capacity = previousWorkBuffer.Capacity;

// left wall of square
for (int i = membraneResolution; i > 0; i--)
{
previousWorkBuffer.Add(new Vector2(-cellDimensions,
cellDimensions - 2 * cellDimensions / membraneResolution * i));
cellDimensions - 2 * nodeLength * i));
}

// bottom wall of square
for (int i = membraneResolution; i > 0; i--)
{
previousWorkBuffer.Add(new Vector2(
cellDimensions - 2 * cellDimensions / membraneResolution * i,
cellDimensions - 2 * nodeLength * i,
cellDimensions));
}

// right wall of square
for (int i = membraneResolution; i > 0; i--)
{
previousWorkBuffer.Add(new Vector2(cellDimensions,
-cellDimensions + 2 * cellDimensions / membraneResolution * i));
-cellDimensions + 2 * nodeLength * i));
}

// bottom wall of square
for (int i = membraneResolution; i > 0; i--)
{
previousWorkBuffer.Add(new Vector2(
-cellDimensions + 2 * cellDimensions / membraneResolution * i,
-cellDimensions + 2 * nodeLength * i,
-cellDimensions));
}

// This needs to actually run a bunch of times as the points moving towards the organelles is iterative.
// We use rotating work buffers to save time on skipping useless copies
for (int i = 0; i < 40 * cellDimensions; i++)
for (int i = 0; i < 60 * cellDimensions; i++)
{
DrawCorrectMembrane(cellDimensions, previousWorkBuffer, nextWorkBuffer);
DrawMembrane(cellDimensions, previousWorkBuffer, nextWorkBuffer, Type.CellWall ? GetMovementForCellWall : GetMovement);

(previousWorkBuffer, nextWorkBuffer) = (nextWorkBuffer, previousWorkBuffer);
}
Expand Down Expand Up @@ -635,18 +650,6 @@ private void BuildMesh()
return writeIndex;
}

private void DrawCorrectMembrane(float cellDimensions, List<Vector2> sourceBuffer, List<Vector2> targetBuffer)
{
if (Type.CellWall)
{
DrawMembrane(cellDimensions, sourceBuffer, targetBuffer, GetMovementForCellWall);
}
else
{
DrawMembrane(cellDimensions, sourceBuffer, targetBuffer, GetMovement);
}
}

private void DrawMembrane(float cellDimensions, List<Vector2> sourceBuffer, List<Vector2> targetBuffer,
Func<Vector2, Vector2, Vector2> movementFunc)
{
Expand All @@ -658,13 +661,27 @@ private void DrawCorrectMembrane(float cellDimensions, List<Vector2> sourceBuffe
targetBuffer.RemoveAt(targetBuffer.Count - 1);

// Loops through all the points in the membrane and relocates them as necessary.
for (int i = 0, end = sourceBuffer.Count; i < end; ++i)
for (int i = 0, end = sourceBuffer.Count; i < end; i++)
{
var closestOrganelle = FindClosestOrganelles(sourceBuffer[i]);
var closestOrganelle = FindClosestOrganelleInRange(sourceBuffer[i], 3f);
if (closestOrganelle ==
new Vector2(INVALID_FOUND_ORGANELLE, INVALID_FOUND_ORGANELLE))
{
targetBuffer[i] = (sourceBuffer[(end + i - 1) % end] + sourceBuffer[(i + 1) % end]) / 2;
var distantOrganelle = FindCenterOfOrganellesInRange(sourceBuffer[i], 5f);

var midpoint = (sourceBuffer[(end + i - 1) % end] + sourceBuffer[(i + 1) % end]) / 2;

if (distantOrganelle == sourceBuffer[i])
{
targetBuffer[i] = midpoint;
}
else
{
var movementDirection = movementFunc(sourceBuffer[i], distantOrganelle + distantOrganelle + midpoint / 3);

targetBuffer[i] = new Vector2(sourceBuffer[i].x - movementDirection.x,
sourceBuffer[i].y - movementDirection.y);
}
}
else
{
Expand Down
4 changes: 3 additions & 1 deletion src/microbe_stage/Microbe.Contact.cs
Expand Up @@ -419,7 +419,9 @@ public void SendOrganellePositionsToMembrane()
foreach (var entry in organelles.Organelles)
{
var cartesian = Hex.AxialToCartesian(entry.Position);
organellePositions.Add(new Vector2(cartesian.x, cartesian.z));
organellePositions
.AddRange(entry.Definition.Hexes
.Select(x => new Vector2(Hex.AxialToCartesian(x).x, Hex.AxialToCartesian(x).z) + new Vector2(cartesian.x, cartesian.z)));
}

Membrane.OrganellePositions = organellePositions;
Expand Down