Ejemplo n.º 1
0
        /// <summary>
        ///     Creates a reflection matrix that reflects along a line defined by two vectors.
        /// </summary>
        /// <param name="to">The first point defining the line to reflect along.</param>
        /// <param name="from">The second point defining the line to reflect along.</param>
        /// <returns>The reflection matrix.</returns>
        public static Matrix3x2 CreateReflection(Vector2 to, Vector2 from)
        {
            Vector2 v2 = to * to;

            float xy2 = 2 * to.X * to.Y;
            if (@from == default(Vector2))
                return new Matrix3x2(v2.X - v2.Y, xy2, xy2, v2.Y - v2.X, 0, 0) * (1 / to.LengthSquared());

            return Matrix3x2.CreateTranslation(-@from)
                   * (new Matrix3x2(v2.X - v2.Y, xy2, xy2, v2.Y - v2.X, 0, 0) * (1 / to.LengthSquared()))
                   * Matrix3x2.CreateTranslation(@from);
        }
Ejemplo n.º 2
0
 public void ExecuteTest(Operations operation, int innerIterations, Vector2 v1, Vector2 v2)
 {
     Vector2 res;
     switch (operation)
     {
         case Operations.Add_Operator:
             for (int i = 0; i < innerIterations; i++)
             { res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; res = v1 + v2; }
             break;
         case Operations.Add_Function:
             for (int i = 0; i < innerIterations; i++)
             { Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); Vector2.Add(v1, v2); }
             break;
         case Operations.Sub_Operator:
             for (int i = 0; i < innerIterations; i++)
             { res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; res = v1 - v2; }
             break;
         case Operations.Sub_Function:
             for (int i = 0; i < innerIterations; i++)
             { Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); Vector2.Subtract(v1, v2); }
             break;
         case Operations.Mul_Operator:
             for (int i = 0; i < innerIterations; i++)
             { res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; res = v1 * v2; }
             break;
         case Operations.Mul_Function:
             for (int i = 0; i < innerIterations; i++)
             { Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); Vector2.Multiply(v1, v2); }
             break;
         case Operations.Dot:
             for (int i = 0; i < innerIterations; i++)
             { Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); Vector2.Dot(v1, v2); }
             break;
         case Operations.SquareRoot:
             for (int i = 0; i < innerIterations; i++)
             { Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); Vector2.SquareRoot(v1); }
             break;
         case Operations.Length_Squared:
             for (int i = 0; i < innerIterations; i++)
             { v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); v1.LengthSquared(); }
             break;
         case Operations.Normalize:
             for (int i = 0; i < innerIterations; i++)
             { Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); Vector2.Normalize(v1); }
             break;
         case Operations.Distance_Squared:
             for (int i = 0; i < innerIterations; i++)
             { Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); Vector2.DistanceSquared(v1, v2); }
             break;
     }
 }
        public override void Update(InputState inputState, Vector2 origin)
        {
            if (abilityUIs.Count != represented.activatedAbilities.Count)
            {
                UpdateAbilityUIs();
            }

            isBadDrag = false;
            isVisible = represented.zone.zoneId == ConvergeZoneId.Hand ? (represented.zone.owner.isActivePlayer) : true;

            if (!isVisible)
            {
                return;
            }

            isMouseOver = (inputState.hoveringElement == this);
            if (isMouseOver && inputState.mouseLeft.justPressed && represented.controller.isActivePlayer)
            {
                isMousePressing = true;
                mousePressedPos = inputState.MousePos;
            }

            if (isMousePressing && isMouseOver && inputState.mouseLeft.justReleased)
            {
                represented.Play(Game1.activePlayer); // clicked
            }
            if (!inputState.mouseLeft.isDown)
            {
                isMousePressing = false;
            }

            float MINDRAG    = 5;
            float MINDRAGSQR = MINDRAG * MINDRAG;

            if (isDragging)
            {
                Game1.ticking = false;
                if (isMousePressing)
                {
                    this.gfxFrame = new Rectangle((int)inputState.MousePos.X - 25, (int)inputState.MousePos.Y - 30, 50, 60);

                    if (inputState.hoveringElement != null && inputState.hoveringElement is ConvergeUIObject)
                    {
                        isBadDrag = !represented.CanTarget(((ConvergeUIObject)inputState.hoveringElement).represented, represented.controller);
                    }
                }
                else
                {
                    //dragged onto = inputState.hoveringElement
                    if (inputState.hoveringElement != null)
                    {
                        if (inputState.hoveringElement is ConvergeUIObject)
                        {
                            represented.UseOn(((ConvergeUIObject)inputState.hoveringElement).represented);
                        }
                    }
                    else
                    {
                        ConvergeZone currentZone = represented.zone;
                        ConvergeZone attackZone  = represented.controller.attack;
                        ConvergeZone defenseZone = represented.controller.defense;
                        if (currentZone.zoneId == ConvergeZoneId.Defense && attackZone.bounds.Contains(inputState.MousePos))
                        {
                            represented.EnterAttack();
                        }
                        else if (currentZone.zoneId == ConvergeZoneId.Attack && defenseZone.bounds.Contains(inputState.MousePos))
                        {
                            represented.WithdrawAttack();
                        }
                        else if (currentZone.zoneId == ConvergeZoneId.Hand && defenseZone.bounds.Contains(inputState.MousePos))
                        {
                            represented.Play(represented.controller);
                        }
                    }

                    isDragging = false;
                }
            }
            else
            {
                if (isMousePressing && (inputState.MousePos - mousePressedPos).LengthSquared() > MINDRAGSQR)
                {
                    isDragging = true;
                }

                const float MOVESPEED  = 15.0f;
                Vector2     targetPos  = represented.nominalPosition;
                Vector2     moveOffset = targetPos - this.gfxFrame.XY();
                if (moveOffset.LengthSquared() < MOVESPEED * MOVESPEED)
                {
                    this.gfxFrame = new Rectangle(targetPos.ToPoint(), new Point(50, 60));
                }
                else
                {
                    moveOffset.Normalize();
                    this.gfxFrame = new Rectangle((this.gfxFrame.XY() + moveOffset * MOVESPEED).ToPoint(), new Point(50, 60));
                }
            }

            Vector2 offset = new Vector2(this.gfxFrame.Width / 2, 12);

            foreach (ConvergeUIAbility abilityUI in abilityUIs)
            {
                if (abilityUI.isActive)
                {
                    abilityUI.offset = offset;
                    abilityUI.Update(inputState);
                    offset.X += 32.0f;
                }
            }
        }
Ejemplo n.º 4
0
        public void Update(float deltaTime)
        {
            members.RemoveAll(m => m.IsDead || m.Removed);
            if (members.Count < 2)
            {
                return;
            }

            //calculate the "center of mass" of the swarm and the distance to the closest character in the swarm
            float       closestDistSqr = float.MaxValue;
            Vector2     center         = Vector2.Zero;
            AICharacter closest        = null;

            foreach (AICharacter member in members)
            {
                center += member.SimPosition;
                if (member == ai.Character)
                {
                    continue;
                }
                float distSqr = Vector2.DistanceSquared(member.SimPosition, ai.Character.SimPosition);
                if (distSqr < closestDistSqr)
                {
                    closestDistSqr = distSqr;
                    closest        = member;
                }
            }
            center /= members.Count;

            if (closest == null)
            {
                return;
            }

            //steer away from the closest if too close
            float closestDist = (float)Math.Sqrt(closestDistSqr);

            if (closestDist < minDistFromClosest)
            {
                Vector2 diff = closest.SimPosition - ai.SimPosition;
                if (diff.LengthSquared() < 0.0001f)
                {
                    diff = Vector2.UnitX;
                }
                ai.SteeringManager.SteeringManual(deltaTime, -diff);
            }
            //steer closer to the center of mass if too far
            else if (Vector2.DistanceSquared(center, ai.SimPosition) > maxDistFromCenter * maxDistFromCenter)
            {
                float distFromCenter = Vector2.Distance(center, ai.SimPosition);
                ai.SteeringManager.SteeringSeek(center, (distFromCenter - maxDistFromCenter) / 10.0f);
            }

            //keep the characters moving in roughly the same direction
            if (cohesion > 0.0f)
            {
                Vector2 avgVel = Vector2.Zero;
                foreach (AICharacter member in members)
                {
                    avgVel += member.AnimController.TargetMovement;
                }
                avgVel /= members.Count;
                ai.SteeringManager.SteeringManual(deltaTime, avgVel * cohesion);
            }
        }
Ejemplo n.º 5
0
        partial void UpdateNetPlayerPositionProjSpecific(float deltaTime, float lowestSubPos)
        {
            if (character != GameMain.Client.Character || !character.AllowInput)
            {
                //remove states without a timestamp (there may still be ID-based states
                //in the list when the controlled character switches to timestamp-based interpolation)
                character.MemState.RemoveAll(m => m.Timestamp == 0.0f);

                //use simple interpolation for other players' characters and characters that can't move
                if (character.MemState.Count > 0)
                {
                    CharacterStateInfo serverPos = character.MemState.Last();
                    if (!character.isSynced)
                    {
                        SetPosition(serverPos.Position, false);
                        Collider.LinearVelocity = Vector2.Zero;
                        character.MemLocalState.Clear();
                        character.LastNetworkUpdateID = serverPos.ID;
                        character.isSynced            = true;
                        return;
                    }

                    if (character.MemState[0].Interact == null || character.MemState[0].Interact.Removed)
                    {
                        character.DeselectCharacter();
                        character.SelectedConstruction = null;
                    }
                    else if (character.MemState[0].Interact is Character)
                    {
                        character.SelectCharacter((Character)character.MemState[0].Interact);
                    }
                    else if (character.MemState[0].Interact is Item newSelectedConstruction)
                    {
                        if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction)
                        {
                            foreach (var ic in newSelectedConstruction.Components)
                            {
                                if (ic.CanBeSelected)
                                {
                                    ic.Select(character);
                                }
                            }
                        }
                        character.SelectedConstruction = newSelectedConstruction;
                    }

                    if (character.MemState[0].Animation == AnimController.Animation.CPR)
                    {
                        character.AnimController.Anim = AnimController.Animation.CPR;
                    }
                    else if (character.AnimController.Anim == AnimController.Animation.CPR)
                    {
                        character.AnimController.Anim = AnimController.Animation.None;
                    }

                    Vector2 newVelocity        = Collider.LinearVelocity;
                    Vector2 newPosition        = Collider.SimPosition;
                    float   newRotation        = Collider.Rotation;
                    float   newAngularVelocity = Collider.AngularVelocity;
                    Collider.CorrectPosition(character.MemState, out newPosition, out newVelocity, out newRotation, out newAngularVelocity);

                    newVelocity = newVelocity.ClampLength(100.0f);
                    if (!MathUtils.IsValid(newVelocity))
                    {
                        newVelocity = Vector2.Zero;
                    }
                    overrideTargetMovement = newVelocity.LengthSquared() > 0.01f ? newVelocity : Vector2.Zero;

                    Collider.LinearVelocity  = newVelocity;
                    Collider.AngularVelocity = newAngularVelocity;

                    float distSqrd       = Vector2.DistanceSquared(newPosition, Collider.SimPosition);
                    float errorTolerance = character.AllowInput ? 0.01f : 0.1f;
                    if (distSqrd > errorTolerance)
                    {
                        if (distSqrd > 10.0f || !character.AllowInput)
                        {
                            Collider.TargetRotation = newRotation;
                            SetPosition(newPosition, lerp: distSqrd < 1.0f);
                        }
                        else
                        {
                            Collider.TargetRotation = newRotation;
                            Collider.TargetPosition = newPosition;
                            Collider.MoveToTargetPosition(true);
                        }
                    }

                    //unconscious/dead characters can't correct their position using AnimController movement
                    // -> we need to correct it manually
                    if (!character.AllowInput)
                    {
                        MainLimb.PullJointWorldAnchorB = Collider.SimPosition;
                        MainLimb.PullJointEnabled      = true;
                    }
                }
                character.MemLocalState.Clear();
            }
            else
            {
                //remove states with a timestamp (there may still timestamp-based states
                //in the list if the controlled character switches from timestamp-based interpolation to ID-based)
                character.MemState.RemoveAll(m => m.Timestamp > 0.0f);

                for (int i = 0; i < character.MemLocalState.Count; i++)
                {
                    if (character.Submarine == null)
                    {
                        //transform in-sub coordinates to outside coordinates
                        if (character.MemLocalState[i].Position.Y > lowestSubPos)
                        {
                            character.MemLocalState[i].TransformInToOutside();
                        }
                    }
                    else if (currentHull?.Submarine != null)
                    {
                        //transform outside coordinates to in-sub coordinates
                        if (character.MemLocalState[i].Position.Y < lowestSubPos)
                        {
                            character.MemLocalState[i].TransformOutToInside(currentHull.Submarine);
                        }
                    }
                }

                if (character.MemState.Count < 1)
                {
                    return;
                }

                overrideTargetMovement = Vector2.Zero;

                CharacterStateInfo serverPos = character.MemState.Last();

                if (!character.isSynced)
                {
                    SetPosition(serverPos.Position, false);
                    Collider.LinearVelocity = Vector2.Zero;
                    character.MemLocalState.Clear();
                    character.LastNetworkUpdateID = serverPos.ID;
                    character.isSynced            = true;
                    return;
                }

                int localPosIndex = character.MemLocalState.FindIndex(m => m.ID == serverPos.ID);
                if (localPosIndex > -1)
                {
                    CharacterStateInfo localPos = character.MemLocalState[localPosIndex];

                    //the entity we're interacting with doesn't match the server's
                    if (localPos.Interact != serverPos.Interact)
                    {
                        if (serverPos.Interact == null || serverPos.Interact.Removed)
                        {
                            character.DeselectCharacter();
                            character.SelectedConstruction = null;
                        }
                        else if (serverPos.Interact is Character)
                        {
                            character.SelectCharacter((Character)serverPos.Interact);
                        }
                        else
                        {
                            var newSelectedConstruction = (Item)serverPos.Interact;
                            if (newSelectedConstruction != null && character.SelectedConstruction != newSelectedConstruction)
                            {
                                newSelectedConstruction.TryInteract(character, true, true);
                            }
                            character.SelectedConstruction = newSelectedConstruction;
                        }
                    }

                    if (localPos.Animation != serverPos.Animation)
                    {
                        if (serverPos.Animation == AnimController.Animation.CPR)
                        {
                            character.AnimController.Anim = AnimController.Animation.CPR;
                        }
                        else if (character.AnimController.Anim == AnimController.Animation.CPR)
                        {
                            character.AnimController.Anim = AnimController.Animation.None;
                        }
                    }

                    Hull serverHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(serverPos.Position), character.CurrentHull, serverPos.Position.Y < lowestSubPos);
                    Hull clientHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(localPos.Position), serverHull, localPos.Position.Y < lowestSubPos);

                    if (serverHull != null && clientHull != null && serverHull.Submarine != clientHull.Submarine)
                    {
                        //hull subs don't match => teleport the camera to the other sub
                        character.Submarine   = serverHull.Submarine;
                        character.CurrentHull = currentHull = serverHull;
                        SetPosition(serverPos.Position);
                        character.MemLocalState.Clear();
                    }
                    else
                    {
                        Vector2 positionError = serverPos.Position - localPos.Position;
                        float   rotationError = serverPos.Rotation.HasValue && localPos.Rotation.HasValue ?
                                                serverPos.Rotation.Value - localPos.Rotation.Value :
                                                0.0f;

                        for (int i = localPosIndex; i < character.MemLocalState.Count; i++)
                        {
                            Hull pointHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(character.MemLocalState[i].Position), clientHull, character.MemLocalState[i].Position.Y < lowestSubPos);
                            if (pointHull != clientHull && ((pointHull == null) || (clientHull == null) || (pointHull.Submarine == clientHull.Submarine)))
                            {
                                break;
                            }
                            character.MemLocalState[i].Translate(positionError, rotationError);
                        }

                        float errorMagnitude = positionError.Length();
                        if (errorMagnitude > 0.01f)
                        {
                            Collider.TargetPosition = Collider.SimPosition + positionError;
                            Collider.TargetRotation = Collider.Rotation + rotationError;
                            Collider.MoveToTargetPosition(lerp: true);
                            if (errorMagnitude > 0.5f)
                            {
                                character.MemLocalState.Clear();
                                foreach (Limb limb in Limbs)
                                {
                                    limb.body.TargetPosition = limb.body.SimPosition + positionError;
                                    limb.body.MoveToTargetPosition(lerp: true);
                                }
                            }
                        }
                    }
                }

                if (character.MemLocalState.Count > 120)
                {
                    character.MemLocalState.RemoveRange(0, character.MemLocalState.Count - 120);
                }
                character.MemState.Clear();
            }
        }
