Exemple #1
0
    protected override void OnPositionChanged(Quat rotation, float angle,
                                              Vector3 membraneCoords)
    {
        organelle.OrganelleGraphics.Transform = new Transform(rotation, membraneCoords);

        Vector3 middle = Hex.AxialToCartesian(new Hex(0, 0));
        Vector3 membranePointDirection = (membraneCoords - middle).Normalized();

        membraneCoords += membranePointDirection * Constants.DEFAULT_HEX_SIZE * 2;

        if (organelle.ParentMicrobe.Species.IsBacteria)
        {
            membraneCoords *= 0.5f;
        }

        var physicsRotation = MathUtils.CreateRotationForPhysicsOrganelle(angle);
        var parentMicrobe   = currentShapesParent;

        if (parentMicrobe.Colony != null && !NeedsUpdateAnyway())
        {
            // Get the real position of the pilus while in the colony
            membraneCoords  = organelle.RotatedPositionInsideColony(membraneCoords);
            membraneCoords += parentMicrobe.GetOffsetRelativeToMaster();
        }

        var transform = new Transform(physicsRotation, membraneCoords);

        if (NeedsUpdateAnyway())
        {
            CreateShape(parentMicrobe);
        }

        currentShapesParent.ShapeOwnerSetTransform(addedChildShapes[0], transform);
    }
Exemple #2
0
    public virtual void Update(float elapsed)
    {
        // TODO: it would be nicer if this were notified when the
        // membrane changes to not recheck this constantly

        Vector3 middle         = Hex.AxialToCartesian(new Hex(0, 0));
        var     delta          = middle - organellePos;
        Vector3 exit           = middle - delta;
        var     membraneCoords = organelle.ParentMicrobe.Membrane.GetExternalOrganelle(exit.x,
                                                                                       exit.z);

        if (!membraneCoords.Equals(lastCalculatedPos) || NeedsUpdateAnyway())
        {
            float angle = Mathf.Atan2(-delta.z, delta.x);
            if (angle < 0)
            {
                angle = angle + (2 * Mathf.Pi);
            }

            angle = (angle * 180 / Mathf.Pi - 90) % 360;

            var rotation = MathUtils.CreateRotationForExternal(angle);

            OnPositionChanged(rotation, angle, membraneCoords);

            lastCalculatedPos = membraneCoords;
        }
    }
Exemple #3
0
    public static float CalculateSpeed(IEnumerable <OrganelleTemplate> organelles, MembraneType membraneType,
                                       float membraneRigidity)
    {
        float microbeMass = Constants.MICROBE_BASE_MASS;

        float organelleMovementForce = 0;

        Vector3 forwardsDirection = new Vector3(0, 0, -1);

        foreach (var organelle in organelles)
        {
            microbeMass += organelle.Definition.Mass;

            if (organelle.Definition.HasComponentFactory <MovementComponentFactory>())
            {
                Vector3 organelleDirection = (Hex.AxialToCartesian(new Hex(0, 0))
                                              - Hex.AxialToCartesian(organelle.Position)).Normalized();

                float directionFactor = organelleDirection.Dot(forwardsDirection);

                organelleMovementForce += Constants.FLAGELLA_BASE_FORCE
                                          * organelle.Definition.Components.Movement.Momentum / 100.0f
                                          * directionFactor;
            }
        }

        float baseMovementForce = Constants.CELL_BASE_THRUST *
                                  (membraneType.MovementFactor - membraneRigidity * Constants.MEMBRANE_RIGIDITY_MOBILITY_MODIFIER);

        float finalSpeed = (baseMovementForce + organelleMovementForce) / microbeMass;

        return(finalSpeed);
    }
Exemple #4
0
    public void OnAttachToCell(PlacedOrganelle organelle)
    {
        this.organelle = organelle;
        organellePos   = Hex.AxialToCartesian(organelle.Position);

        CustomAttach();
    }
