コード例 #1
0
        /// <summary>
        /// Handles the situation where there is a missing vector from the vector field.
        /// </summary>
        /// <param name="selfCell">This unit's current cell.</param>
        /// <param name="vectorField">The vector field.</param>
        /// <param name="input">The steering input.</param>
        /// <param name="output">The steering output.</param>
        private void HandleMissingVectorFromField(Cell selfCell, IVectorField vectorField, SteeringInput input, SteeringOutput output)
        {
            var     unit    = input.unit;
            Vector3 unitPos = unit.position;

            // find all (up to) 8 neighbours
            _neighbours.Clear();
            input.grid.GetConcentricNeighbours(selfCell, 1, _neighbours);

            // sort the neighbours depending on their distance to the unit, i.e. nearest cell neighbours first
            _cellComparer.compareTo = unitPos;
            _neighbours.Sort(_cellComparer);

            // loop through cell neighbours and try to escape to the nearest one that is walkable and has a vector field cell
            int neighboursCount = _neighbours.count;

            for (int i = 0; i < neighboursCount; i++)
            {
                var     neighbour    = _neighbours[i];
                Vector3 neighbourPos = neighbour.position;
                if (neighbour.IsWalkableWithClearance(unit) && vectorField.GetFieldCellAtPos(neighbour).direction.sqrMagnitude != 0f && neighbourPos.y <= unitPos.y)
                {
                    // if the neighbour cell is walkable, has a vector field vector and is at a lower or same height as the unit
                    output.maxAllowedSpeed     = unit.maximumSpeed;
                    output.desiredAcceleration = Seek(neighbourPos, input);
                    return;
                }
            }

            // only request path if we can't find a neighbouring cell to escape to, if there is a valid destination and if the unit is actually movable
            if (unit.isMovable && vectorField.destination != null)
            {
                RequestPath(vectorField.destination.position, input);
            }
        }
コード例 #2
0
        /// <summary>
        /// The first order approximation as seen here (infinitesimal current loop):
        /// https://en.wikipedia.org/wiki/Magnetic_dipole#External_magnetic_field_produced_by_a_magnetic_dipole_moment
        /// The magConstant is also known as the permeability.
        /// Griffiths 5.87
        /// </summary>
        public static IVectorField MagneticDipole(Vector3 magMoment, double magConstant)
        {
            Vector3      constantVectOne = (-magConstant / (4 * Math.PI)) * magMoment;
            IVectorField termOne         = FieldExtensions.SphericalScalarField(1.0, -3).Multiply(constantVectOne);

            double constantTwo = (magConstant / (4 * Math.PI)) * 3;
            Func <Vector3, Vector3> termTwoFunc = r => Math.Pow(r.Magnitude, -5) * (magMoment * r) * r;
            IVectorField            termTwo     = new CustomVectorField(termTwoFunc);

            return(termOne.Add(termTwo));
        }
コード例 #3
0
        /// <summary>
        /// The first order approximation as seen here (infinitesimal seperation):
        /// https://en.wikipedia.org/wiki/Electric_dipole_moment#Potential_and_field_of_an_electric_dipole
        /// The elecConstant is the permitivity
        /// See griffiths 3.104
        /// </summary>
        public static IVectorField ElectricDipole(Vector3 elecMoment, double elecConstant)
        {
            if (elecConstant <= 0)
            {
                throw new ArgumentException(nameof(elecConstant) + " must be positive");
            }
            Vector3      constantVectOne = (-1 / (4 * Math.PI * elecConstant)) * elecMoment;
            IVectorField termOne         = FieldExtensions.SphericalScalarField(1.0, -3).Multiply(constantVectOne);

            double constantTwo = (3 / (4 * Math.PI * elecConstant));
            Func <Vector3, Vector3> termTwoFunc = r => Math.Pow(r.Magnitude, -3) * (elecMoment * r.UnitDirection) * r.UnitDirection;
            IVectorField            termTwo     = new CustomVectorField(termTwoFunc);

            return(termOne.Add(termTwo));
        }