Ejemplo n.º 6
0
        private Vector2 CalculateSteeringSeek(Vector2 target, float weight, Func <PathNode, bool> startNodeFilter = null, Func <PathNode, bool> endNodeFilter = null, Func <PathNode, bool> nodeFilter = null)
        {
            Vector2 targetDiff = target - currentTarget;

            if (currentPath != null && currentPath.Nodes.Any())
            {
                //current path calculated relative to a different sub than where the character is now
                //take that into account when calculating if the target has moved
                Submarine currentPathSub = currentPath?.Nodes.First().Submarine;
                if (currentPathSub != character.Submarine && character.Submarine != null)
                {
                    Vector2 subDiff = character.Submarine.SimPosition - currentPathSub.SimPosition;
                    targetDiff += subDiff;
                }
            }
            bool needsNewPath = character.Params.PathFinderPriority > 0.5f && (currentPath == null || currentPath.Unreachable || currentPath.Finished || targetDiff.LengthSquared() > 1);

            //find a new path if one hasn't been found yet or the target is different from the current target
            if (needsNewPath || findPathTimer < -1.0f)
            {
                IsPathDirty = true;
                if (findPathTimer > 0.0f)
                {
                    return(Vector2.Zero);
                }
                currentTarget = target;
                Vector2 currentPos = host.SimPosition;
                if (character != null && character.Submarine == null)
                {
                    var targetHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(target), null, false);
                    if (targetHull != null && targetHull.Submarine != null)
                    {
                        currentPos -= targetHull.Submarine.SimPosition;
                    }
                }
                pathFinder.InsideSubmarine = character.Submarine != null;
                var  newPath    = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", startNodeFilter, endNodeFilter, nodeFilter);
                bool useNewPath = currentPath == null || needsNewPath || currentPath.Finished;
                if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
                {
                    // It's possible that the current path was calculated from a start point that is no longer valid.
                    // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
                    useNewPath = newPath.Cost <currentPath.Cost ||
                                               Vector2.DistanceSquared(character.WorldPosition, currentPath.CurrentNode.WorldPosition)> Math.Pow(Vector2.Distance(character.WorldPosition, newPath.Nodes.First().WorldPosition) * 3, 2);
                }
                if (useNewPath)
                {
                    currentPath = newPath;
                }
                float priority = MathHelper.Lerp(3, 1, character.Params.PathFinderPriority);
                findPathTimer = priority * Rand.Range(1.0f, 1.2f);
                IsPathDirty   = false;
                return(DiffToCurrentNode());
            }

            Vector2 diff     = DiffToCurrentNode();
            var     collider = character.AnimController.Collider;
            // Only humanoids can climb ladders
            bool canClimb = character.AnimController is HumanoidAnimController;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (canClimb && !character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }
            if (diff == Vector2.Zero)
            {
                return(Vector2.Zero);
            }
            return(Vector2.Normalize(diff) * weight);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Ray-cast against the proxies in the tree. This relies on the callback
        /// to perform a exact ray-cast in the case were the proxy contains a Shape.
        /// The callback also performs the any collision filtering. This has performance
        /// roughly equal to k * log(n), where k is the number of collisions and n is the
        /// number of proxies in the tree.
        /// </summary>
        /// <param name="callback">A callback class that is called for each proxy that is hit by the ray.</param>
        /// <param name="input">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>
        public void RayCast(Func <RayCastInput, int, float> callback, ref RayCastInput input)
        {
            Vector2 p1 = input.Point1;
            Vector2 p2 = input.Point2;
            Vector2 r  = p2 - p1;

            Debug.Assert(r.LengthSquared() > 0.0f);
            r.Normalize();

            // v is perpendicular to the segment.
            Vector2 absV = MathUtils.Abs(new Vector2(-r.Y, r.X));

            // Separating axis for segment (Gino, p80).
            // |dot(v, p1 - c)| > dot(|v|, h)

            float maxFraction = input.MaxFraction;

            // Build a bounding box for the segment.
            AABB segmentAABB = new AABB();

            {
                Vector2 t = p1 + maxFraction * (p2 - p1);
                Vector2.Min(ref p1, ref t, out segmentAABB.LowerBound);
                Vector2.Max(ref p1, ref t, out segmentAABB.UpperBound);
            }

            _stack.Clear();
            _stack.Push(_root);

            while (_stack.Count > 0)
            {
                int nodeId = _stack.Pop();
                if (nodeId == NullNode)
                {
                    continue;
                }

                TreeNode <T> node = _nodes[nodeId];

                if (AABB.TestOverlap(ref node.AABB, ref segmentAABB) == false)
                {
                    continue;
                }

                // Separating axis for segment (Gino, p80).
                // |dot(v, p1 - c)| > dot(|v|, h)
                Vector2 c          = node.AABB.Center;
                Vector2 h          = node.AABB.Extents;
                float   separation = Math.Abs(Vector2.Dot(new Vector2(-r.Y, r.X), p1 - c)) - Vector2.Dot(absV, h);
                if (separation > 0.0f)
                {
                    continue;
                }

                if (node.IsLeaf())
                {
                    RayCastInput subInput;
                    subInput.Point1      = input.Point1;
                    subInput.Point2      = input.Point2;
                    subInput.MaxFraction = maxFraction;

                    float value = callback(subInput, nodeId);

                    if (value == 0.0f)
                    {
                        // the client has terminated the raycast.
                        return;
                    }

                    if (value > 0.0f)
                    {
                        // Update segment bounding box.
                        maxFraction = value;
                        Vector2 t = p1 + maxFraction * (p2 - p1);
                        segmentAABB.LowerBound = Vector2.Min(p1, t);
                        segmentAABB.UpperBound = Vector2.Max(p1, t);
                    }
                }
                else
                {
                    _stack.Push(node.Child1);
                    _stack.Push(node.Child2);
                }
            }
        }
        public override void Update(float dt)
        {
            Vector2 f = Vector2.Zero;

            foreach (Body worldBody in World.BodyList)
            {
                if (!IsActiveOn(worldBody))
                {
                    continue;
                }

                foreach (Body controllerBody in Bodies)
                {
                    if (worldBody == controllerBody || (worldBody.BodyType == BodyType.Static && controllerBody.BodyType == BodyType.Static) || !controllerBody.Enabled)
                    {
                        continue;
                    }

                    Vector2 d  = controllerBody.Position - worldBody.Position;
                    float   r2 = d.LengthSquared();

                    if (r2 <= Settings.Epsilon || r2 > MaxRadius * MaxRadius || r2 < MinRadius * MinRadius)
                    {
                        continue;
                    }

                    switch (GravityType)
                    {
                    case GravityType.DistanceSquared:
                        f = Strength / r2 * worldBody.Mass * controllerBody.Mass * d;
                        break;

                    case GravityType.Linear:
                        f = Strength / (float)Math.Sqrt(r2) * worldBody.Mass * controllerBody.Mass * d;
                        break;
                    }

                    worldBody.ApplyForce(ref f);
                }

                foreach (Vector2 point in Points)
                {
                    Vector2 d  = point - worldBody.Position;
                    float   r2 = d.LengthSquared();

                    if (r2 <= Settings.Epsilon || r2 > MaxRadius * MaxRadius || r2 < MinRadius * MinRadius)
                    {
                        continue;
                    }

                    switch (GravityType)
                    {
                    case GravityType.DistanceSquared:
                        f = Strength / r2 * worldBody.Mass * d;
                        break;

                    case GravityType.Linear:
                        f = Strength / (float)Math.Sqrt(r2) * worldBody.Mass * d;
                        break;
                    }

                    worldBody.ApplyForce(ref f);
                }
            }
        }
Ejemplo n.º 9
0
        internal override void SolveVelocityConstraints(ref SolverData data)
        {
            Vector2 vA = data.velocities[_indexA].v;
            float wA = data.velocities[_indexA].w;
            Vector2 vB = data.velocities[_indexB].v;
            float wB = data.velocities[_indexB].w;

            float mA = _invMassA, mB = _invMassB;
            float iA = _invIA, iB = _invIB;

            float h = data.step.dt;

            // Solve angular friction
            {
                float Cdot = wB - wA;
                float impulse = -_angularMass * Cdot;

                float oldImpulse = _angularImpulse;
                float maxImpulse = h * MaxTorque;
                _angularImpulse = MathUtils.Clamp(_angularImpulse + impulse, -maxImpulse, maxImpulse);
                impulse = _angularImpulse - oldImpulse;

                wA -= iA * impulse;
                wB += iB * impulse;
            }

            // Solve linear friction
            {
                Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);

                Vector2 impulse = -MathUtils.Mul(ref _linearMass, Cdot);
                Vector2 oldImpulse = _linearImpulse;
                _linearImpulse += impulse;

                float maxImpulse = h * MaxForce;

                if (_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
                {
                    _linearImpulse.Normalize();
                    _linearImpulse *= maxImpulse;
                }

                impulse = _linearImpulse - oldImpulse;

                vA -= mA * impulse;
                wA -= iA * MathUtils.Cross(_rA, impulse);

                vB += mB * impulse;
                wB += iB * MathUtils.Cross(_rB, impulse);
            }

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
            data.velocities[_indexB].v = vB;
            data.velocities[_indexB].w = wB;
        }