Exemple #5
0
    public virtual void Update(float elapsed)
    {
        // TODO: it would be nicer if this were notified when the
        // membrane changes to not recheck this constantly

        Vector3 middle = Hex.AxialToCartesian(new Hex(0, 0));
        var     relativeOrganellePosition = middle - organellePos;

        if (relativeOrganellePosition == Vector3.Zero)
        {
            relativeOrganellePosition = DefaultVisualPos;
        }

        Vector3 exit           = middle - relativeOrganellePosition;
        var     membraneCoords = organelle.ParentMicrobe.Membrane.GetVectorTowardsNearestPointOfMembrane(exit.x,
                                                                                                         exit.z);

        if (!membraneCoords.Equals(lastCalculatedPosition) || NeedsUpdateAnyway())
        {
            float angle = GetAngle(relativeOrganellePosition);

            var rotation = MathUtils.CreateRotationForExternal(angle);

            OnPositionChanged(rotation, angle, membraneCoords);

            lastCalculatedPosition = membraneCoords;
        }
    }
Exemple #6
0
    /// <summary>
    ///   Calculate the momentum of the movement organelle based on
    ///   angle towards middle of cell
    /// </summary>
    private static Vector3 CalculateForce(Hex pos, float momentum)
    {
        Vector3 organelle = Hex.AxialToCartesian(pos);
        Vector3 middle    = Hex.AxialToCartesian(new Hex(0, 0));
        var     delta     = middle - organelle;

        return(delta.Normalized() * momentum);
    }
Exemple #7
0
    protected override void OnPositionChanged(Quat rotation, float angle,
                                              Vector3 membraneCoords)
    {
        organelle.OrganelleGraphics.Transform = new Transform(rotation, membraneCoords);

        Vector3 middle = Hex.AxialToCartesian(new Hex(0, 0));
        Vector3 membranePointDirection = (membraneCoords - middle).Normalized();

        membraneCoords += membranePointDirection * Constants.DEFAULT_HEX_SIZE * 2;

        if (organelle.ParentMicrobe.Species.IsBacteria)
        {
            membraneCoords *= 0.5f;
        }

        float pilusSize = 4.6f;

        // Scale the size down for bacteria
        if (organelle.ParentMicrobe.Species.IsBacteria)
        {
            pilusSize *= 0.5f;
        }

        var physicsRotation = MathUtils.CreateRotationForPhysicsOrganelle(angle);

        // Need to remove the old copy first
        DestroyShape();

        // TODO: Godot doesn't have Cone shape.
        // https://github.com/godotengine/godot-proposals/issues/610
        // So this uses a cylinder for now

        // @pilusShape = organelle.world.GetPhysicalWorld().CreateCone(pilusSize / 10.f,
        //     pilusSize);

        var shape = new CylinderShape();

        shape.Radius = pilusSize / 10.0f;
        shape.Height = pilusSize;

        var parentMicrobe = organelle.ParentMicrobe;

        var ownerId = parentMicrobe.CreateShapeOwner(shape);

        parentMicrobe.ShapeOwnerAddShape(ownerId, shape);

        // TODO: find a way to pass the information to the shape /
        // parentMicrobe what is a pilus part of the collision
        // pilusShape.SetCustomTag(PHYSICS_PILUS_TAG);

        var transform = new Transform(physicsRotation, membraneCoords);

        parentMicrobe.ShapeOwnerSetTransform(ownerId, transform);

        parentMicrobe.AddPilus(ownerId);
        addedChildShapes.Add(ownerId);
    }
Exemple #8
0
    /// <summary>
    ///   Calculate the momentum of the movement organelle based on
    ///   angle towards middle of cell
    ///   If the flagella is placed in the microbe's center, hence delta equals 0,
    ///   consider defaultPos as the organelle's "false" position.
    /// </summary>
    private static Vector3 CalculateForce(Hex pos, float momentum)
    {
        Vector3 organellePosition = Hex.AxialToCartesian(pos);
        Vector3 middle            = Hex.AxialToCartesian(new Hex(0, 0));
        var     delta             = middle - organellePosition;

        if (delta == Vector3.Zero)
        {
            delta = DefaultVisualPos;
        }
        return(delta.Normalized() * momentum);
    }
Exemple #9
0
    public Vector3 CalculateCenterOffset()
    {
        var offset = new Vector3(0, 0, 0);

        foreach (var hex in Hexes)
        {
            offset += Hex.AxialToCartesian(hex);
        }

        offset /= Hexes.Count;
        return(offset);
    }
