예제 #1
0
        private IEnumerator moveBetweenNodes(Entity entity, MarioClearPipeInteraction interaction, Vector2 from, Vector2 to, float?travelSpeed = null, bool?lerpPipeOffset = null)
        {
            interaction.Distance = (from - to).Length();

            interaction.DirectionVector = GetPipeExitDirectionVector(to, from);
            interaction.Direction       = GetPipeExitDirection(to, from);

            interaction.From = from;
            interaction.To   = to;

            interaction.TravelSpeed    = travelSpeed != null ? travelSpeed.Value : interaction.TravelSpeed;
            interaction.LerpPipeOffset = lerpPipeOffset != null ? lerpPipeOffset.Value : interaction.LerpPipeOffset;

            while (entity != null && interaction.Moved <= interaction.Distance && interaction.Distance != 0f && !interaction.ExitEarly)
            {
                interaction?.OnPipeUpdate(entity, interaction);

                float lerpValue = interaction.Moved / interaction.Distance;

                entity.Position    = Vector2.Lerp(from, to, lerpValue) + (interaction.LerpPipeOffset ? Vector2.Lerp(Vector2.Zero, interaction.PipeRenderOffset, lerpValue) : interaction.PipeRenderOffset);
                interaction.Moved += interaction.TravelSpeed * Engine.DeltaTime;

                yield return(null);
            }

            interaction.Moved -= interaction.Distance;
        }
예제 #2
0
        private void ejectFromPipe(Entity entity, MarioClearPipeInteraction interaction)
        {
            // Fix float positions, causes weird collision bugs for entities
            entity.Position = new Vector2((int)Math.Round(entity.Position.X), (int)Math.Round(entity.Position.Y));

            interaction.OnPipeExit?.Invoke(entity, interaction);
            interaction.CurrentClearPipe = null;

            CurrentlyTransportedEntities.Remove(entity);
        }
예제 #3
0
        public static bool CanTransportEntity(Entity entity, Direction direction)
        {
            if (entity != null && !CurrentlyTransportedEntities.Contains(entity))
            {
                MarioClearPipeInteraction interaction = GetClearPipeInteraction(entity);

                return(interaction?.CanEnterPipe?.Invoke(entity, direction) == true);
            }

            return(false);
        }
예제 #4
0
        // Visually update exiting steps
        // Correct for exit overshooting
        private IEnumerator exitPipeMovement(Entity entity, MarioClearPipeInteraction interaction)
        {
            Vector2 previousPosition = entity.Position;
            Vector2 currentPosition  = entity.Position;

            bool colliding = entity?.CollideFirst <MarioClearPipeSolid>() != null;

            while (entity != null && entity.Scene != null && colliding)
            {
                entity.Position += interaction.DirectionVector * TransportSpeed * Engine.DeltaTime;

                previousPosition = currentPosition;
                currentPosition  = entity.Position;

                colliding = entity.CollideFirst <MarioClearPipeSolid>() != null;

                if (colliding)
                {
                    yield return(null);
                }
            }

            // Correct for overshooting the exit, attempt to place entity as close as possible to the pipe

            Vector2 lowerValue    = previousPosition;
            Vector2 upperValue    = currentPosition;
            Vector2 lastUnblocked = entity.Position;

            while (entity != null && entity.Scene != null && (lowerValue - upperValue).LengthSquared() > 0.5f)
            {
                entity.Position = Vector2.Lerp(lowerValue, upperValue, 0.5f);

                if (entity.CollideFirst <MarioClearPipeSolid>() != null)
                {
                    lowerValue = entity.Position;
                }
                else
                {
                    upperValue    = entity.Position;
                    lastUnblocked = entity.Position;
                }
            }

            entity.Position = lastUnblocked;
        }
예제 #5
0
        // TODO - Cleanup and make more generic
        private IEnumerator pipeMovement(Entity entity, bool fromStart, bool canBounceBack = true, Vector2?forcedStartPosition = null)
        {
            MarioClearPipeInteraction interaction = GetClearPipeInteraction(entity);

            int startIndex = fromStart ? 0 : nodes.Length - 1;
            int lastIndex  = fromStart ? nodes.Length - 1 : 0;
            int direction  = fromStart ? 1 : -1;

            Direction transportStartDirection = fromStart ? startDirection : endDirection;
            Direction transportEndDirection   = fromStart ? endDirection : startDirection;

            if (forcedStartPosition != null || CanTransportEntity(entity, transportStartDirection))
            {
                CurrentlyTransportedEntities.Add(entity);
                interaction.CurrentClearPipe = this;
                interaction.ExitEarly        = false;
                interaction?.OnPipeEnter?.Invoke(entity, interaction);

                // Check if we are entering the pipe or bouncing back from a blocked exit
                if (forcedStartPosition != null)
                {
                    entity.Position = forcedStartPosition.Value;
                }
                else
                {
                    // Gracefully attempt to move to the first node
                    yield return(moveBetweenNodes(entity, interaction, entity.Position, nodes[startIndex], TransportSpeed * transportSpeedEnterMultiplier, true));
                }

                // Follow the nodes
                for (int i = startIndex; i != lastIndex && !interaction.ExitEarly; i += direction)
                {
                    yield return(moveBetweenNodes(entity, interaction, nodes[i], nodes[i + direction], TransportSpeed, false));
                }

                if (interaction.ExitEarly)
                {
                    ejectFromPipe(entity, interaction);

                    yield break;
                }

                // Check if we can exit the pipe
                if (CanExitPipe(entity, interaction.DirectionVector, TransportSpeed))
                {
                    yield return(exitPipeMovement(entity, interaction));
                }

                // Send back if it gets stuck in a solid
                if (entity != null && entity.Scene != null && entity.CollideCheck <Solid>())
                {
                    if (canBounceBack)
                    {
                        entity.Position = nodes[lastIndex] + interaction.PipeRenderOffset;

                        yield return(pipeMovement(entity, !fromStart, false, entity.Position));
                    }
                    else
                    {
                        ejectFromPipe(entity, interaction);
                    }
                }
                else
                {
                    ejectFromPipe(entity, interaction);
                }
            }
        }