Ejemplo n.º 10
0
        private Vector2 CalculateSteeringSeek(Vector2 target, float weight, Func <PathNode, bool> startNodeFilter = null, Func <PathNode, bool> endNodeFilter = null, Func <PathNode, bool> nodeFilter = null, bool checkVisibility = true)
        {
            Vector2 targetDiff = target - currentTarget;

            if (currentPath != null && currentPath.Nodes.Any())
            {
                //current path calculated relative to a different sub than where the character is now
                //take that into account when calculating if the target has moved
                Submarine currentPathSub = currentPath?.Nodes.First().Submarine;
                if (currentPathSub != character.Submarine && character.Submarine != null)
                {
                    Vector2 subDiff = character.Submarine.SimPosition - currentPathSub.SimPosition;
                    targetDiff += subDiff;
                }
            }
            bool needsNewPath = character.Params.PathFinderPriority > 0.5f && (currentPath == null || currentPath.Unreachable || targetDiff.LengthSquared() > 1);

            //find a new path if one hasn't been found yet or the target is different from the current target
            if (needsNewPath || findPathTimer < -1.0f)
            {
                IsPathDirty = true;
                if (findPathTimer < 0)
                {
                    currentTarget = target;
                    Vector2 currentPos = host.SimPosition;
                    if (character != null && character.Submarine == null)
                    {
                        var targetHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(target), null, false);
                        if (targetHull != null && targetHull.Submarine != null)
                        {
                            currentPos -= targetHull.Submarine.SimPosition;
                        }
                    }
                    pathFinder.InsideSubmarine            = character.Submarine != null;
                    pathFinder.ApplyPenaltyToOutsideNodes = character.PressureProtection <= 0;
                    var  newPath    = pathFinder.FindPath(currentPos, target, character.Submarine, "(Character: " + character.Name + ")", startNodeFilter, endNodeFilter, nodeFilter, checkVisibility: checkVisibility);
                    bool useNewPath = needsNewPath || currentPath == null || currentPath.CurrentNode == null || findPathTimer < -1 && Math.Abs(character.AnimController.TargetMovement.X) <= 0;
                    if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
                    {
                        // Check if the new path is the same as the old, in which case we just ignore it and continue using the old path (or the progress would reset).
                        if (IsIdenticalPath())
                        {
                            useNewPath = false;
                        }
                        else
                        {
                            // Use the new path if it has significantly lower cost (don't change the path if it has marginally smaller cost. This reduces navigating backwards due to new path that is calculated from the node just behind us).
                            float t = (float)currentPath.CurrentIndex / (currentPath.Nodes.Count - 1);
                            useNewPath = newPath.Cost < currentPath.Cost * MathHelper.Lerp(0.95f, 0, t);
                            if (!useNewPath)
                            {
                                // It's possible that the current path was calculated from a start point that is no longer valid.
                                // Therefore, let's accept also paths with a greater cost than the current, if the current node is much farther than the new start node.
                                useNewPath = Vector2.DistanceSquared(character.WorldPosition, currentPath.CurrentNode.WorldPosition) > Math.Pow(Vector2.Distance(character.WorldPosition, newPath.Nodes.First().WorldPosition) * 3, 2);
                            }
                        }

                        bool IsIdenticalPath()
                        {
                            int nodeCount = newPath.Nodes.Count;

                            if (nodeCount == currentPath.Nodes.Count)
                            {
                                for (int i = 0; i < nodeCount - 1; i++)
                                {
                                    if (newPath.Nodes[i] != currentPath.Nodes[i])
                                    {
                                        return(false);
                                    }
                                }
                                return(true);
                            }
                            return(false);
                        }
                    }
                    if (useNewPath)
                    {
                        currentPath = newPath;
                    }
                    float priority = MathHelper.Lerp(3, 1, character.Params.PathFinderPriority);
                    findPathTimer = priority * Rand.Range(1.0f, 1.2f);
                    IsPathDirty   = false;
                    return(DiffToCurrentNode());
                }
            }

            Vector2 diff     = DiffToCurrentNode();
            var     collider = character.AnimController.Collider;
            // Only humanoids can climb ladders
            bool canClimb = character.AnimController is HumanoidAnimController;

            //if not in water and the waypoint is between the top and bottom of the collider, no need to move vertically
            if (canClimb && !character.AnimController.InWater && !character.IsClimbing && diff.Y < collider.height / 2 + collider.radius)
            {
                diff.Y = 0.0f;
            }
            if (diff == Vector2.Zero)
            {
                return(Vector2.Zero);
            }
            return(Vector2.Normalize(diff) * weight);
        }
Ejemplo n.º 11
0
        public override void TargetedMovement(Vector2 vectorToTargetPosition)
        {
            if (isStone)
            {
                if (vectorToTargetPosition.Y > 16)
                {
                    gHelper.DropThroughPlatform();
                }
                DoStoneMovement();
                return;
            }
            int     targetAbove = 80;
            Vector2 vectorAbove = vectorToTargetPosition;

            projectile.friendly = false;
            // only check for exact position once close to target
            if (vectorToTargetPosition.LengthSquared() < 256 * 256)
            {
                for (int i = 16; i < targetAbove; i += 8)
                {
                    vectorAbove = new Vector2(vectorToTargetPosition.X, vectorToTargetPosition.Y - i);
                    if (!Collision.CanHit(projectile.Center, 1, 1, projectile.Center + vectorAbove, 1, 1))
                    {
                        break;
                    }
                }
            }
            myTurnToDrop |= Math.Abs(vectorAbove.X) < 64 && IsMyTurn();
            if (myTurnToDrop && Math.Abs(vectorAbove.X) <= 16 && Math.Abs(vectorAbove.Y) <= 16 && animationFrame - stoneStartFrame > 80)
            {
                DoStoneDust();
                isStone         = true;
                myTurnToDrop    = false;
                stoneStartFrame = animationFrame;
                if (targetNPCIndex is int idx && Main.npc[idx].active)
                {
                    //// approximately home in
                    if (vectorToTargetPosition.Y > 16)
                    {
                        float xSpeed = FallSpeed * vectorToTargetPosition.X / vectorToTargetPosition.Y;
                        projectile.velocity.X = Math.Min(xSpeed, 8);
                    }
                    else
                    {
                        projectile.velocity.X = 0;
                    }
                }
                return;
            }
            if (vectorAbove.Y > 16)
            {
                gHelper.DropThroughPlatform();
            }
            int speed = Math.Abs(vectorAbove.X) < 64 ? 14 : 11;

            DistanceFromGroup(ref vectorAbove);
            vectorAbove.SafeNormalize();
            vectorAbove *= speed;
            int inertia = 16;

            projectile.velocity = (projectile.velocity * (inertia - 1) + vectorAbove) / inertia;
        }
Ejemplo n.º 12
0
        public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true)
        {
            prevPosition = position;
            prevZoom     = zoom;

            float moveSpeed = 20.0f / zoom;

            Vector2 moveCam = Vector2.Zero;

            if (targetPos == Vector2.Zero)
            {
                Vector2 moveInput = Vector2.Zero;
                if (allowMove && GUI.KeyboardDispatcher.Subscriber == null)
                {
                    if (PlayerInput.KeyDown(Keys.LeftShift))
                    {
                        moveSpeed *= 2.0f;
                    }
                    if (PlayerInput.KeyDown(Keys.LeftControl))
                    {
                        moveSpeed *= 0.5f;
                    }

                    if (GameMain.Config.KeyBind(InputType.Left).IsDown())
                    {
                        moveInput.X -= 1.0f;
                    }
                    if (GameMain.Config.KeyBind(InputType.Right).IsDown())
                    {
                        moveInput.X += 1.0f;
                    }
                    if (GameMain.Config.KeyBind(InputType.Down).IsDown())
                    {
                        moveInput.Y -= 1.0f;
                    }
                    if (GameMain.Config.KeyBind(InputType.Up).IsDown())
                    {
                        moveInput.Y += 1.0f;
                    }
                }

                velocity = Vector2.Lerp(velocity, moveInput, deltaTime * 10.0f);
                moveCam  = velocity * moveSpeed * deltaTime * 60.0f;

                if (Screen.Selected == GameMain.GameScreen && FollowSub)
                {
                    var closestSub = Submarine.FindClosest(WorldViewCenter);
                    if (closestSub != null)
                    {
                        moveCam += FarseerPhysics.ConvertUnits.ToDisplayUnits(closestSub.Velocity * deltaTime);
                    }
                }

                if (allowZoom && GUI.MouseOn == null)
                {
                    Vector2 mouseInWorld = ScreenToWorld(PlayerInput.MousePosition);
                    Vector2 diffViewCenter;
                    diffViewCenter = ((mouseInWorld - Position) * Zoom);
                    targetZoom     = MathHelper.Clamp(
                        targetZoom + (PlayerInput.ScrollWheelSpeed / 1000.0f) * zoom,
                        GameMain.DebugDraw ? MinZoom * 0.1f : MinZoom,
                        MaxZoom);

                    Zoom = MathHelper.Lerp(Zoom, targetZoom, deltaTime * 10.0f);
                    if (!PlayerInput.KeyDown(Keys.F))
                    {
                        Position = mouseInWorld - (diffViewCenter / Zoom);
                    }
                }
            }
            else if (allowMove)
            {
                Vector2 mousePos = PlayerInput.MousePosition;
                Vector2 offset   = mousePos - resolution.ToVector2() / 2;
                offset.X = offset.X / (resolution.X * 0.4f);
                offset.Y = -offset.Y / (resolution.Y * 0.3f);
                if (offset.LengthSquared() > 1.0f)
                {
                    offset.Normalize();
                }
                offset *= offsetAmount;
                // Freeze the camera movement by default, when the cursor is on top of an ui element.
                // Setting a positive value to the OffsetAmount, will override this behaviour.
                if (GUI.MouseOn != null && offsetAmount > 0)
                {
                    Freeze = true;
                }
                if (CharacterHealth.OpenHealthWindow != null || CrewManager.IsCommandInterfaceOpen)
                {
                    offset *= 0;
                    Freeze  = false;
                }
                if (Freeze)
                {
                    offset = previousOffset;
                }
                else
                {
                    previousOffset = offset;
                }

                //how much to zoom out (zoom completely out when offset is 1000)
                float zoomOutAmount = Math.Min(offset.Length() / 1000.0f, 1.0f);
                //zoom amount when resolution is not taken into account
                float unscaledZoom = MathHelper.Lerp(DefaultZoom, MinZoom, zoomOutAmount);
                //zoom with resolution taken into account (zoom further out on smaller resolutions)
                float scaledZoom = unscaledZoom * globalZoomScale;

                //an ad-hoc way of allowing the players to have roughly the same maximum view distance regardless of the resolution,
                //while still keeping the zoom around 1.0 when not looking further away (because otherwise we'd always be downsampling
                //on lower resolutions, which doesn't look that good)
                float newZoom = MathHelper.Lerp(unscaledZoom, scaledZoom,
                                                (GameMain.Config == null || GameMain.Config.EnableMouseLook) ? (float)Math.Sqrt(zoomOutAmount) : 0.3f);

                Zoom += (newZoom - zoom) / ZoomSmoothness;

                //force targetzoom to the current zoom value, so the camera stays at the same zoom when switching to freecam
                targetZoom = Zoom;

                Vector2 diff = (targetPos + offset) - position;

                moveCam = diff / MoveSmoothness;
            }
            rotation        += angularVelocity * deltaTime;
            angularVelocity *= (1.0f - angularDamping);
            angularVelocity += -rotation * angularSpring;

            angularDamping = 0.05f;
            angularSpring  = 0.2f;

            if (Shake < 0.01f)
            {
                shakePosition = Vector2.Zero;
                shakeTimer    = 0.0f;
            }
            else
            {
                shakeTimer += deltaTime * 5.0f;
                Vector2 noisePos = new Vector2((float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0) - 0.5f, (float)PerlinNoise.CalculatePerlin(shakeTimer, shakeTimer, 0.5f) - 0.5f);

                shakePosition = noisePos * Shake * 2.0f;
                Shake         = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f);
            }

            Translate(moveCam + shakePosition);
            Freeze = false;
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Copy vertices. This assumes the vertices define a convex polygon.
        /// It is assumed that the exterior is the the right of each edge.
        /// </summary>
        /// <param name="vertices">The vertices.</param>
        public void Set(Vertices vertices)
        {
            Debug.Assert(vertices.Count >= 3 && vertices.Count <= Settings.MaxPolygonVertices);

            if (Settings.ConserveMemory)
            {
                Vertices = vertices;
            }
            else
            {
                // Copy vertices.
                Vertices = new Vertices(vertices);
            }

            Normals = new Vertices(vertices.Count);

            // Compute normals. Ensure the edges have non-zero length.
            for (int i = 0; i < vertices.Count; ++i)
            {
                int     i1   = i;
                int     i2   = i + 1 < vertices.Count ? i + 1 : 0;
                Vector2 edge = Vertices[i2] - Vertices[i1];
                Debug.Assert(edge.LengthSquared() > Settings.Epsilon * Settings.Epsilon);

                Vector2 temp = new Vector2(edge.Y, -edge.X);
                temp.Normalize();
                Normals.Add(temp);
            }

#if DEBUG
            if (Vertices.Count > 3)
            {
                // Ensure the polygon is convex and the interior
                // is to the left of each edge.
                for (int i = 0; i < Vertices.Count; ++i)
                {
                    int     i1   = i;
                    int     i2   = i + 1 < Vertices.Count ? i + 1 : 0;
                    Vector2 edge = Vertices[i2] - Vertices[i1];

                    for (int j = 0; j < vertices.Count; ++j)
                    {
                        // Don't check vertices on the current edge.
                        if (j == i1 || j == i2)
                        {
                            continue;
                        }

                        Vector2 r = Vertices[j] - Vertices[i1];

                        // Your polygon is non-convex (it has an indentation) or
                        // has colinear edges.
                        float s = edge.X * r.Y - edge.Y * r.X;

                        Debug.Assert(s > 0.0f);
                    }
                }
            }
#endif

            // Compute the polygon mass data
            ComputeProperties();
        }