コード例 #4
0
        public void SetPath(IVectorField vectorField)
        {
            Transformer = vectorField.Transformer;
            var length = vectorField.Transformer.GridSize.X * vectorField.Transformer.GridSize.Y;

            if (Vectors == null || Vectors.Length != length)
            {
                Vectors = new Array2D <Vector2>(vectorField.Transformer.GridSize.X, vectorField.Transformer.GridSize.Y);
            }

            for (var i = 0; i < length; i++)
            {
                Vectors[i] = vectorField[i];
            }
        }
コード例 #5
0
        private void CleanupGroup()
        {
            // null vector field and everything else
            _vectorField = null;
            StopInternal();

            // remove the group from load balancer
            NavLoadBalancer.steering.Remove(this);

            if (_modelUnit != null)
            {
                // destroy the model unit
                GameObject.Destroy(_modelUnit.gameObject, 0.1f);
            }
        }
コード例 #6
0
        private void SetVectorFieldPath()
        {
            _stopped          = false;
            this.hasArrived   = false;
            _announcedEndOnce = false;

            if (_vectorField != null)
            {
                // if the group has a vector field, set new path on it
                _vectorField.SetNewPath(_currentPath);
            }
            else
            {
                // if the group does not have a vector field - create one
                _vectorField = GameServices.vectorFieldManager.CreateVectorField(this, _currentPath);
            }
        }
コード例 #7
0
        /// <summary>
        /// Creates a vector field using the VectorFieldOptions exposed on this component.
        /// </summary>
        /// <param name="group">The transient unit group.</param>
        /// <param name="path">The path.</param>
        /// <returns>A new vector field, or null on error</returns>
        public IVectorField CreateVectorField(TransientGroup <IUnitFacade> group, Path path)
        {
            IVectorField newField = null;

            switch (vectorFieldOptions.vectorFieldType)
            {
            case VectorFieldType.FullGridField:
            {
                newField = new FullGridVectorField(group, path, vectorFieldOptions);
                break;
            }

            case VectorFieldType.ProgressiveField:
            {
                newField = new ProgressiveVectorField(group, path, vectorFieldOptions);
                break;
            }

            case VectorFieldType.CrossGridField:
            {
                newField = new CrossGridVectorField(group, path, vectorFieldOptions);
                break;
            }

            default:
            case VectorFieldType.FunnelField:
            {
                newField = new FunnelVectorField(group, path, vectorFieldOptions);
                break;
            }
            }

            if (newField == null)
            {
                return(null);
            }

            newField.Initialize();

            return(newField);
        }
コード例 #8
0
ファイル: Problem.cs プロジェクト: BlueCode2019/fem-net
        public Problem(IFiniteElementSpace finiteElementSpace,
                       Dictionary <int, IVectorField> boundaryConditions,
                       BilinearForm bilinearForm, IVectorField rightHandSide,
                       ISolver solver = null, IQuadrature quadrature = null)
        {
            this.finiteElementSpace = finiteElementSpace;
            this.boundaryConditions = boundaryConditions;

            this.bilinearForm  = bilinearForm;
            this.rightHandSide = rightHandSide;
            var dim      = rightHandSide.Dimension;
            var mismatch = boundaryConditions.Values
                           .Any(condition => condition.Dimension != dim);

            if (mismatch)
            {
                throw new ArgumentException("Dimension mismatched.");
            }
            // TODO: Validate bilinear form.

            this.solver     = solver ?? new ConjugateGradient(1e-6);
            this.quadrature = quadrature ?? new GaussianQuadrature();
        }
コード例 #9
0
 /// <summary>
 /// A basic force field that has no dependence on the object the force is acting on.
 /// </summary>
 public static ForceField BasicForce(IVectorField forceField) => new ForceField(forceField);
コード例 #10
0
 public ClampedVectorField(IVectorField vectorField, Func<Vector3, bool> clampFunction)
 {
     UnderlyingVectorField = vectorField;
     ClampFunction = clampFunction;
 }