Exemple #10
0
    private void SetupOrganelleGraphics()
    {
        var organelleSceneInstance = (Spatial)Definition.LoadedScene.Instance();

        // Store the material of the organelle to be updated
        GeometryInstance geometry;

        // Fetch the actual model from the scene to get at the material we set the tint on
        if (string.IsNullOrEmpty(Definition.DisplaySceneModelPath))
        {
            geometry = (GeometryInstance)organelleSceneInstance;
        }
        else
        {
            geometry = organelleSceneInstance.GetNode <GeometryInstance>(Definition.DisplaySceneModelPath);
        }

        // Store animation player for later use
        if (!string.IsNullOrEmpty(Definition.DisplaySceneAnimation))
        {
            OrganelleAnimation = organelleSceneInstance.GetNode <AnimationPlayer>(Definition.DisplaySceneAnimation);
        }

        organelleMaterial = (ShaderMaterial)geometry.MaterialOverride;

        // There is an intermediate node so that the organelle scene root rotation and scale work
        OrganelleGraphics = new Spatial();
        OrganelleGraphics.AddChild(organelleSceneInstance);

        AddChild(OrganelleGraphics);

        OrganelleGraphics.Scale = new Vector3(Constants.DEFAULT_HEX_SIZE, Constants.DEFAULT_HEX_SIZE,
                                              Constants.DEFAULT_HEX_SIZE);

        // Position the intermediate node relative to origin of cell
        var transform = new Transform(Quat.Identity,
                                      Hex.AxialToCartesian(Position) + Definition.CalculateModelOffset());

        OrganelleGraphics.Transform = transform;

        // For some reason MathUtils.CreateRotationForOrganelle(Orientation) in the above transform doesn't work
        OrganelleGraphics.RotateY((Orientation * -60) * MathUtils.DEGREES_TO_RADIANS);
    }
Exemple #11
0
    public static Vector3 GetVector(int orientation)
    {
        Hex hex0 = new Hex(0, 0);
        Hex hex1 = new Hex(0, 0);

        if (orientation == 0)
        {
            hex1 = new Hex(0, 1);
        }
        else if (orientation == 5)
        {
            hex1 = new Hex(1, 0);
        }
        else if (orientation == 4)
        {
            hex1 = new Hex(1, -1);
        }
        else if (orientation == 3)
        {
            hex1 = new Hex(0, -1);
        }
        else if (orientation == 2)
        {
            hex1 = new Hex(-1, 0);
        }
        else if (orientation == 1)
        {
            hex1 = new Hex(-1, 1);
        }

        Vector3 hex0v  = Hex.AxialToCartesian(hex0);
        Vector3 hex1v  = Hex.AxialToCartesian(hex1);
        Vector3 hexdif = hex1v - hex0v;

        hexdif = hexdif.Normalized();

        GD.Print("hex dif: (", hexdif.x, ", ", hexdif.y, ", ", hexdif.z, ")");

        return(hexdif);
    }
Exemple #12
0
    /// <summary>
    ///   Calculates a world pos for emitting compounds
    /// </summary>
    private Vector3 CalculateNearbyWorldPosition()
    {
        // The back of the microbe
        var exit           = Hex.AxialToCartesian(new Hex(0, 1));
        var membraneCoords = Membrane.GetVectorTowardsNearestPointOfMembrane(exit.x, exit.z);

        // Get the distance to eject the compounds
        var ejectionDistance = Membrane.EncompassingCircleRadius;

        // The membrane radius doesn't take being bacteria into account
        if (Species.IsBacteria)
        {
            ejectionDistance *= 0.5f;
        }

        float angle = 180;

        // Find the direction the microbe is facing
        var yAxis        = Transform.basis.y;
        var microbeAngle = Mathf.Atan2(yAxis.x, yAxis.y);

        if (microbeAngle < 0)
        {
            microbeAngle += 2 * Mathf.Pi;
        }

        microbeAngle = microbeAngle * 180 / Mathf.Pi;

        // Take the microbe angle into account so we get world relative degrees
        var finalAngle = (angle + microbeAngle) % 360;

        var s = Mathf.Sin(finalAngle / 180 * Mathf.Pi);
        var c = Mathf.Cos(finalAngle / 180 * Mathf.Pi);

        var ejectionDirection = new Vector3(-membraneCoords.x * c + membraneCoords.z * s, 0,
                                            membraneCoords.x * s + membraneCoords.z * c);

        return(Translation + (ejectionDirection * ejectionDistance));
    }