Ejemplo n.º 14
0
        public static ResolvedMotion ResolvePolygonMotion(Polygon polygonA, Polygon polygonB, Vector2 velocityA)
        {
            var offset = ComputeComparisonOffset(polygonA, polygonB);

            var result = new ResolvedMotion();

            result.AreIntersecting      = true;
            result.WouldHaveIntersected = true;
            result.WillBeIntersecting   = true;

            float velocityProjection;
            var   velocityDistance = velocityA.Length();
            var   velocityAxis     = Vector2.Normalize(velocityA);

            Interval intervalA, intervalB, newIntervalA;
            float    minDistance = float.MaxValue;

            int bufferSize = polygonA.Count + polygonB.Count + 4;

            using (var axisBuffer = BufferPool <Vector2> .Allocate(bufferSize)) {
                int axisCount = 0;

                if (velocityA.LengthSquared() > 0)
                {
                    axisCount         += 4;
                    axisBuffer.Data[0] = Vector2.Normalize(velocityA);
                    axisBuffer.Data[1] = new Vector2(-axisBuffer.Data[0].X, axisBuffer.Data[0].Y);
                    axisBuffer.Data[2] = new Vector2(axisBuffer.Data[0].X, -axisBuffer.Data[0].Y);
                    axisBuffer.Data[3] = new Vector2(-axisBuffer.Data[0].X, -axisBuffer.Data[0].Y);
                }

                GetPolygonAxes(axisBuffer.Data, ref axisCount, polygonA);
                GetPolygonAxes(axisBuffer.Data, ref axisCount, polygonB);

                for (int i = 0; i < axisCount; i++)
                {
                    var axis = axisBuffer.Data[i];

                    intervalA = ProjectOntoAxis(axis, polygonA, offset);
                    intervalB = ProjectOntoAxis(axis, polygonB, offset);

                    bool intersects = intervalA.Intersects(intervalB, Geometry.IntersectionEpsilon);
                    if (!intersects)
                    {
                        result.AreIntersecting = false;
                    }

                    velocityProjection = axis.Dot(ref velocityA);

                    newIntervalA      = intervalA;
                    newIntervalA.Min += velocityProjection;
                    newIntervalA.Max += velocityProjection;

                    var intersectionDistance = newIntervalA.GetDistance(intervalB);
                    intersects = intersectionDistance < 0;
                    if (!intersects)
                    {
                        result.WouldHaveIntersected = false;
                    }

                    if (result.WouldHaveIntersected == false)
                    {
                        result.WillBeIntersecting = false;
                        result.ResultVelocity     = velocityA;
                        break;
                    }

                    if ((velocityDistance > 0) && (intersectionDistance < minDistance))
                    {
                        var minVect     = axis * intersectionDistance;
                        var newVelocity = velocityA + minVect;
                        var newLength   = Vector2.Dot(velocityAxis, newVelocity);
                        newVelocity = velocityAxis * newLength;

                        if (newVelocity.LengthSquared() > velocityA.LengthSquared())
                        {
                            continue;
                        }
                        if (Vector2.Dot(velocityA, newVelocity) < 0.0f)
                        {
                            newVelocity = Vector2.Zero;
                        }

                        velocityProjection   = axis.Dot(ref newVelocity);
                        newIntervalA.Min     = (intervalA.Min + velocityProjection);
                        newIntervalA.Max     = (intervalA.Max + velocityProjection);
                        intersectionDistance = newIntervalA.GetDistance(intervalB);

                        if (intersectionDistance < -IntersectionEpsilon)
                        {
                            continue;
                        }

                        result.ResultVelocity     = newVelocity;
                        result.WillBeIntersecting = false;
                        minDistance = intersectionDistance;
                    }
                }
            }

            return(result);
        }
        private void fixedupdate()
        {
            var dirY = Vector2.Zero;
            var dirX = Vector2.Zero;

            if (Root.instance.input.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.W))
            {
                dirY += ship.DerivedForward;
            }

            if (Root.instance.input.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.S))
            {
                dirY += ship.DerivedBackward;
            }

            if (Root.instance.input.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.D))
            {
                dirX += ship.DerivedRight;
            }

            if (Root.instance.input.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.A))
            {
                dirX += ship.DerivedLeft;
            }

            if (Root.instance.input.IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Space))
            {
                velocityX *= 0.95f;
                velocityY *= 0.95f;

                if (velocityX.LengthSquared() < 0.01f)
                {
                    velocityX = Vector2.Zero;
                }

                if (velocityY.LengthSquared() < 0.01f)
                {
                    velocityY = Vector2.Zero;
                }
            }

            if (dirY != Vector2.Zero)
            {
                dirY.Normalize();
                velocityY += dirY * accY * Root.instance.time.deltaTime;

                if (velocityY.LengthSquared() > 1)
                {
                    //acquires new heading faster
                    velocityY += dirY * accY * Root.instance.time.deltaTime * 2f;
                    velocityY.Normalize();
                }
            }

            if (dirX != Vector2.Zero)
            {
                dirX.Normalize();
                velocityX += dirX * accX * Root.instance.time.deltaTime;

                if (velocityX.LengthSquared() > 1)
                {
                    //acquires new heading faster
                    velocityX += dirX * accX * Root.instance.time.deltaTime * 2f;
                    velocityX.Normalize();
                }
            }

            _transform.Position += velocityY * maxYSpeed * Root.instance.time.deltaTime;
            _transform.Position += velocityX * maxXSpeed * Root.instance.time.deltaTime;
            velocityX           *= 0.95f;
        }
Ejemplo n.º 16
0
        internal override void SolveVelocityConstraints(ref SolverData data)
        {
            Vector2 vA = data.velocities[_indexA].v;
            float wA = data.velocities[_indexA].w;

            // Cdot = v + cross(w, r)
            Vector2 Cdot = vA + MathUtils.Cross(wA, _rA);
            Vector2 impulse = MathUtils.Mul(ref _mass, -(Cdot + _C + _gamma * _impulse));

            Vector2 oldImpulse = _impulse;
            _impulse += impulse;
            float maxImpulse = data.step.dt * MaxForce;
            if (_impulse.LengthSquared() > maxImpulse * maxImpulse)
            {
                _impulse *= maxImpulse / _impulse.Length();
            }
            impulse = _impulse - oldImpulse;

            vA += _invMassA * impulse;
            wA += _invIA * MathUtils.Cross(_rA, impulse);

            data.velocities[_indexA].v = vA;
            data.velocities[_indexA].w = wA;
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Updates the Turret
        /// </summary>
        /// <param name="elapsedTime">The in-game time between the previous and current frame</param>
        public override void  Update(float elapsedTime)
        {
            // Update the frame timer
            frameDelay += elapsedTime;

            if (frameDelay > 0.15f && shotDelay == 0 && frame > 0)
            {
                // Decrement the frame number
                frame--;
            }

            if (frame == 0)
            {
                // Restart the animation
                frame = 0;
                // Update the shot timer
                shotDelay += elapsedTime;
            }

            // Sense the player's position
            PlayerShip player         = ScrollingShooterGame.Game.Player;
            Vector2    playerPosition = new Vector2(player.Bounds.X, player.Bounds.Y);

            // Get a vector from our position to the player's position
            Vector2 toPlayer = playerPosition - this.position;

            if (toPlayer.LengthSquared() < 150000)
            {
                // We sense the player's ship!
                // Get a normalized turning vector
                toPlayer.Normalize();

                // Rotate towards them!
                this.alpha = (float)Math.Atan2(toPlayer.Y, toPlayer.X) - MathHelper.PiOver2;

                // If it is time to shoot, fire a bullet towards the player
                if (shotDelay > 1f)
                {
                    if ((frameDelay > 0.15f && frame < 6) || (frameDelay > 0.24f && frame >= 6))
                    {
                        // Reset the frame delay
                        frameDelay = 0;

                        // Increment the frame number
                        frame++;
                    }

                    if (frame >= 8)
                    {
                        // Reset the shot delay
                        shotDelay = 0;

                        // Spawn the bullet
                        ScrollingShooterGame.GameObjectManager.CreateProjectile(ProjectileType.EnemyTurretTowerBullet, this.position + offset, bulletVel * toPlayer);
                    }
                }
            }
            else if (frameDelay > 0.15f && frame > 0)
            {
                // Decrement the frame number
                frame--;
            }
        }
Ejemplo n.º 18
0
 /// <summary>
 ///     Creates a reflection matrix that reflects along a line from the origin to a point given.
 /// </summary>
 /// <param name="to">The point defining the line to reflect along.</param>
 /// <returns>The reflection matrix.</returns>
 public static Matrix3x2 CreateReflection(Vector2 to)
 {
     Vector2 v2 = to * to;
     float xy2 = 2 * to.X * to.Y;
     return new Matrix3x2(v2.X - v2.Y, xy2, xy2, v2.Y - v2.X, 0, 0) * (1 / to.LengthSquared());
 }
Ejemplo n.º 19
0
 public void LengthSquaredTest()
 {
     Assert.IsTrue(TestHelper.ApproximatelyEquals(v1.LengthSquared(), 384.5193f));
 }
Ejemplo n.º 20
0
        public override void UpdateHUD(Character character, float deltaTime, Camera cam)
        {
            IsActive = true;

            bool lightOn = Timing.TotalTime % 0.5f < 0.25f && onOffSwitch.BarScroll < 0.5f;

            fissionRateScrollBar.Enabled   = !autoTemp;
            turbineOutputScrollBar.Enabled = !autoTemp;

            criticalHeatWarning.Selected   = temperature > allowedTemperature.Y && lightOn;
            lowTemperatureWarning.Selected = temperature < allowedTemperature.X && lightOn;
            criticalOutputWarning.Selected = -currPowerConsumption > load * 1.5f && lightOn;

            warningButtons["ReactorWarningOverheating"].Selected = temperature > optimalTemperature.Y && lightOn;
            warningButtons["ReactorWarningHighOutput"].Selected  = -currPowerConsumption > load * 1.1f && lightOn;
            warningButtons["ReactorWarningLowTemp"].Selected     = temperature < optimalTemperature.X && lightOn;
            warningButtons["ReactorWarningLowOutput"].Selected   = -currPowerConsumption < load * 0.9f && lightOn;
            warningButtons["ReactorWarningFuelOut"].Selected     = prevAvailableFuel < fissionRate * 0.01f && lightOn;
            warningButtons["ReactorWarningLowFuel"].Selected     = prevAvailableFuel < fissionRate && lightOn;
            warningButtons["ReactorWarningMeltdown"].Selected    = meltDownTimer > MeltdownDelay * 0.5f || item.Condition == 0.0f && lightOn;
            warningButtons["ReactorWarningSCRAM"].Selected       = temperature > 0.1f && onOffSwitch.BarScroll > 0.5f;

            AutoTemp = autoTempSlider.BarScroll < 0.5f;
            shutDown = onOffSwitch.BarScroll > 0.5f;

            if ((sliderControlsContainer.Rect.Contains(PlayerInput.MousePosition) || sliderControlsContainer.Children.Contains(GUIScrollBar.draggingBar)) &&
                !PlayerInput.KeyDown(InputType.Deselect) && !PlayerInput.KeyHit(InputType.Deselect))
            {
                Character.DisableControls = true;
            }

            if (shutDown)
            {
                fissionRateScrollBar.BarScroll   = FissionRate / 100.0f;
                turbineOutputScrollBar.BarScroll = TurbineOutput / 100.0f;
            }
            else if (!autoTemp && Character.DisableControls && GUI.KeyboardDispatcher.Subscriber == null)
            {
                Vector2 input = Vector2.Zero;
                float   rate  = 50.0f; //percentage per second

                if (PlayerInput.KeyDown(InputType.Left))
                {
                    input.X += -1.0f;
                }
                if (PlayerInput.KeyDown(InputType.Right))
                {
                    input.X += 1.0f;
                }
                if (PlayerInput.KeyDown(InputType.Up))
                {
                    input.Y += 1.0f;
                }
                if (PlayerInput.KeyDown(InputType.Down))
                {
                    input.Y += -1.0f;
                }
                if (PlayerInput.KeyDown(InputType.Run))
                {
                    rate = 200.0f;
                }
                else if (PlayerInput.KeyDown(InputType.Crouch))
                {
                    rate = 20.0f;
                }

                rate    *= deltaTime;
                input.X *= rate;
                input.Y *= rate;

                if (input.LengthSquared() > 0)
                {
                    LastUser      = Character.Controlled;
                    unsentChanges = true;
                    if (input.X != 0.0f && GUIScrollBar.draggingBar != fissionRateScrollBar)
                    {
                        targetFissionRate = MathHelper.Clamp(targetFissionRate + input.X, 0.0f, 100.0f);
                        fissionRateScrollBar.BarScroll += input.X / 100.0f;
                    }
                    if (input.Y != 0.0f && GUIScrollBar.draggingBar != turbineOutputScrollBar)
                    {
                        targetTurbineOutput = MathHelper.Clamp(targetTurbineOutput + input.Y, 0.0f, 100.0f);
                        turbineOutputScrollBar.BarScroll += input.Y / 100.0f;
                    }
                }
            }
        }
Ejemplo n.º 21
0
        private List <HitscanResult> DoRayCast(Vector2 rayStart, Vector2 rayEnd)
        {
            List <HitscanResult> hits = new List <HitscanResult>();

            Vector2 dir = rayEnd - rayStart;

            dir = dir.LengthSquared() < 0.00001f ? Vector2.UnitY : Vector2.Normalize(dir);

            //do an AABB query first to see if the start of the ray is inside a fixture
            var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.One * 0.001f, rayStart + Vector2.One * 0.001f);

            GameMain.World.QueryAABB((fixture) =>
            {
                //ignore sensors and items
                if (fixture?.Body == null || fixture.IsSensor)
                {
                    return(true);
                }
                if (fixture.Body.UserData is Item item && (item.GetComponent <Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0))
                {
                    return(true);
                }
                if (fixture.Body?.UserData as string == "ruinroom")
                {
                    return(true);
                }

                //ignore everything else than characters, sub walls and level walls
                if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel))
                {
                    return(true);
                }

                if (fixture.Body.UserData is VoronoiCell && this.item.Submarine != null)
                {
                    return(true);
                }

                fixture.Body.GetTransform(out FarseerPhysics.Common.Transform transform);
                if (!fixture.Shape.TestPoint(ref transform, ref rayStart))
                {
                    return(true);
                }

                hits.Add(new HitscanResult(fixture, rayStart, -dir, 0.0f));
                return(true);
            }, ref aabb);

            GameMain.World.RayCast((fixture, point, normal, fraction) =>
            {
                //ignore sensors and items
                if (fixture?.Body == null || fixture.IsSensor)
                {
                    return(-1);
                }

                if (fixture.Body.UserData is Item item && (item.GetComponent <Door>() == null && !item.Prefab.DamagedByProjectiles || item.Condition <= 0))
                {
                    return(-1);
                }
                if (fixture.Body?.UserData as string == "ruinroom")
                {
                    return(-1);
                }

                //ignore everything else than characters, sub walls and level walls
                if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel))
                {
                    return(-1);
                }

                //ignore level cells if the item the point of impact are inside a sub
                if (fixture.Body.UserData is VoronoiCell && this.item.Submarine != null)
                {
                    if (Hull.FindHull(ConvertUnits.ToDisplayUnits(point), this.item.CurrentHull) != null)
                    {
                        return(-1);
                    }
                }

                hits.Add(new HitscanResult(fixture, point, normal, fraction));

                return(hits.Count < 25 ? 1 : 0);
            }, rayStart, rayEnd, Physics.CollisionCharacter | Physics.CollisionWall | Physics.CollisionLevel);

            return(hits);
        }