コード例 #11
0
 public ProductVectorField(IVectorField origField, double constantMultiplier) : this(origField, () => constantMultiplier)
 {
 }
コード例 #12
0
 public ProductVectorField(IVectorField vectorField, Generator<double> multiplierGen)
 {
     this.multiplierGen = multiplierGen;
     UnderlyingVectorField = vectorField;
 }
コード例 #13
0
 /// <summary>
 /// Adds this vector field to another.
 /// </summary>
 public static SumVectorField Add(this IVectorField f, IVectorField other) => new SumVectorField(f, other);
コード例 #14
0
        /// <summary>
        /// Handles portalling.
        /// </summary>
        /// <param name="unitData">This unit's UnitFacade.</param>
        /// <param name="group">This unit's current/old group.</param>
        /// <param name="vectorField">The vector field.</param>
        /// <param name="pathPortalIndex">Index of the portal in the current path.</param>
        /// <param name="grid">The grid.</param>
        private void HandlePortal(IUnitFacade unitData, DefaultSteeringTransientUnitGroup group, IVectorField vectorField, int pathPortalIndex, IGrid grid)
        {
            var portal = _currentPath[pathPortalIndex] as IPortalNode;
            if (portal == null)
            {
                // if the path node that was reported as a portal turns out not to be - return
                return;
            }

            if (object.ReferenceEquals(unitData, group.modelUnit))
            {
                // don't ever let model unit jump portal
                return;
            }

            int groupCount = group.count;
            var to = _currentPath[pathPortalIndex + 1];

            // we consider a portal a "far portal" when the distance between it and its partner is more than the diagonal cell size
            // 'far portal' means that it is NOT considered a grid stitching connector portal
            // Requires that grid stitching portals are always placed adjacent to each other
            float portalNewGroupThreshold = (grid.cellSize * Consts.SquareRootTwo) + 0.1f;
            bool isFarPortal = (portal.position - portal.partner.position).sqrMagnitude > (portalNewGroupThreshold * portalNewGroupThreshold);

            if (isFarPortal)
            {
                // if it is a far portal, we need to make or use the next group
                if (group.nextGroup == null)
                {
                    // new group does not exist yet, so create it and tell the old group about it
                    var groupStrat = GroupingManager.GetGroupingStrategy<IUnitFacade>();
                    if (groupStrat == null)
                    {
                        Debug.Log("No Grouping Strategy has been registered for IUnitFacade");
                        return;
                    }

                    var newGroup = groupStrat.CreateGroup(groupCount) as DefaultSteeringTransientUnitGroup;
                    if (newGroup == null)
                    {
                        return;
                    }

                    group.nextGroup = newGroup;
                    _nextGroup = newGroup;
                }
                else
                {
                    // new group exists, so just use it
                    _nextGroup = group.nextGroup;
                }

                // make sure to remove the unit from the old group
                group.Remove(unitData);
            }

            _isPortalling = true;
            // actually execute the portal
            portal.Execute(
                unitData.transform,
                to,
                () =>
                {
                    _isPortalling = false;

                    if (isFarPortal)
                    {
                        // if it is a far portal, we are supposed to join up with the new group
                        _nextGroup.Add(unitData);
                        unitData.transientGroup = _nextGroup;

                        if (_nextGroup.count == 1)
                        {
                            // let the first unit in the new group be responsible for setting the new group up
                            if (vectorField.destination != null)
                            {
                                // the new group's path starts on the other side of the portal...
                                int pathCount = _currentPath.count;
                                var newPath = new Path(pathCount - (pathPortalIndex + 2));
                                for (int i = pathCount - 1; i >= pathPortalIndex + 2; i--)
                                {
                                    newPath.Push(_currentPath[i]);
                                }

                                // the first member that joins the new group tells the new group to move along the path of the old group
                                Vector3 destination = vectorField.destination.position;
                                if ((to.position - destination).sqrMagnitude > 1f)
                                {
                                    // check though that the destination is not the same as the starting position
                                    _nextGroup.MoveAlong(newPath);
                                }

                                // pass along old group's waypoints to new group
                                if (group.currentWaypoints.count > 0)
                                {
                                    _nextGroup.SetWaypoints(group.currentWaypoints);
                                }

                                // pass along old group's formation to the new group
                                if (group.currentFormation != null)
                                {
                                    _nextGroup.TransferFormation(group.currentFormation, groupCount, group);
                                }
                            }
                        }
                    }
                });
        }
