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

Corrected rotation in colonies #2461

Merged
merged 15 commits into from Aug 19, 2021
7 changes: 5 additions & 2 deletions src/microbe_stage/Membrane.cs
Expand Up @@ -220,17 +220,20 @@ public bool Contains(float x, float y)
}

/// <summary>
/// Finds the position of external organelles based on its "internal" location.
/// Finds the point on the membrane nearest to the given point.
/// </summary>
/// <remarks>
/// <para>
/// Used for finding out where to put an external organelle.
/// </para>
/// <para>
/// The returned Vector is in world coordinates (x, 0, z) and
/// not in internal membrane coordinates (x, y, 0). This is so
/// that gameplay code doesn't have to do the conversion
/// everywhere this is used.
/// </para>
/// </remarks>
public Vector3 GetExternalOrganelle(float x, float y)
public Vector3 GetVectorTowardsNearestPointOfMembrane(float x, float y)
{
// Calculate now if dirty to make flagella positioning only have to be done once
// NOTE: that flagella position should only be read once all organelles that are
Expand Down
66 changes: 54 additions & 12 deletions src/microbe_stage/Microbe.cs
Expand Up @@ -1429,23 +1429,65 @@ private void OnIGotAddedToColony()
if (ColonyParent == null)
return;

var oldRotation = Rotation;
var vectorToParent = GlobalTransform.origin - ColonyParent.GlobalTransform.origin;
var newTransform = GetNewRelativeTransform();

Rotation = newTransform.rotation;
Translation = newTransform.translation;

ChangeNodeParent(ColonyParent);
}

/// <summary>
/// This method calculates the relative rotation and translation this microbe should have to its microbe parent.
/// <a href="https://randomthrivefiles.b-cdn.net/documentation/fixed_colony_rotation_explanation_image.png">
/// Visual explanation
/// </a>
/// </summary>
/// <remarks>
/// <para>
/// Storing the old global translation and rotation, re-parenting and then reapplying the stored values is
/// worse than this code because this code utilizes GetVectorTowardsNearestPointOfMembrane. This reduces the
FuJa0815 marked this conversation as resolved.
Show resolved Hide resolved
/// visual gap between the microbes in a colony.
/// </para>
/// </remarks>
/// <returns>Returns relative translation and rotation</returns>
private (Vector3 translation, Vector3 rotation) GetNewRelativeTransform()
{
// Gets the global rotation of the parent
var globalParentRotation = ColonyParent.GlobalTransform.basis.GetEuler();

// A vector from the parent to me
var vectorFromParent = GlobalTransform.origin - ColonyParent.GlobalTransform.origin;

// A vector from me to the parent
var vectorToParent = -vectorFromParent;

// TODO: using quaternions here instead of assuming that rotating about the up/down axis is right would be nice
// This vector represents the vectorToParent as if I had no rotation.
// This works by rotating vectorToParent by the negative value (therefore Down) of my current rotation
// This is important, because GetVectorTowardsNearestPointOfMembrane only works with non-rotated microbes
var vectorToParentWithoutRotation = vectorToParent.Rotated(Vector3.Down, Rotation.y);
hhyyrylainen marked this conversation as resolved.
Show resolved Hide resolved

var vectorToParentRotated = vectorToParent.Rotated(Vector3.Down, Rotation.y);
var vectorToMembrane = Membrane.GetExternalOrganelle(vectorToParentRotated.x, vectorToParentRotated.y);
// This vector represents the vectorFromParent as if the parent had no rotation.
var vectorFromParentWithoutRotation = vectorFromParent.Rotated(Vector3.Down, globalParentRotation.y);

vectorToParentRotated = (-vectorToParent).Rotated(Vector3.Down, ColonyParent.Rotation.y);
var parentVectorToItsMembrane =
ColonyParent.Membrane.GetExternalOrganelle(vectorToParentRotated.x, vectorToParentRotated.y);
// Calculates the vector from the center of the parent's membrane towards me with canceled out rotation.
// This gets added to the vector calculated one call before.
var correctedVectorFromParent = ColonyParent.Membrane
.GetVectorTowardsNearestPointOfMembrane(vectorFromParentWithoutRotation.x,
vectorFromParentWithoutRotation.z).Rotated(Vector3.Up, globalParentRotation.y);

var requiredDistance = vectorToMembrane.Length() + parentVectorToItsMembrane.Length();
// Calculates the vector from my center to my membrane towards the parent.
// This vector gets rotated back to cancel out the rotation applied two calls above.
// -= to negate the vector, so that the two membrane vectors amplify
correctedVectorFromParent -= Membrane
.GetVectorTowardsNearestPointOfMembrane(vectorToParentWithoutRotation.x, vectorToParentWithoutRotation.z)
.Rotated(Vector3.Up, Rotation.y);

var offset = vectorToParent.Normalized() * requiredDistance;
// Rotated because the rotational scope is different.
var newTranslation = correctedVectorFromParent.Rotated(Vector3.Down, globalParentRotation.y);

Rotation = oldRotation - ColonyParent.Rotation;
Translation = offset.Rotated(Vector3.Down, ColonyParent.Rotation.y);
return (newTranslation, Rotation - globalParentRotation);
}

private void SetScaleFromSpecies()
Expand Down Expand Up @@ -2257,7 +2299,7 @@ private Vector3 CalculateNearbyWorldPosition()
{
// The back of the microbe
var exit = Hex.AxialToCartesian(new Hex(0, 1));
var membraneCoords = Membrane.GetExternalOrganelle(exit.x, exit.z);
var membraneCoords = Membrane.GetVectorTowardsNearestPointOfMembrane(exit.x, exit.z);

// Get the distance to eject the compounds
var ejectionDistance = Membrane.EncompassingCircleRadius;
Expand Down
Expand Up @@ -40,7 +40,7 @@ public virtual void Update(float elapsed)
Vector3 middle = Hex.AxialToCartesian(new Hex(0, 0));
var delta = middle - organellePos;
Vector3 exit = middle - delta;
var membraneCoords = organelle.ParentMicrobe.Membrane.GetExternalOrganelle(exit.x,
var membraneCoords = organelle.ParentMicrobe.Membrane.GetVectorTowardsNearestPointOfMembrane(exit.x,
exit.z);

if (!membraneCoords.Equals(lastCalculatedPosition) || NeedsUpdateAnyway())
Expand Down