Ejemplo n.º 22
0
        public CollisionResult CollideCircleAtTime(float s, Circle c, out double t)
        {
            return(CollideCircleAtTime2(s, c, out t));

            t = -1;//arbitrary error case

            Vector2 vel = Velocity * s - c.Velocity * s;
            Vector2 pos = Position - c.Position;

            Vector2 d = ClosestOnSegment(pos, pos + vel, Vector2.Zero);

            double closestDistanceSquared = Vector2.DistanceSquared(d, Vector2.Zero);

            if (closestDistanceSquared <= Math.Pow(Radius + c.Radius, 2))
            { // Collision occured
                // Projection of c center on this circle's velocity vector
                Vector2 a     = Vector2.Zero - pos;
                Vector2 b     = vel;
                float   aDotB = Vector2.Dot(a, b);
                if (aDotB < .0001f)
                {
                    return(CollisionResult.None);
                }                                                    // This can happen if the collision is tangential, so just ignore it for now?
                Vector2 projection = pos + (aDotB / b.LengthSquared()) * b;

                // Calculate leg of right triangle: the distance from the closest point where the circles actually collided
                double legSquared = Math.Pow(Radius + c.Radius, 2) - (projection - Vector2.Zero).LengthSquared();

                // The percentage of time in this step that passes before the collision
                t = 1 - (legSquared / Vector2.DistanceSquared(pos, projection));
                if (t < -1 || t > 1)
                {
                    return(CollisionResult.None);
                }                                                     // When does this happen and why is it bad?

                // The position of the circles at time of collision
                Vector2 newPos  = Position + Velocity * s * (float)t;
                Vector2 cNewPos = c.Position + c.Velocity * s * (float)t;

                // Calculate response (bounce)

                // The norm of the vector between the two circles
                Vector2 n = Vector2.Normalize(cNewPos - newPos);


                ////Reflection
                //Vector2 reflection = Velocity - 2 * Vector2.Dot(Velocity, n) * n;
                //Vector2 cReflection = c.Velocity - 2 * Vector2.Dot(c.Velocity, n) * n;

                //float totalMass = Mass + c.Mass;
                //Vector2 lerp = Vector2.Lerp(reflection, Velocity, Mass / totalMass);
                //Vector2 cLerp = Vector2.Lerp(cReflection, c.Velocity, c.Mass / totalMass);

                //Vector2 newV = lerp;
                //Vector2 cNewV = cLerp;

                //impulse magnitude?
                Vector2 deltaV    = Velocity - c.Velocity;
                float   magnitude = deltaV.Length();

                //Resultant velocities
                Vector2 newV  = Velocity - (1 / Mass) * magnitude * n;
                Vector2 cNewV = c.Velocity + (1 / c.Mass) * magnitude * n;


                // Add some separation (.01f is arbitrary ?)
                //newPos = newPos + newV * .01f;
                //cNewPos = cNewPos + cNewV * .01f;

                return(new CollisionResult(newPos, newV, cNewPos, cNewV));
            }
            else
            {
                return(CollisionResult.None);
            }
        }
Ejemplo n.º 23
0
    public static void AssertIsUnit(Vector2 v)
    {
        float lengthSquared = v.LengthSquared();

        Debug.Assert(Math.Abs(lengthSquared - 1) < 1e-2f, "not normalized");
    }
Ejemplo n.º 24
0
        /// <summary>
        /// Gets the intersection between the convex shape and the ray.
        /// </summary>
        /// <param name="ray">Ray to test.</param>
        /// <param name="transform">Transform of the convex shape.</param>
        /// <param name="maximumLength">Maximum distance to travel in units of the ray direction's length.</param>
        /// <param name="hit">Ray hit data, if any.</param>
        /// <returns>Whether or not the ray hit the target.</returns>
        public override bool RayTest(ref Ray ray, ref RigidTransform transform, float maximumLength, out RayHit hit)
        {
            //Put the ray into local space.
            Quaternion conjugate;

            Quaternion.Conjugate(ref transform.Orientation, out conjugate);
            Ray localRay;

            Vector3.Subtract(ref ray.Position, ref transform.Position, out localRay.Position);
            Vector3.Transform(ref localRay.Position, ref conjugate, out localRay.Position);
            Vector3.Transform(ref ray.Direction, ref conjugate, out localRay.Direction);

            //Check for containment in the cylindrical portion of the capsule.
            if (localRay.Position.Y >= -halfLength && localRay.Position.Y <= halfLength && localRay.Position.X * localRay.Position.X + localRay.Position.Z * localRay.Position.Z <= collisionMargin * collisionMargin)
            {
                //It's inside!
                hit.T        = 0;
                hit.Location = localRay.Position;
                hit.Normal   = new Vector3(hit.Location.X, 0, hit.Location.Z);
                float normalLengthSquared = hit.Normal.LengthSquared();
                if (normalLengthSquared > 1e-9f)
                {
                    Vector3.Divide(ref hit.Normal, (float)Math.Sqrt(normalLengthSquared), out hit.Normal);
                }
                else
                {
                    hit.Normal = new Vector3();
                }
                //Pull the hit into world space.
                Vector3.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal);
                RigidTransform.Transform(ref hit.Location, ref transform, out hit.Location);
                return(true);
            }

            //Project the ray direction onto the plane where the cylinder is a circle.
            //The projected ray is then tested against the circle to compute the time of impact.
            //That time of impact is used to compute the 3d hit location.
            Vector2 planeDirection = new Vector2(localRay.Direction.X, localRay.Direction.Z);
            float   planeDirectionLengthSquared = planeDirection.LengthSquared();

            if (planeDirectionLengthSquared < Toolbox.Epsilon)
            {
                //The ray is nearly parallel with the axis.
                //Skip the cylinder-sides test.  We're either inside the cylinder and won't hit the sides, or we're outside
                //and won't hit the sides.
                if (localRay.Position.Y > halfLength)
                {
                    goto upperSphereTest;
                }
                if (localRay.Position.Y < -halfLength)
                {
                    goto lowerSphereTest;
                }


                hit = new RayHit();
                return(false);
            }
            Vector2 planeOrigin = new Vector2(localRay.Position.X, localRay.Position.Z);
            float   dot;

            Vector2.Dot(ref planeDirection, ref planeOrigin, out dot);
            float closestToCenterT = -dot / planeDirectionLengthSquared;

            Vector2 closestPoint;

            Vector2.Multiply(ref planeDirection, closestToCenterT, out closestPoint);
            Vector2.Add(ref planeOrigin, ref closestPoint, out closestPoint);
            //How close does the ray come to the circle?
            float squaredDistance = closestPoint.LengthSquared();

            if (squaredDistance > collisionMargin * collisionMargin)
            {
                //It's too far!  The ray cannot possibly hit the capsule.
                hit = new RayHit();
                return(false);
            }



            //With the squared distance, compute the distance backward along the ray from the closest point on the ray to the axis.
            float backwardsDistance = collisionMargin * (float)Math.Sqrt(1 - squaredDistance / (collisionMargin * collisionMargin));
            float tOffset           = backwardsDistance / (float)Math.Sqrt(planeDirectionLengthSquared);

            hit.T = closestToCenterT - tOffset;

            //Compute the impact point on the infinite cylinder in 3d local space.
            Vector3.Multiply(ref localRay.Direction, hit.T, out hit.Location);
            Vector3.Add(ref hit.Location, ref localRay.Position, out hit.Location);

            //Is it intersecting the cylindrical portion of the capsule?
            if (hit.Location.Y <= halfLength && hit.Location.Y >= -halfLength && hit.T < maximumLength)
            {
                //Yup!
                hit.Normal = new Vector3(hit.Location.X, 0, hit.Location.Z);
                float normalLengthSquared = hit.Normal.LengthSquared();
                if (normalLengthSquared > 1e-9f)
                {
                    Vector3.Divide(ref hit.Normal, (float)Math.Sqrt(normalLengthSquared), out hit.Normal);
                }
                else
                {
                    hit.Normal = new Vector3();
                }
                //Pull the hit into world space.
                Vector3.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal);
                RigidTransform.Transform(ref hit.Location, ref transform, out hit.Location);
                return(true);
            }

            if (hit.Location.Y < halfLength)
            {
                goto lowerSphereTest;
            }
upperSphereTest:
            //Nope! It may be intersecting the ends of the capsule though.
            //We're above the capsule, so cast a ray against the upper sphere.
            //We don't have to worry about it hitting the bottom of the sphere since it would have hit the cylinder portion first.
            var spherePosition = new Vector3(0, halfLength, 0);

            if (Toolbox.RayCastSphere(ref localRay, ref spherePosition, collisionMargin, maximumLength, out hit))
            {
                //Pull the hit into world space.
                Vector3.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal);
                RigidTransform.Transform(ref hit.Location, ref transform, out hit.Location);
                return(true);
            }
            //No intersection! We can't be hitting the other sphere, so it's over!
            hit = new RayHit();
            return(false);

lowerSphereTest:
            //Okay, what about the bottom sphere?
            //We're above the capsule, so cast a ray against the upper sphere.
            //We don't have to worry about it hitting the bottom of the sphere since it would have hit the cylinder portion first.
            spherePosition = new Vector3(0, -halfLength, 0);
            if (Toolbox.RayCastSphere(ref localRay, ref spherePosition, collisionMargin, maximumLength, out hit))
            {
                //Pull the hit into world space.
                Vector3.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal);
                RigidTransform.Transform(ref hit.Location, ref transform, out hit.Location);
                return(true);
            }
            //No intersection! We can't be hitting the other sphere, so it's over!
            hit = new RayHit();
            return(false);
        }
Ejemplo n.º 25
0
        internal override bool SolvePositionConstraints()
        {
            // TODO_ERIN block solve with limit. COME ON ERIN

            Body b1 = BodyA;
            Body b2 = BodyB;

            float angularError = 0.0f;
            float positionError;

            // Solve angular limit constraint.
            if (_enableLimit && _limitState != LimitState.Inactive)
            {
                float angle        = b2.Sweep.A - b1.Sweep.A - ReferenceAngle;
                float limitImpulse = 0.0f;

                if (_limitState == LimitState.Equal)
                {
                    // Prevent large angular corrections
                    float C = MathUtils.Clamp(angle - _lowerAngle, -Settings.MaxAngularCorrection,
                                              Settings.MaxAngularCorrection);
                    limitImpulse = -_motorMass * C;
                    angularError = Math.Abs(C);
                }
                else if (_limitState == LimitState.AtLower)
                {
                    float C = angle - _lowerAngle;
                    angularError = -C;

                    // Prevent large angular corrections and allow some slop.
                    C            = MathUtils.Clamp(C + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f);
                    limitImpulse = -_motorMass * C;
                }
                else if (_limitState == LimitState.AtUpper)
                {
                    float C = angle - _upperAngle;
                    angularError = C;

                    // Prevent large angular corrections and allow some slop.
                    C            = MathUtils.Clamp(C - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection);
                    limitImpulse = -_motorMass * C;
                }

                b1.Sweep.A -= b1.InvI * limitImpulse;
                b2.Sweep.A += b2.InvI * limitImpulse;

                b1.SynchronizeTransform();
                b2.SynchronizeTransform();
            }

            // Solve point-to-point constraint.
            {
                /*Transform xf1, xf2;
                 * b1.GetTransform(out xf1);
                 * b2.GetTransform(out xf2);*/

                Vector2 r1 = MathUtils.Multiply(ref b1.Xf.R, LocalAnchorA - b1.LocalCenter);
                Vector2 r2 = MathUtils.Multiply(ref b2.Xf.R, LocalAnchorB - b2.LocalCenter);

                Vector2 C = b2.Sweep.C + r2 - b1.Sweep.C - r1;
                positionError = C.Length();

                float invMass1 = b1.InvMass, invMass2 = b2.InvMass;
                float invI1 = b1.InvI, invI2 = b2.InvI;

                // Handle large detachment.
                const float k_allowedStretch = 10.0f * Settings.LinearSlop;
                if (C.LengthSquared() > k_allowedStretch * k_allowedStretch)
                {
                    // Use a particle solution (no rotation).
                    Vector2 u = C;
                    u.Normalize();
                    float k = invMass1 + invMass2;
                    Debug.Assert(k > Settings.Epsilon);
                    float       m        = 1.0f / k;
                    Vector2     impulse2 = m * (-C);
                    const float k_beta   = 0.5f;
                    b1.Sweep.C -= k_beta * invMass1 * impulse2;
                    b2.Sweep.C += k_beta * invMass2 * impulse2;

                    C = b2.Sweep.C + r2 - b1.Sweep.C - r1;
                }

                Mat22 K1 = new Mat22(new Vector2(invMass1 + invMass2, 0.0f), new Vector2(0.0f, invMass1 + invMass2));
                Mat22 K2 = new Mat22(new Vector2(invI1 * r1.Y * r1.Y, -invI1 * r1.X * r1.Y),
                                     new Vector2(-invI1 * r1.X * r1.Y, invI1 * r1.X * r1.X));
                Mat22 K3 = new Mat22(new Vector2(invI2 * r2.Y * r2.Y, -invI2 * r2.X * r2.Y),
                                     new Vector2(-invI2 * r2.X * r2.Y, invI2 * r2.X * r2.X));

                Mat22 Ka;
                Mat22.Add(ref K1, ref K2, out Ka);

                Mat22 K;
                Mat22.Add(ref Ka, ref K3, out K);


                Vector2 impulse = K.Solve(-C);

                b1.Sweep.C -= b1.InvMass * impulse;
                MathUtils.Cross(ref r1, ref impulse, out _tmpFloat1);
                b1.Sweep.A -= b1.InvI * /* r1 x impulse */ _tmpFloat1;

                b2.Sweep.C += b2.InvMass * impulse;
                MathUtils.Cross(ref r2, ref impulse, out _tmpFloat1);
                b2.Sweep.A += b2.InvI * /* r2 x impulse */ _tmpFloat1;

                b1.SynchronizeTransform();
                b2.SynchronizeTransform();
            }

            return(positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop);
        }