コード例 #15
0
ファイル: ForceField.cs プロジェクト: domisterwoozy/LabBox
 /// <summary>
 /// Directly applies the raw field as a force and applies zero torque.
 /// </summary>
 public ForceField(IVectorField rawField) : this(rawField, ForceFieldFactory.DirectApplier) { }
コード例 #16
0
        private void CleanupGroup()
        {
            // null vector field and everything else
            _vectorField = null;
            StopInternal();

            // remove the group from load balancer
            NavLoadBalancer.steering.Remove(this);

            if (_modelUnit != null)
            {
                // destroy the model unit
                GameObject.Destroy(_modelUnit.gameObject, 0.1f);
            }
        }
コード例 #17
0
 public ForceField(IVectorField rawField, ForceApplicationFunc forApplFunc, ForceApplicationFunc torqueApplFunc)
 {
     RawField              = rawField;
     ForceApplicationFunc  = forApplFunc;
     TorqueApplicationFunc = torqueApplFunc;
 }
コード例 #18
0
 public TranslatedVectorField(IVectorField underlyingVectField, Generator <Vector3> translationGen)
 {
     UnderlyingVectorField = underlyingVectField;
     this.translationGen   = translationGen;
 }
コード例 #19
0
 /// <summary>
 /// Always applies zero torque and applies the specified force.
 /// </summary>
 public ForceField(IVectorField rawField, ForceApplicationFunc applFunc) : this(rawField, applFunc, ForceFieldFactory.NullApplier)
 {
 }
コード例 #20
0
 /// <summary>
 /// Directly applies the raw field as a force and applies zero torque.
 /// </summary>
 public ForceField(IVectorField rawField) : this(rawField, ForceFieldFactory.DirectApplier)
 {
 }
コード例 #21
0
 public static ForceField Drag(IVectorField windField) => new ForceField(windField, DragForceApplier);
コード例 #22
0
 public SumVectorField(IVectorField a, IVectorField b)
 {
     A = a;
     B = b;
 }
コード例 #23
0
ファイル: ForceField.cs プロジェクト: domisterwoozy/LabBox
 /// <summary>
 /// Always applies zero torque and applies the specified force.
 /// </summary>
 public ForceField(IVectorField rawField, ForceApplicationFunc applFunc) : this(rawField, applFunc, ForceFieldFactory.NullApplier) { }
コード例 #24
0
        private void SetVectorFieldPath()
        {
            _stopped = false;
            this.hasArrived = false;
            _announcedEndOnce = false;

            if (_vectorField != null)
            {
                // if the group has a vector field, set new path on it
                _vectorField.SetNewPath(_currentPath);
            }
            else
            {
                // if the group does not have a vector field - create one
                _vectorField = GameServices.vectorFieldManager.CreateVectorField(this, _currentPath);
            }
        }
コード例 #25
0
 public ClampedVectorField(IVectorField vectorField, Func <Vector3, bool> clampFunction)
 {
     UnderlyingVectorField = vectorField;
     ClampFunction         = clampFunction;
 }
コード例 #26
0
 /// <summary>
 /// Returns a new vector field with the origin moved to a specified position.
 /// </summary>
 public static TranslatedVectorField Translate(this IVectorField f, Vector3 translation) => new TranslatedVectorField(f, () => translation);
コード例 #27
0
 /// <summary>
 /// Multiplies this vector field by a constant value.
 /// </summary>
 public static ProductVectorField Multiply(this IVectorField f, double mult) => new ProductVectorField(f, mult);