Exemple #13
0
    public float CalculateSpeed()
    {
        float microbeMass = Constants.MICROBE_BASE_MASS;

        float baseMovementForce = 0;
        float organelleMovementForce = 0;

        Vector3 forwardsDirection = new Vector3(0, 0, -1);

        foreach (var organelle in editedMicrobeOrganelles.Organelles)
        {
            microbeMass += organelle.Definition.Mass;

            if (organelle.Definition.HasComponentFactory<MovementComponentFactory>())
            {
                Vector3 organelleDirection = (Hex.AxialToCartesian(new Hex(0, 0))
                 - Hex.AxialToCartesian(organelle.Position)).Normalized();

                float directionFactor = organelleDirection.Dot(forwardsDirection);

                // Flagella pointing backwards don't slow you down
                directionFactor = Math.Max(directionFactor, 0);

                organelleMovementForce += Constants.FLAGELLA_BASE_FORCE
                    * organelle.Definition.Components.Movement.Momentum / 100.0f
                    * directionFactor;
            }
        }

        baseMovementForce = Constants.CELL_BASE_THRUST *
            (Membrane.MovementFactor - Rigidity * Constants.MEMBRANE_RIGIDITY_MOBILITY_MODIFIER);

        float finalSpeed = (baseMovementForce + organelleMovementForce) / microbeMass;

        return finalSpeed;
    }
Exemple #14
0
    /// <summary>
    ///   This destroys and creates again entities to represent all
    ///   the currently placed organelles. Call this whenever
    ///   editedMicrobeOrganelles is changed.
    /// </summary>
    private void UpdateAlreadyPlacedVisuals()
    {
        int nextFreeHex       = 0;
        int nextFreeOrganelle = 0;

        // Build the entities to show the current microbe
        foreach (var organelle in editedMicrobeOrganelles.Organelles)
        {
            foreach (var hex in organelle.RotatedHexes)
            {
                var pos = Hex.AxialToCartesian(hex + organelle.Position);

                if (nextFreeHex >= placedHexes.Count)
                {
                    // New hex needed
                    placedHexes.Add(CreateEditorHex());
                }

                var hexNode = placedHexes[nextFreeHex++];
                hexNode.MaterialOverride = validMaterial;
                hexNode.Translation      = pos;

                hexNode.Visible = true;
            }

            // Model of the organelle
            if (organelle.Definition.DisplayScene != null)
            {
                var pos = Hex.AxialToCartesian(organelle.Position) +
                          organelle.Definition.CalculateModelOffset();

                if (nextFreeOrganelle >= placedModels.Count)
                {
                    // New organelle model needed
                    placedModels.Add(CreateEditorOrganelle());
                }

                var organelleModel = placedModels[nextFreeOrganelle++];

                organelleModel.Transform = new Transform(
                    MathUtils.CreateRotationForOrganelle(1 * organelle.Orientation), pos);

                organelleModel.Scale = new Vector3(Constants.DEFAULT_HEX_SIZE, Constants.DEFAULT_HEX_SIZE,
                                                   Constants.DEFAULT_HEX_SIZE);

                organelleModel.Visible = true;

                UpdateOrganellePlaceHolderScene(organelleModel,
                                                organelle.Definition.DisplayScene);
            }
        }

        // Delete excess entities
        while (nextFreeHex < placedHexes.Count)
        {
            placedHexes[placedHexes.Count - 1].QueueFree();
            placedHexes.RemoveAt(placedHexes.Count - 1);
        }

        while (nextFreeOrganelle < placedModels.Count)
        {
            placedModels[placedModels.Count - 1].QueueFree();
            placedModels.RemoveAt(placedModels.Count - 1);
        }
    }