Ejemplo n.º 26
0
        private void UpdateAutoPilot(float deltaTime)
        {
            if (controlledSub == null)
            {
                return;
            }
            if (posToMaintain != null)
            {
                Vector2 steeringVel = GetSteeringVelocity((Vector2)posToMaintain, 10.0f);
                TargetVelocity = Vector2.Lerp(TargetVelocity, steeringVel, AutoPilotSteeringLerp);
                return;
            }

            autopilotRayCastTimer         -= deltaTime;
            autopilotRecalculatePathTimer -= deltaTime;
            if (autopilotRecalculatePathTimer <= 0.0f)
            {
                //periodically recalculate the path in case the sub ends up to a position
                //where it can't keep traversing the initially calculated path
                UpdatePath();
                autopilotRecalculatePathTimer = RecalculatePathInterval;
            }

            if (steeringPath == null)
            {
                return;
            }
            steeringPath.CheckProgress(ConvertUnits.ToSimUnits(controlledSub.WorldPosition), 10.0f);

            if (autopilotRayCastTimer <= 0.0f && steeringPath.NextNode != null)
            {
                Vector2 diff = ConvertUnits.ToSimUnits(steeringPath.NextNode.Position - controlledSub.WorldPosition);

                //if the node is close enough, check if it's visible
                float lengthSqr = diff.LengthSquared();
                if (lengthSqr > 0.001f && lengthSqr < AutopilotMinDistToPathNode * AutopilotMinDistToPathNode)
                {
                    diff = Vector2.Normalize(diff);

                    //check if the next waypoint is visible from all corners of the sub
                    //(i.e. if we can navigate directly towards it or if there's obstacles in the way)
                    bool nextVisible = true;
                    for (int x = -1; x < 2; x += 2)
                    {
                        for (int y = -1; y < 2; y += 2)
                        {
                            Vector2 cornerPos =
                                new Vector2(controlledSub.Borders.Width * x, controlledSub.Borders.Height * y) / 2.0f;

                            cornerPos = ConvertUnits.ToSimUnits(cornerPos * 1.1f + controlledSub.WorldPosition);

                            float dist = Vector2.Distance(cornerPos, steeringPath.NextNode.SimPosition);

                            if (Submarine.PickBody(cornerPos, cornerPos + diff * dist, null, Physics.CollisionLevel) == null)
                            {
                                continue;
                            }

                            nextVisible = false;
                            x           = 2;
                            y           = 2;
                        }
                    }

                    if (nextVisible)
                    {
                        steeringPath.SkipToNextNode();
                    }
                }

                autopilotRayCastTimer = AutopilotRayCastInterval;
            }

            Vector2 newVelocity = Vector2.Zero;

            if (steeringPath.CurrentNode != null)
            {
                newVelocity = GetSteeringVelocity(steeringPath.CurrentNode.WorldPosition, 2.0f);
            }

            Vector2 avoidDist = new Vector2(
                Math.Max(1000.0f * Math.Abs(controlledSub.Velocity.X), controlledSub.Borders.Width * 0.75f),
                Math.Max(1000.0f * Math.Abs(controlledSub.Velocity.Y), controlledSub.Borders.Height * 0.75f));

            float avoidRadius             = avoidDist.Length();
            float damagingWallAvoidRadius = avoidRadius * 1.5f;

            Vector2 newAvoidStrength = Vector2.Zero;

            debugDrawObstacles.Clear();

            //steer away from nearby walls
            var closeCells = Level.Loaded.GetCells(controlledSub.WorldPosition, 4);

            foreach (VoronoiCell cell in closeCells)
            {
                if (cell.DoesDamage)
                {
                    foreach (GraphEdge edge in cell.Edges)
                    {
                        Vector2 closestPoint = MathUtils.GetClosestPointOnLineSegment(edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, controlledSub.WorldPosition);
                        float   dist         = Vector2.Distance(closestPoint, controlledSub.WorldPosition);
                        if (dist > damagingWallAvoidRadius)
                        {
                            continue;
                        }
                        Vector2 diff  = controlledSub.WorldPosition - cell.Center;
                        Vector2 avoid = Vector2.Normalize(diff) * (damagingWallAvoidRadius - dist) / damagingWallAvoidRadius;
                        newAvoidStrength += avoid;
                        debugDrawObstacles.Add(new ObstacleDebugInfo(edge, edge.Center, 1.0f, avoid, cell.Translation));
                    }
                    continue;
                }

                foreach (GraphEdge edge in cell.Edges)
                {
                    if (MathUtils.GetLineIntersection(edge.Point1 + cell.Translation, edge.Point2 + cell.Translation, controlledSub.WorldPosition, cell.Center, out Vector2 intersection))
                    {
                        Vector2 diff = controlledSub.WorldPosition - intersection;
                        //far enough -> ignore
                        if (Math.Abs(diff.X) > avoidDist.X && Math.Abs(diff.Y) > avoidDist.Y)
                        {
                            debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, 0.0f, Vector2.Zero, Vector2.Zero));
                            continue;
                        }
                        if (diff.LengthSquared() < 1.0f)
                        {
                            diff = Vector2.UnitY;
                        }

                        Vector2 normalizedDiff = Vector2.Normalize(diff);
                        float   dot            = controlledSub.Velocity == Vector2.Zero ?
                                                 0.0f : Vector2.Dot(controlledSub.Velocity, -normalizedDiff);

                        //not heading towards the wall -> ignore
                        if (dot < 1.0)
                        {
                            debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot, Vector2.Zero, cell.Translation));
                            continue;
                        }

                        Vector2 change = (normalizedDiff * Math.Max((avoidRadius - diff.Length()), 0.0f)) / avoidRadius;
                        if (change.LengthSquared() < 0.001f)
                        {
                            continue;
                        }
                        newAvoidStrength += change * (dot - 1.0f);
                        debugDrawObstacles.Add(new ObstacleDebugInfo(edge, intersection, dot - 1.0f, change * (dot - 1.0f), cell.Translation));
                    }
                }
            }

            avoidStrength  = Vector2.Lerp(avoidStrength, newAvoidStrength, deltaTime * 10.0f);
            TargetVelocity = Vector2.Lerp(TargetVelocity, newVelocity + avoidStrength * 100.0f, AutoPilotSteeringLerp);

            //steer away from other subs
            foreach (Submarine sub in Submarine.Loaded)
            {
                if (sub == controlledSub)
                {
                    continue;
                }
                if (controlledSub.DockedTo.Contains(sub))
                {
                    continue;
                }
                Point   sizeSum          = controlledSub.Borders.Size + sub.Borders.Size;
                Vector2 minDist          = sizeSum.ToVector2() / 2;
                Vector2 diff             = controlledSub.WorldPosition - sub.WorldPosition;
                float   xDist            = Math.Abs(diff.X);
                float   yDist            = Math.Abs(diff.Y);
                Vector2 maxAvoidDistance = minDist * 2;
                if (xDist > maxAvoidDistance.X || yDist > maxAvoidDistance.Y)
                {
                    //far enough -> ignore
                    continue;
                }
                float dot = controlledSub.Velocity == Vector2.Zero ? 0.0f : Vector2.Dot(Vector2.Normalize(controlledSub.Velocity), -diff);
                if (dot < 0.0f)
                {
                    //heading away -> ignore
                    continue;
                }
                float distanceFactor = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(maxAvoidDistance.X + maxAvoidDistance.Y, minDist.X + minDist.Y, xDist + yDist));
                float velocityFactor = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, 3, controlledSub.Velocity.Length()));
                TargetVelocity += 100 * Vector2.Normalize(diff) * distanceFactor * velocityFactor;
            }

            //clamp velocity magnitude to 100.0f (Is this required? The X and Y components are clamped in the property setter)
            float velMagnitude = TargetVelocity.Length();

            if (velMagnitude > 100.0f)
            {
                TargetVelocity *= 100.0f / velMagnitude;
            }
        }
        SystemPosition4 VS(Position4 input)
        {
            Matrix4x4 testMatrix = new Matrix4x4(
                1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1);

            Vector2 v2 = new Vector2(1, 2);
            Vector2 r2 = Vector2.Abs(v2);

            r2 = Vector2.Add(v2, v2);
            r2 = Vector2.Clamp(v2, v2, v2);
            float r = Vector2.Distance(v2, v2);

            r  = Vector2.DistanceSquared(v2, v2);
            r2 = Vector2.Divide(v2, v2);
            r2 = Vector2.Divide(v2, r);
            r  = Vector2.Dot(v2, v2);
            r2 = Vector2.Lerp(v2, v2, 0.75f);
            r2 = Vector2.Max(v2, v2);
            r2 = Vector2.Min(v2, v2);
            r2 = Vector2.Multiply(v2, v2);
            r2 = Vector2.Multiply(v2, r);
            r2 = Vector2.Multiply(r, v2);
            r2 = Vector2.Negate(v2);
            r2 = Vector2.Normalize(v2);
            r2 = Vector2.Reflect(v2, v2);
            r2 = Vector2.SquareRoot(v2);
            r2 = Vector2.Subtract(v2, v2);
            r  = v2.Length();
            r  = v2.LengthSquared();
            r2 = Vector2.Transform(v2, testMatrix);

            Vector3 v3 = new Vector3(1, 2, 3);
            Vector3 r3 = Vector3.Abs(v3);

            r3 = Vector3.Add(v3, v3);
            r3 = Vector3.Clamp(v3, v3, v3);
            r3 = Vector3.Cross(v3, v3);
            r  = Vector3.Distance(v3, v3);
            r  = Vector3.DistanceSquared(v3, v3);
            r3 = Vector3.Divide(v3, v3);
            r3 = Vector3.Divide(v3, r);
            r  = Vector3.Dot(v3, v3);
            r3 = Vector3.Lerp(v3, v3, 0.75f);
            r3 = Vector3.Max(v3, v3);
            r3 = Vector3.Min(v3, v3);
            r3 = Vector3.Multiply(v3, v3);
            r3 = Vector3.Multiply(v3, r);
            r3 = Vector3.Multiply(r, v3);
            r3 = Vector3.Negate(v3);
            r3 = Vector3.Normalize(v3);
            r3 = Vector3.Reflect(v3, v3);
            r3 = Vector3.SquareRoot(v3);
            r3 = Vector3.Subtract(v3, v3);
            r  = v3.Length();
            r  = v3.LengthSquared();
            r3 = Vector3.Transform(v3, testMatrix);

            Vector4 v4 = new Vector4(1, 2, 3, 4);
            Vector4 r4 = Vector4.Abs(v4);

            r4 = Vector4.Add(v4, v4);
            r4 = Vector4.Clamp(v4, v4, v4);
            r  = Vector4.Distance(v4, v4);
            r  = Vector4.DistanceSquared(v4, v4);
            r4 = Vector4.Divide(v4, v4);
            r4 = Vector4.Divide(v4, r);
            r  = Vector4.Dot(v4, v4);
            r4 = Vector4.Lerp(v4, v4, 0.75f);
            r4 = Vector4.Max(v4, v4);
            r4 = Vector4.Min(v4, v4);
            r4 = Vector4.Multiply(v4, v4);
            r4 = Vector4.Multiply(v4, r);
            r4 = Vector4.Multiply(r, v4);
            r4 = Vector4.Negate(v4);
            r4 = Vector4.Normalize(v4);
            r4 = Vector4.SquareRoot(v4);
            r4 = Vector4.Subtract(v4, v4);
            r  = v4.Length();
            r  = v4.LengthSquared();
            r4 = Vector4.Transform(v2, testMatrix);
            r4 = Vector4.Transform(v3, testMatrix);
            r4 = Vector4.Transform(v4, testMatrix);

            SystemPosition4 output;

            output.Position = input.Position;
            return(output);
        }