コード例 #28
0
 /// <summary>
 /// Returns a new vector field that is 'clamped' outside a specified volume of influence.
 /// When clamped the value of the field is zero.
 /// </summary>
 public static ClampedVectorField Clamp(this IVectorField f, Func <Vector3, bool> clampFunction) => new ClampedVectorField(f, clampFunction);
コード例 #29
0
 public ProductVectorField(IVectorField origField, double constantMultiplier) : this(origField, () => constantMultiplier) { }
コード例 #30
0
        /// <summary>
        /// Handles the situation where there is a missing vector from the vector field.
        /// </summary>
        /// <param name="selfCell">This unit's current cell.</param>
        /// <param name="vectorField">The vector field.</param>
        /// <param name="input">The steering input.</param>
        /// <param name="output">The steering output.</param>
        private void HandleMissingVectorFromField(Cell selfCell, IVectorField vectorField, SteeringInput input, SteeringOutput output)
        {
            var unit = input.unit;
            Vector3 unitPos = unit.position;

            // find all (up to) 8 neighbours
            _neighbours.Clear();
            input.grid.GetConcentricNeighbours(selfCell, 1, _neighbours);

            // sort the neighbours depending on their distance to the unit, i.e. nearest cell neighbours first
            _cellComparer.compareTo = unitPos;
            _neighbours.Sort(_cellComparer);

            // loop through cell neighbours and try to escape to the nearest one that is walkable and has a vector field cell
            int neighboursCount = _neighbours.count;
            for (int i = 0; i < neighboursCount; i++)
            {
                var neighbour = _neighbours[i];
                Vector3 neighbourPos = neighbour.position;
                if (neighbour.isWalkable(unit.attributes) && vectorField.GetFieldCellAtPos(neighbour).direction.sqrMagnitude != 0f && neighbourPos.y <= unitPos.y)
                {
                    // if the neighbour cell is walkable, has a vector field vector and is at a lower or same height as the unit
                    output.maxAllowedSpeed = unit.maximumSpeed;
                    output.desiredAcceleration = Seek(neighbourPos, input);
                    return;
                }
            }

            // only request path if we can't find a neighbouring cell to escape to, if there is a valid destination and if the unit is actually movable
            if (unit.isMovable && vectorField.destination != null)
            {
                RequestPath(vectorField.destination.position, input);
            }
        }
コード例 #31
0
 /// <summary>
 /// Returns a new vector field with the origin moved by a specified generation function.
 /// </summary>
 public static TranslatedVectorField Translate(this IVectorField f, Generator <Vector3> translation) => new TranslatedVectorField(f, translation);
コード例 #32
0
 public ProductVectorField(IVectorField vectorField, Generator <double> multiplierGen)
 {
     this.multiplierGen    = multiplierGen;
     UnderlyingVectorField = vectorField;
 }
コード例 #33
0
 public SumVectorField(IVectorField a, IVectorField b)
 {
     A = a;
     B = b;
 }
コード例 #34
0
ファイル: ForceField.cs プロジェクト: domisterwoozy/LabBox
 public ForceField(IVectorField rawField, ForceApplicationFunc forApplFunc, ForceApplicationFunc torqueApplFunc)
 {
     RawField = rawField;
     ForceApplicationFunc = forApplFunc;
     TorqueApplicationFunc = torqueApplFunc;
 }
コード例 #35
0
 public TranslatedVectorField(IVectorField underlyingVectField, Generator<Vector3> translationGen)
 {
     UnderlyingVectorField = underlyingVectField;
     this.translationGen = translationGen;
 }