Exemple #15
0
    /// <summary>
    ///   Called by a microbe when this organelle has been added to it
    /// </summary>
    public void OnAddedToMicrobe(Microbe microbe)
    {
        if (Definition == null)
        {
            throw new Exception("PlacedOrganelle has no definition set");
        }

        if (ParentMicrobe != null)
        {
            throw new InvalidOperationException("PlacedOrganelle is already in a microbe");
        }

        // Store parameters
        ParentMicrobe = microbe;

        // Grab the species colour for us
        Colour = microbe.Species.Colour;

        ParentMicrobe.OrganelleParent.AddChild(this);

        // Graphical display
        if (Definition.LoadedScene != null)
        {
            // There is an intermediate node so that the organelle scene root rotation and scale work
            OrganelleGraphics = new Spatial();
            var organelleSceneInstance = (Spatial)Definition.LoadedScene.Instance();

            AddChild(OrganelleGraphics);

            OrganelleGraphics.Scale = new Vector3(Constants.DEFAULT_HEX_SIZE, Constants.DEFAULT_HEX_SIZE,
                                                  Constants.DEFAULT_HEX_SIZE);

            var transform = new Transform(MathUtils.CreateRotationForOrganelle(Orientation),
                                          Definition.CalculateModelOffset());
            OrganelleGraphics.Transform = transform;

            // Store the material of the organelle to be updated
            GeometryInstance geometry;

            // Fetch the actual model from the scene to get at the material we set the tint on
            if (string.IsNullOrEmpty(Definition.DisplaySceneModelPath))
            {
                geometry = (GeometryInstance)organelleSceneInstance;
            }
            else
            {
                geometry = organelleSceneInstance.GetNode <GeometryInstance>(Definition.DisplaySceneModelPath);
            }

            // Store animation player for later use
            if (!string.IsNullOrEmpty(Definition.DisplaySceneAnimation))
            {
                OrganelleAnimation = organelleSceneInstance.GetNode <AnimationPlayer>(Definition.DisplaySceneAnimation);
            }

            organelleMaterial = (ShaderMaterial)geometry.MaterialOverride;

            OrganelleGraphics.AddChild(organelleSceneInstance);
        }

        // Position relative to origin of cell
        RotateY(Orientation * 60);
        Translation = Hex.AxialToCartesian(Position);

        float hexSize = Constants.DEFAULT_HEX_SIZE;

        // Scale the physics hex size down for bacteria
        if (microbe.Species.IsBacteria)
        {
            hexSize *= 0.5f;
        }

        // Physics
        ParentMicrobe.Mass += Definition.Mass;

        // Add hex collision shapes
        foreach (Hex hex in Definition.GetRotatedHexes(Orientation))
        {
            var shape = new SphereShape();
            shape.Radius = hexSize * 2.0f;

            var ownerId = ParentMicrobe.CreateShapeOwner(shape);

            // This is needed to actually add the shape
            ParentMicrobe.ShapeOwnerAddShape(ownerId, shape);

            // The shape is in our parent so the final position is our
            // offset plus the hex offset
            Vector3 shapePosition = Hex.AxialToCartesian(hex) + Translation;

            // Scale for bacteria physics.
            if (microbe.Species.IsBacteria)
            {
                shapePosition *= 0.5f;
            }

            var transform = new Transform(Quat.Identity, shapePosition);
            ParentMicrobe.ShapeOwnerSetTransform(ownerId, transform);

            shapes.Add(ownerId);
        }

        // Components
        Components = new List <IOrganelleComponent>();

        foreach (var factory in Definition.ComponentFactories)
        {
            var component = factory.Create();

            if (component == null)
            {
                throw new Exception("PlacedOrganelle component factory returned null");
            }

            component.OnAttachToCell(this);

            Components.Add(component);
        }

        ResetGrowth();
    }