Ejemplo n.º 28
0
        public override void Update(GameTime gameTime)
        {
            Container = new Rectangle((int)Position.X, (int)Position.Y, _texture.Width, _texture.Height);
            Position  = Velocity + Position;
            Origin    = new Vector2(Container.Width / 2, Container.Height / 2);

            GamePadState padState   = GamePad.GetState(PlayerIndex.One, GamePadDeadZone.Circular);
            Vector2      leftStick  = padState.ThumbSticks.Left;
            Vector2      rightStick = padState.ThumbSticks.Right;


            Vector2 v = Velocity;

            if (v.X < MaxVelocity && v.X > -MaxVelocity)
            {
                v.X += leftStick.X;
            }
            if (v.Y < MaxVelocity && v.Y > -MaxVelocity)
            {
                v.Y += -leftStick.Y;
            }

            Velocity = v;

            if (rightStick.LengthSquared() > 0.1f)
            {
                Rotation = (float)Math.Atan2(-rightStick.Y, rightStick.X);
            }

            if (padState.Triggers.Right > 0.1f && rTrigState < 0.1f)
            {
                FireRight(gameTime.TotalGameTime.Milliseconds);
            }

            if (padState.Triggers.Left > 0.1f && lTrigState < 0.1f)
            {
                FireLeft(gameTime.TotalGameTime.Milliseconds);
            }

            else if (Velocity != Vector2.Zero)
            {
                v.X = v.X -= 0.01f * v.X;
                v.Y = v.Y -= 0.01f * v.Y;

                Velocity = v;
            }

            var ProjList = _firedProjectiles.ToList();

            foreach (Projectile p in ProjList)
            {
                if (gameTime.TotalGameTime.Milliseconds - p.FireTime > 1000)
                {
                    _firedProjectiles.Remove(p);
                }
                p.Update(gameTime);
            }

            rTrigState = padState.Triggers.Right;
            lTrigState = padState.Triggers.Left;
        }
Ejemplo n.º 29
0
        public void Update(float deltaTime)
        {
            if (GameMain.Client != null)
            {
                if (memPos.Count == 0)
                {
                    return;
                }

                Vector2 newVelocity = Body.LinearVelocity;
                Vector2 newPosition = Body.SimPosition;

                Body.CorrectPosition(memPos, deltaTime, out newVelocity, out newPosition);
                Vector2 moveAmount = ConvertUnits.ToDisplayUnits(newPosition - Body.SimPosition);
                newVelocity = newVelocity.ClampLength(100.0f);
                if (!MathUtils.IsValid(newVelocity))
                {
                    return;
                }

                List <Submarine> subsToMove = submarine.GetConnectedSubs();
                foreach (Submarine dockedSub in subsToMove)
                {
                    if (dockedSub == submarine)
                    {
                        continue;
                    }
                    //clear the position buffer of the docked subs to prevent unnecessary position corrections
                    dockedSub.SubBody.memPos.Clear();
                }

                Submarine closestSub = null;
                if (Character.Controlled == null)
                {
                    closestSub = Submarine.FindClosest(GameMain.GameScreen.Cam.WorldViewCenter);
                }
                else
                {
                    closestSub = Character.Controlled.Submarine;
                }

                bool displace = moveAmount.LengthSquared() > 100.0f * 100.0f;
                foreach (Submarine sub in subsToMove)
                {
                    sub.PhysicsBody.SetTransform(sub.PhysicsBody.SimPosition + ConvertUnits.ToSimUnits(moveAmount), 0.0f);
                    sub.PhysicsBody.LinearVelocity = newVelocity;

                    if (displace)
                    {
                        sub.SubBody.DisplaceCharacters(moveAmount);
                    }
                }

                if (closestSub != null && subsToMove.Contains(closestSub))
                {
                    GameMain.GameScreen.Cam.Position += moveAmount;
                    if (GameMain.GameScreen.Cam.TargetPos != Vector2.Zero)
                    {
                        GameMain.GameScreen.Cam.TargetPos += moveAmount;
                    }

                    if (Character.Controlled != null)
                    {
                        Character.Controlled.CursorPosition += moveAmount;
                    }
                }

                return;
            }

            //if outside left or right edge of the level
            if (Position.X < 0 || Position.X > Level.Loaded.Size.X)
            {
                Rectangle worldBorders = Borders;
                worldBorders.Location += MathUtils.ToPoint(Position);

                //push the sub back below the upper "barrier" of the level
                if (worldBorders.Y > Level.Loaded.Size.Y)
                {
                    Body.LinearVelocity = new Vector2(
                        Body.LinearVelocity.X,
                        Math.Min(Body.LinearVelocity.Y, ConvertUnits.ToSimUnits(Level.Loaded.Size.Y - worldBorders.Y)));
                }
                else if (worldBorders.Y - worldBorders.Height < Level.Loaded.BottomPos)
                {
                    Body.LinearVelocity = new Vector2(
                        Body.LinearVelocity.X,
                        Math.Max(Body.LinearVelocity.Y, ConvertUnits.ToSimUnits(Level.Loaded.BottomPos - (worldBorders.Y - worldBorders.Height))));
                }
            }

            //-------------------------

            Vector2 totalForce = CalculateBuoyancy();

            if (Body.LinearVelocity.LengthSquared() > 0.0001f)
            {
                float dragCoefficient = 0.01f;

                float speedLength = (Body.LinearVelocity == Vector2.Zero) ? 0.0f : Body.LinearVelocity.Length();
                float drag        = speedLength * speedLength * dragCoefficient * Body.Mass;

                totalForce += -Vector2.Normalize(Body.LinearVelocity) * drag;
            }

            ApplyForce(totalForce);

            UpdateDepthDamage(deltaTime);
        }
Ejemplo n.º 30
0
        //Extracted from Box2D

        /// <summary>
        /// Returns the convex hull from the given vertices.
        /// </summary>
        /// <param name="vertices">The vertices.</param>
        public static Vertices GetConvexHull(Vertices vertices)
        {
            if (vertices.Count <= 3)
            {
                return(vertices);
            }

            // Find the right most point on the hull
            int   i0 = 0;
            float x0 = vertices[0].X;

            for (int i = 1; i < vertices.Count; ++i)
            {
                float x = vertices[i].X;
                if (x > x0 || (x == x0 && vertices[i].Y < vertices[i0].Y))
                {
                    i0 = i;
                    x0 = x;
                }
            }

            int[] hull = new int[vertices.Count];
            int   m    = 0;
            int   ih   = i0;

            for (; ;)
            {
                hull[m] = ih;

                int ie = 0;
                for (int j = 1; j < vertices.Count; ++j)
                {
                    if (ie == ih)
                    {
                        ie = j;
                        continue;
                    }

                    Vector2 r = vertices[ie] - vertices[hull[m]];
                    Vector2 v = vertices[j] - vertices[hull[m]];
                    float   c = MathUtils.Cross(ref r, ref v);
                    if (c < 0.0f)
                    {
                        ie = j;
                    }

                    // Collinearity check
                    if (c == 0.0f && v.LengthSquared() > r.LengthSquared())
                    {
                        ie = j;
                    }
                }

                ++m;
                ih = ie;

                if (ie == i0)
                {
                    break;
                }
            }

            Vertices result = new Vertices(m);

            // Copy vertices.
            for (int i = 0; i < m; ++i)
            {
                result.Add(vertices[hull[i]]);
            }
            return(result);
        }
Ejemplo n.º 31
0
        public static void ComputeDistance(out DistanceOutput output, out SimplexCache cache, DistanceInput input)
        {
            cache = new SimplexCache();

            if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled
            {
                ++GJKCalls;
            }

            // Initialize the simplex.
            Simplex simplex = new Simplex();

            simplex.ReadCache(ref cache, input.ProxyA, ref input.TransformA, input.ProxyB, ref input.TransformB);

            // These store the vertices of the last simplex so that we
            // can check for duplicates and prevent cycling.
            FixedArray3 <int> saveA = new FixedArray3 <int>();
            FixedArray3 <int> saveB = new FixedArray3 <int>();

            //Velcro: This code was not used anyway.
            //float distanceSqr1 = Settings.MaxFloat;

            // Main iteration loop.
            int iter = 0;

            while (iter < Settings.MaxGJKIterations)
            {
                // Copy simplex so we can identify duplicates.
                int saveCount = simplex.Count;
                for (int i = 0; i < saveCount; ++i)
                {
                    saveA[i] = simplex.V[i].IndexA;
                    saveB[i] = simplex.V[i].IndexB;
                }

                switch (simplex.Count)
                {
                case 1:
                    break;

                case 2:
                    simplex.Solve2();
                    break;

                case 3:
                    simplex.Solve3();
                    break;

                default:
                    Debug.Assert(false);
                    break;
                }

                // If we have 3 points, then the origin is in the corresponding triangle.
                if (simplex.Count == 3)
                {
                    break;
                }

                // Get search direction.
                Vector2 d = simplex.GetSearchDirection();

                // Ensure the search direction is numerically fit.
                if (d.LengthSquared() < Settings.Epsilon * Settings.Epsilon)
                {
                    // The origin is probably contained by a line segment
                    // or triangle. Thus the shapes are overlapped.

                    // We can't return zero here even though there may be overlap.
                    // In case the simplex is a point, segment, or triangle it is difficult
                    // to determine if the origin is contained in the CSO or very close to it.
                    break;
                }

                // Compute a tentative new simplex vertex using support points.
                SimplexVertex vertex = simplex.V[simplex.Count];
                vertex.IndexA = input.ProxyA.GetSupport(MathUtils.MulT(input.TransformA.q, -d));
                vertex.WA     = MathUtils.Mul(ref input.TransformA, input.ProxyA.Vertices[vertex.IndexA]);

                vertex.IndexB            = input.ProxyB.GetSupport(MathUtils.MulT(input.TransformB.q, d));
                vertex.WB                = MathUtils.Mul(ref input.TransformB, input.ProxyB.Vertices[vertex.IndexB]);
                vertex.W                 = vertex.WB - vertex.WA;
                simplex.V[simplex.Count] = vertex;

                // Iteration count is equated to the number of support point calls.
                ++iter;

                if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled
                {
                    ++GJKIters;
                }

                // Check for duplicate support points. This is the main termination criteria.
                bool duplicate = false;
                for (int i = 0; i < saveCount; ++i)
                {
                    if (vertex.IndexA == saveA[i] && vertex.IndexB == saveB[i])
                    {
                        duplicate = true;
                        break;
                    }
                }

                // If we found a duplicate support point we must exit to avoid cycling.
                if (duplicate)
                {
                    break;
                }

                // New vertex is ok and needed.
                ++simplex.Count;
            }

            if (Settings.EnableDiagnostics) //Velcro: We only gather diagnostics when enabled
            {
                GJKMaxIters = Math.Max(GJKMaxIters, iter);
            }

            // Prepare output.
            simplex.GetWitnessPoints(out output.PointA, out output.PointB);
            output.Distance   = (output.PointA - output.PointB).Length();
            output.Iterations = iter;

            // Cache the simplex.
            simplex.WriteCache(ref cache);

            // Apply radii if requested.
            if (input.UseRadii)
            {
                float rA = input.ProxyA.Radius;
                float rB = input.ProxyB.Radius;

                if (output.Distance > rA + rB && output.Distance > Settings.Epsilon)
                {
                    // Shapes are still no overlapped.
                    // Move the witness points to the outer surface.
                    output.Distance -= rA + rB;
                    Vector2 normal = output.PointB - output.PointA;
                    normal.Normalize();
                    output.PointA += rA * normal;
                    output.PointB -= rB * normal;
                }
                else
                {
                    // Shapes are overlapped when radii are considered.
                    // Move the witness points to the middle.
                    Vector2 p = 0.5f * (output.PointA + output.PointB);
                    output.PointA   = p;
                    output.PointB   = p;
                    output.Distance = 0.0f;
                }
            }
        }