コード例 #36
0
        /// <summary>
        /// Handles portalling.
        /// </summary>
        /// <param name="unitData">This unit's UnitFacade.</param>
        /// <param name="group">This unit's current/old group.</param>
        /// <param name="vectorField">The vector field.</param>
        /// <param name="pathPortalIndex">Index of the portal in the current path.</param>
        /// <param name="grid">The grid.</param>
        private void HandlePortal(IUnitFacade unitData, DefaultSteeringTransientUnitGroup group, IVectorField vectorField, int pathPortalIndex, IGrid grid)
        {
            var portal = _currentPath[pathPortalIndex] as IPortalNode;

            if (portal == null)
            {
                // if the path node that was reported as a portal turns out not to be - return
                return;
            }

            if (object.ReferenceEquals(unitData, group.modelUnit))
            {
                // don't ever let model unit jump portal
                return;
            }

            int groupCount = group.count;
            var to         = _currentPath[pathPortalIndex + 1];

            // we consider a portal a "far portal" when the distance between it and its partner is more than the diagonal cell size
            // 'far portal' means that it is NOT considered a grid stitching connector portal
            // Requires that grid stitching portals are always placed adjacent to each other
            float portalNewGroupThreshold = (grid.cellSize * Consts.SquareRootTwo) + 0.1f;
            bool  isFarPortal             = (portal.position - portal.partner.position).sqrMagnitude > (portalNewGroupThreshold * portalNewGroupThreshold);

            if (isFarPortal)
            {
                // if it is a far portal, we need to make or use the next group
                if (group.nextGroup == null)
                {
                    // new group does not exist yet, so create it and tell the old group about it
                    var groupStrat = GroupingManager.GetGroupingStrategy <IUnitFacade>();
                    if (groupStrat == null)
                    {
                        Debug.Log("No Grouping Strategy has been registered for IUnitFacade");
                        return;
                    }

                    var newGroup = groupStrat.CreateGroup(groupCount) as DefaultSteeringTransientUnitGroup;
                    if (newGroup == null)
                    {
                        return;
                    }

                    group.nextGroup = newGroup;
                    _nextGroup      = newGroup;
                }
                else
                {
                    // new group exists, so just use it
                    _nextGroup = group.nextGroup;
                }

                // make sure to remove the unit from the old group
                group.Remove(unitData);
            }

            _isPortalling = true;
            // actually execute the portal
            portal.Execute(
                unitData.transform,
                to,
                () =>
            {
                _isPortalling = false;

                if (isFarPortal)
                {
                    // if it is a far portal, we are supposed to join up with the new group
                    _nextGroup.Add(unitData);
                    unitData.transientGroup = _nextGroup;

                    if (_nextGroup.count == 1)
                    {
                        // let the first unit in the new group be responsible for setting the new group up
                        if (vectorField.destination != null)
                        {
                            // the new group's path starts on the other side of the portal...
                            int pathCount = _currentPath.count;
                            var newPath   = new Path(pathCount - (pathPortalIndex + 2));
                            for (int i = pathCount - 1; i >= pathPortalIndex + 2; i--)
                            {
                                newPath.Push(_currentPath[i]);
                            }

                            // the first member that joins the new group tells the new group to move along the path of the old group
                            Vector3 destination = vectorField.destination.position;
                            if ((to.position - destination).sqrMagnitude > 1f)
                            {
                                // check though that the destination is not the same as the starting position
                                _nextGroup.MoveAlong(newPath);
                            }

                            // pass along old group's waypoints to new group
                            if (group.currentWaypoints.count > 0)
                            {
                                _nextGroup.SetWaypoints(group.currentWaypoints);
                            }

                            // pass along old group's formation to the new group
                            if (group.currentFormation != null)
                            {
                                _nextGroup.TransferFormation(group.currentFormation, groupCount, group);
                            }
                        }
                    }
                }
            });
        }
コード例 #37
0
ファイル: ForceField.cs プロジェクト: domisterwoozy/LabBox
 /// <summary>
 /// A basic force field that has no dependence on the object the force is acting on.
 /// </summary>
 public static ForceField BasicForce(IVectorField forceField) => new ForceField(forceField);
コード例 #38
0
 /// <summary>
 /// Adds this vector field to another.
 /// </summary>
 public static SumVectorField Add(this IVectorField f, IVectorField other) => new SumVectorField(f, other);
コード例 #39
0
ファイル: ForceField.cs プロジェクト: domisterwoozy/LabBox
 public static ForceField Drag(IVectorField windField) => new ForceField(windField, DragForceApplier);