Exemple #16
0
    /// <summary>
    ///   Called by a microbe when this organelle has been added to it
    /// </summary>
    public void OnAddedToMicrobe(Microbe microbe)
    {
        if (Definition == null)
        {
            throw new Exception("PlacedOrganelle has no definition set");
        }

        if (ParentMicrobe != null)
        {
            throw new InvalidOperationException("PlacedOrganelle is already in a microbe");
        }

        // Store parameters
        ParentMicrobe = microbe;

        // Grab the species colour for us
        Colour = microbe.Species.Colour;

        ParentMicrobe.OrganelleParent.AddChild(this);

        // Graphical display
        if (Definition.LoadedScene != null)
        {
            SetupOrganelleGraphics();
        }

        float hexSize = Constants.DEFAULT_HEX_SIZE;

        // Scale the physics hex size down for bacteria
        if (microbe.Species.IsBacteria)
        {
            hexSize *= 0.5f;
        }

        // Physics
        ParentMicrobe.Mass += Definition.Mass;

        // Add hex collision shapes
        foreach (Hex hex in Definition.GetRotatedHexes(Orientation))
        {
            var shape = new SphereShape();
            shape.Radius = hexSize * 2.0f;

            var ownerId = ParentMicrobe.CreateShapeOwner(shape);

            // This is needed to actually add the shape
            ParentMicrobe.ShapeOwnerAddShape(ownerId, shape);

            // The shape is in our parent so the final position is our
            // offset plus the hex offset
            Vector3 shapePosition = Hex.AxialToCartesian(hex) + Translation;

            // Scale for bacteria physics.
            if (microbe.Species.IsBacteria)
            {
                shapePosition *= 0.5f;
            }

            var transform = new Transform(Quat.Identity, shapePosition);
            ParentMicrobe.ShapeOwnerSetTransform(ownerId, transform);

            shapes.Add(ownerId);
        }

        // Components
        Components = new List <IOrganelleComponent>();

        foreach (var factory in Definition.ComponentFactories)
        {
            var component = factory.Create();

            if (component == null)
            {
                throw new Exception("PlacedOrganelle component factory returned null");
            }

            component.OnAttachToCell(this);

            Components.Add(component);
        }

        ResetGrowth();
    }
Exemple #17
0
    /// <summary>
    ///   If not hovering over an organelle, render the to-be-placed organelle
    /// </summary>
    private void RenderHighlightedOrganelle(int q, int r, int rotation)
    {
        if (ActiveActionName == null)
        {
            return;
        }

        // TODO: this should be changed into a function parameter
        var toBePlacedOrganelle = SimulationParameters.Instance.GetOrganelleType(
            ActiveActionName);

        bool showModel = true;

        foreach (var hex in toBePlacedOrganelle.GetRotatedHexes(rotation))
        {
            int posQ = hex.Q + q;
            int posR = hex.R + r;

            var pos = Hex.AxialToCartesian(new Hex(posQ, posR));

            // Detect can it be placed there
            bool canPlace = isPlacementProbablyValid;

            bool duplicate = false;

            // Skip if there is a placed organelle here already
            foreach (var placed in placedHexes)
            {
                if ((pos - placed.Translation).LengthSquared() < 0.001f)
                {
                    duplicate = true;

                    if (!canPlace)
                    {
                        // Mark as invalid
                        placed.MaterialOverride = invalidMaterial;

                        showModel = false;
                    }

                    break;
                }
            }

            if (duplicate)
            {
                continue;
            }

            var hoverHex = hoverHexes[usedHoverHex++];

            hoverHex.Translation = pos;
            hoverHex.Visible     = true;

            hoverHex.MaterialOverride = canPlace ? validMaterial : invalidMaterial;
        }

        // Model
        if (!string.IsNullOrEmpty(toBePlacedOrganelle.DisplayScene) && showModel)
        {
            var cartesianPosition = Hex.AxialToCartesian(new Hex(q, r));

            var organelleModel = hoverOrganelles[usedHoverOrganelle++];

            organelleModel.Transform = new Transform(
                MathUtils.CreateRotationForOrganelle(rotation),
                cartesianPosition + toBePlacedOrganelle.CalculateModelOffset());

            organelleModel.Scale = new Vector3(Constants.DEFAULT_HEX_SIZE, Constants.DEFAULT_HEX_SIZE,
                                               Constants.DEFAULT_HEX_SIZE);

            organelleModel.Visible = true;

            UpdateOrganellePlaceHolderScene(organelleModel, toBePlacedOrganelle.DisplayScene);
        }
    }
Exemple #18
0
 public static Vector3 GetOrganelleDirection(OrganelleTemplate organelle)
 {
     return((Hex.AxialToCartesian(new Hex(0, 0)) - Hex.AxialToCartesian(organelle.Position)).Normalized());
 }