Ejemplo n.º 32
0
        public override void Update(float deltaTime, Camera cam)
        {
            this.cam = cam;

            if (IsToggle)
            {
                item.SendSignal(0, state ? "1" : "0", "signal_out", sender: null);
            }

            if (user == null ||
                user.Removed ||
                user.SelectedConstruction != item ||
                !user.CanInteractWith(item))
            {
                if (user != null)
                {
                    CancelUsing(user);
                    user = null;
                }
                if (!IsToggle)
                {
                    IsActive = false;
                }
                return;
            }

            user.AnimController.Anim = AnimController.Animation.UsingConstruction;

            if (userPos != Vector2.Zero)
            {
                Vector2 diff = (item.WorldPosition + userPos) - user.WorldPosition;

                if (user.AnimController.InWater)
                {
                    if (diff.Length() > 30.0f)
                    {
                        user.AnimController.TargetMovement = Vector2.Clamp(diff * 0.01f, -Vector2.One, Vector2.One);
                        user.AnimController.TargetDir      = diff.X > 0.0f ? Direction.Right : Direction.Left;
                    }
                    else
                    {
                        user.AnimController.TargetMovement = Vector2.Zero;
                    }
                }
                else
                {
                    diff.Y = 0.0f;
                    if (diff != Vector2.Zero && diff.LengthSquared() > 10.0f * 10.0f)
                    {
                        user.AnimController.TargetMovement = Vector2.Normalize(diff);
                        user.AnimController.TargetDir      = diff.X > 0.0f ? Direction.Right : Direction.Left;
                        return;
                    }
                    user.AnimController.TargetMovement = Vector2.Zero;
                }
            }

            ApplyStatusEffects(ActionType.OnActive, deltaTime, user);

            if (limbPositions.Count == 0)
            {
                return;
            }

            user.AnimController.Anim = AnimController.Animation.UsingConstruction;

            user.AnimController.ResetPullJoints();

            if (dir != 0)
            {
                user.AnimController.TargetDir = dir;
            }

            foreach (LimbPos lb in limbPositions)
            {
                Limb limb = user.AnimController.GetLimb(lb.limbType);
                if (limb == null || !limb.body.Enabled)
                {
                    continue;
                }

                limb.Disabled = true;

                Vector2 worldPosition = new Vector2(item.WorldRect.X, item.WorldRect.Y) + lb.position * item.Scale;
                Vector2 diff          = worldPosition - limb.WorldPosition;

                limb.PullJointEnabled      = true;
                limb.PullJointWorldAnchorB = limb.SimPosition + ConvertUnits.ToSimUnits(diff);
            }
        }
        public override void Update(float deltaTime, Camera cam)
        {
            this.cam = cam;

            if (IsToggle)
            {
                item.SendSignal(0, State ? "1" : "0", "signal_out", sender: null);
            }

            if (user == null ||
                user.Removed ||
                user.SelectedConstruction != item ||
                item.ParentInventory != null ||
                !user.CanInteractWith(item) ||
                (UsableIn == UseEnvironment.Water && !user.AnimController.InWater) ||
                (UsableIn == UseEnvironment.Air && user.AnimController.InWater))
            {
                if (user != null)
                {
                    CancelUsing(user);
                    user = null;
                }
                if (!IsToggle)
                {
                    IsActive = false;
                }
                return;
            }

            user.AnimController.Anim = AnimController.Animation.UsingConstruction;

            if (userPos != Vector2.Zero)
            {
                Vector2 diff = (item.WorldPosition + userPos) - user.WorldPosition;

                if (user.AnimController.InWater)
                {
                    if (diff.LengthSquared() > 30.0f * 30.0f)
                    {
                        user.AnimController.TargetMovement = Vector2.Clamp(diff * 0.01f, -Vector2.One, Vector2.One);
                        user.AnimController.TargetDir      = diff.X > 0.0f ? Direction.Right : Direction.Left;
                    }
                    else
                    {
                        user.AnimController.TargetMovement = Vector2.Zero;
                    }
                }
                else
                {
                    diff.Y = 0.0f;
                    if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && user != Character.Controlled)
                    {
                        if (Math.Abs(diff.X) > 20.0f)
                        {
                            //wait for the character to walk to the correct position
                            return;
                        }
                        else if (Math.Abs(diff.X) > 0.1f)
                        {
                            //aim to keep the collider at the correct position once close enough
                            user.AnimController.Collider.LinearVelocity = new Vector2(
                                diff.X * 0.1f,
                                user.AnimController.Collider.LinearVelocity.Y);
                        }
                    }
                    else
                    {
                        if (Math.Abs(diff.X) > 10.0f)
                        {
                            user.AnimController.TargetMovement = Vector2.Normalize(diff);
                            user.AnimController.TargetDir      = diff.X > 0.0f ? Direction.Right : Direction.Left;
                            return;
                        }
                    }
                    user.AnimController.TargetMovement = Vector2.Zero;
                }
            }

            ApplyStatusEffects(ActionType.OnActive, deltaTime, user);

            if (limbPositions.Count == 0)
            {
                return;
            }

            user.AnimController.Anim = AnimController.Animation.UsingConstruction;

            user.AnimController.ResetPullJoints();

            if (dir != 0)
            {
                user.AnimController.TargetDir = dir;
            }

            foreach (LimbPos lb in limbPositions)
            {
                Limb limb = user.AnimController.GetLimb(lb.LimbType);
                if (limb == null || !limb.body.Enabled)
                {
                    continue;
                }

                if (lb.AllowUsingLimb)
                {
                    switch (lb.LimbType)
                    {
                    case LimbType.RightHand:
                    case LimbType.RightForearm:
                    case LimbType.RightArm:
                        if (user.Inventory.GetItemInLimbSlot(InvSlotType.RightHand) != null)
                        {
                            continue;
                        }
                        break;

                    case LimbType.LeftHand:
                    case LimbType.LeftForearm:
                    case LimbType.LeftArm:
                        if (user.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand) != null)
                        {
                            continue;
                        }
                        break;
                    }
                }

                limb.Disabled = true;

                Vector2 worldPosition = new Vector2(item.WorldRect.X, item.WorldRect.Y) + lb.Position * item.Scale;
                Vector2 diff          = worldPosition - limb.WorldPosition;

                limb.PullJointEnabled      = true;
                limb.PullJointWorldAnchorB = limb.SimPosition + ConvertUnits.ToSimUnits(diff);
            }
        }
Ejemplo n.º 34
0
        public void Vector2LengthSquaredTest1()
        {
            Vector2 a = new Vector2(0.0f, 0.0f);

            float expected = 0.0f;
            float actual = a.LengthSquared();

            Assert.Equal(expected, actual);
        }
        private void DamageCharacters(Vector2 worldPosition, Attack attack, float force, Entity damageSource, Character attacker)
        {
            if (attack.Range <= 0.0f)
            {
                return;
            }

            //long range for the broad distance check, because large characters may still be in range even if their collider isn't
            float broadRange = Math.Max(attack.Range * 10.0f, 10000.0f);

            foreach (Character c in Character.CharacterList)
            {
                if (!c.Enabled ||
                    Math.Abs(c.WorldPosition.X - worldPosition.X) > broadRange ||
                    Math.Abs(c.WorldPosition.Y - worldPosition.Y) > broadRange)
                {
                    continue;
                }

                Vector2 explosionPos = worldPosition;
                if (c.Submarine != null)
                {
                    explosionPos -= c.Submarine.Position;
                }

                Hull hull       = Hull.FindHull(explosionPos, null, false);
                bool underWater = hull == null || explosionPos.Y < hull.Surface;

                explosionPos = ConvertUnits.ToSimUnits(explosionPos);

                Dictionary <Limb, float> distFactors         = new Dictionary <Limb, float>();
                Dictionary <Limb, float> damages             = new Dictionary <Limb, float>();
                List <Affliction>        modifiedAfflictions = new List <Affliction>();
                foreach (Limb limb in c.AnimController.Limbs)
                {
                    if (limb.IsSevered || limb.IgnoreCollisions || !limb.body.Enabled)
                    {
                        continue;
                    }

                    float dist = Vector2.Distance(limb.WorldPosition, worldPosition);

                    //calculate distance from the "outer surface" of the physics body
                    //doesn't take the rotation of the limb into account, but should be accurate enough for this purpose
                    float limbRadius = limb.body.GetMaxExtent();
                    dist = Math.Max(0.0f, dist - ConvertUnits.ToDisplayUnits(limbRadius));

                    if (dist > attack.Range)
                    {
                        continue;
                    }

                    float distFactor = 1.0f - dist / attack.Range;

                    //solid obstacles between the explosion and the limb reduce the effect of the explosion
                    distFactor *= GetObstacleDamageMultiplier(explosionPos, worldPosition, limb.SimPosition);
                    distFactors.Add(limb, distFactor);

                    modifiedAfflictions.Clear();
                    foreach (Affliction affliction in attack.Afflictions.Keys)
                    {
                        //previously the damage would be divided by the number of limbs (the intention was to prevent characters with more limbs taking more damage from explosions)
                        //that didn't work well on large characters like molochs and endworms: the explosions tend to only damage one or two of their limbs, and since the characters
                        //have lots of limbs, they tended to only take a fraction of the damage they should

                        //now we just divide by 10, which keeps the damage to normal-sized characters roughly the same as before and fixes the large characters
                        modifiedAfflictions.Add(affliction.CreateMultiplied(distFactor / 10));
                    }
                    c.LastDamageSource = damageSource;
                    if (attacker == null)
                    {
                        if (damageSource is Item item)
                        {
                            attacker = item.GetComponent <Projectile>()?.User;
                            if (attacker == null)
                            {
                                attacker = item.GetComponent <MeleeWeapon>()?.User;
                            }
                        }
                    }

                    //use a position slightly from the limb's position towards the explosion
                    //ensures that the attack hits the correct limb and that the direction of the hit can be determined correctly in the AddDamage methods
                    Vector2      dir          = worldPosition - limb.WorldPosition;
                    Vector2      hitPos       = limb.WorldPosition + (dir.LengthSquared() <= 0.001f ? Rand.Vector(1.0f) : Vector2.Normalize(dir)) * 0.01f;
                    AttackResult attackResult = c.AddDamage(hitPos, modifiedAfflictions, attack.Stun * distFactor, false, attacker: attacker);
                    damages.Add(limb, attackResult.Damage);

                    if (attack.StatusEffects != null && attack.StatusEffects.Any())
                    {
                        attack.SetUser(attacker);
                        var statusEffectTargets = new List <ISerializableEntity>()
                        {
                            c, limb
                        };
                        foreach (StatusEffect statusEffect in attack.StatusEffects)
                        {
                            statusEffect.Apply(ActionType.OnUse, 1.0f, damageSource, statusEffectTargets);
                            statusEffect.Apply(ActionType.Always, 1.0f, damageSource, statusEffectTargets);
                            statusEffect.Apply(underWater ? ActionType.InWater : ActionType.NotInWater, 1.0f, damageSource, statusEffectTargets);
                        }
                    }

                    if (limb.WorldPosition != worldPosition && !MathUtils.NearlyEqual(force, 0.0f))
                    {
                        Vector2 limbDiff = Vector2.Normalize(limb.WorldPosition - worldPosition);
                        if (!MathUtils.IsValid(limbDiff))
                        {
                            limbDiff = Rand.Vector(1.0f);
                        }
                        Vector2 impulse      = limbDiff * distFactor * force;
                        Vector2 impulsePoint = limb.SimPosition - limbDiff * limbRadius;
                        limb.body.ApplyLinearImpulse(impulse, impulsePoint, maxVelocity: NetConfig.MaxPhysicsBodyVelocity * 0.2f);
                    }
                }

                if (c == Character.Controlled && !c.IsDead && playTinnitus)
                {
                    Limb head = c.AnimController.GetLimb(LimbType.Head);
                    if (head != null && damages.TryGetValue(head, out float headDamage) && headDamage > 0.0f && distFactors.TryGetValue(head, out float headFactor))
                    {
                        PlayTinnitusProjSpecific(headFactor);
                    }
                }

                //sever joints
                if (attack.SeverLimbsProbability > 0.0f)
                {
                    foreach (Limb limb in c.AnimController.Limbs)
                    {
                        if (limb.character.Removed || limb.Removed)
                        {
                            continue;
                        }
                        if (limb.IsSevered)
                        {
                            continue;
                        }
                        if (!c.IsDead && !limb.CanBeSeveredAlive)
                        {
                            continue;
                        }
                        if (distFactors.TryGetValue(limb, out float distFactor))
                        {
                            if (damages.TryGetValue(limb, out float damage))
                            {
                                c.TrySeverLimbJoints(limb, attack.SeverLimbsProbability * distFactor, damage, allowBeheading: true);
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 36
0
        public void Vector2LengthSquaredTest1()
        {
            Vector2 a = new Vector2(0.0f, 0.0f);

            float expected = 0.0f;
            float actual = a.LengthSquared();

            Assert.AreEqual(expected, actual, "Vector2.LengthSquared did not return the expected value.");
        }
Ejemplo n.º 37
0
        private List <HitscanResult> DoRayCast(Vector2 rayStart, Vector2 rayEnd)
        {
            List <HitscanResult> hits = new List <HitscanResult>();

            Vector2 dir = rayEnd - rayStart;

            dir = dir.LengthSquared() < 0.00001f ? Vector2.UnitY : Vector2.Normalize(dir);

            //do an AABB query first to see if the start of the ray is inside a fixture
            var aabb = new FarseerPhysics.Collision.AABB(rayStart - Vector2.One * 0.001f, rayStart + Vector2.One * 0.001f);

            GameMain.World.QueryAABB((fixture) =>
            {
                //ignore sensors and items
                if (fixture?.Body == null || fixture.IsSensor)
                {
                    return(true);
                }
                if (fixture.UserData is Item)
                {
                    return(true);
                }

                //ignore everything else than characters, sub walls and level walls
                if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel))
                {
                    return(true);
                }

                hits.Add(new HitscanResult(fixture, rayStart, -dir, 0.0f));
                return(true);
            }, ref aabb);

            GameMain.World.RayCast((fixture, point, normal, fraction) =>
            {
                //ignore sensors and items
                if (fixture?.Body == null || fixture.IsSensor)
                {
                    return(-1);
                }
                if (fixture.UserData is Item)
                {
                    return(-1);
                }

                //ignore everything else than characters, sub walls and level walls
                if (!fixture.CollisionCategories.HasFlag(Physics.CollisionCharacter) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionWall) &&
                    !fixture.CollisionCategories.HasFlag(Physics.CollisionLevel))
                {
                    return(-1);
                }

                hits.Add(new HitscanResult(fixture, point, normal, fraction));

                return(hits.Count < 25 ? 1 : 0);
            }, rayStart, rayEnd);

            return(hits);
        }