Skip to content

Commit

Permalink
Improved membranes (#74)
Browse files Browse the repository at this point in the history
* allow concave membranes
  • Loading branch information
adQuid committed Jan 6, 2023
1 parent 59810e3 commit 8df5aa0
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 31 deletions.
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

0 comments on commit 8df5aa0

Please sign in to comment.