예제 #1
0
        public static void Control(PhysicsValues physicsValues, GameDuration elapsedDuration, Entity entity)
        {
            // initialize Behavior stores if necessary
            if (!_activeBehavior.ContainsKey(entity))
            {
                Behavior defaultBehavior = InitializeBehaviors(entity);

                _activeBehavior.Add(entity, defaultBehavior);
            }

            Behavior current = _activeBehavior[entity];

            // update the duration the active Behavior has been running
            current.AddToActiveDuration(elapsedDuration);

            // store all relevant data in BehaviorContext
            var context = new BehaviorContext(physicsValues, elapsedDuration);

            // if the minimum running duration of the current Behavior has passed, look for another applicable Behavior
            if (current.ActiveDuration > current.MinimumDuration())
            {
                foreach (Behavior b in _possibleBehaviors[entity])
                {
                    // we only look for *other* Behaviors
                    if (current.Equals(b))
                    {
                        continue;
                    }

                    // determine the other Behavior's current priority
                    var otherPrio = b.DeterminePriority(context);

                    // only consider other Behavior if it's applicable
                    if (otherPrio == BehaviorPriority.NA)
                    {
                        continue;
                    }

                    // switch to other Behavior depending on relation between priorities
                    var currentPrio = current.DeterminePriority(context);
                    if (otherPrio / (currentPrio + otherPrio) > Rng.NextDouble())
                    {
                        // reset the current Behavior, as it might become active again later
                        current.Reset();

                        // change active Behavior to new one
                        _activeBehavior[entity] = b;
                        current = b;

                        ////Console.WriteLine("Entity {0} switched to behavior {1}", entity, b);
                    }
                }
            }

            // let the active Behavior control the entity
            var position = entity.Get <PositionComponent>();

            current.Behave(context, position);
            entity.Set(position);
        }
예제 #2
0
        private void SetNewPlayerPosition()
        {
            Vector2 oldPosition = GetLevelProgression().CurrentPlayerPosition;

            Vector2 newPosition = gamePhysics.DoPlayerPhysics(oldPosition);

            if (!LevelAnalysis.IsVectorOnGround(levelAttempt.Level, newPosition))
            {
                bool isPlayerStanding = GetLevelProgression().IsPlayerStanding;

                Ground groundCollidedWith = collisions.GetPlayerGroundCollision(newPosition, isPlayerStanding);

                if (groundCollidedWith != null)
                {
                    Vector2 rightFoot = PhysicsValues.GetRightFootPosition(newPosition);

                    float deltaX = Math.Abs(rightFoot.X - groundCollidedWith.LeftX);
                    float deltaY = Math.Abs(groundCollidedWith.TopY - rightFoot.Y);

                    if (deltaY > deltaX)
                    {
                        AddPlayerFail();
                    }

                    newPosition = new Vector2(newPosition.X, groundCollidedWith.TopY);

                    gamePhysics.ResetVerticalVelocity();
                }
            }

            GetLevelProgression().CurrentPlayerPosition = newPosition;
        }
예제 #3
0
        public static float GetChasmYDifference(float hangTime)
        {
            int iterations = (int)Math.Round(hangTime * GeneralValues.FPS);

            float jumpDistance = iterations * PhysicsValues.GetJumpAcceleration();

            float gravityDistance = (iterations * (iterations + 1)) / 2 * PhysicsValues.GetGravityAccelerationPerFrame();

            return(jumpDistance - gravityDistance);
        }
예제 #4
0
        public Vector2 GetProjectilePosition(float time, float groundY)
        {
            float hitXPosition = GetPlayerRightEdgeXByTime(time);

            float startingXPosition = GeneralValues.MusicStartPositionX + hitXPosition + time *
                                      PhysicsValues.GetProjectileVelocity() + (PhysicsValues.ProjectileHitboxWidth / 2.0f);

            float startingYPosition = groundY + LevelGenerationValues.GetProjectileYOffset();

            return(new Vector2(startingXPosition, startingYPosition));
        }
예제 #5
0
        private static void SetPositionFromCollisionPosition(PhysicsValues physicsValues, World world, PositionData positionData)
        {
            if (positionData.IsFalling)
            {
                positionData.Placement.Pos = positionData.InternalPos;
                return;
            }

            var entityPos = positionData.InternalPos;
            var blockPos  = (BlockPos)entityPos;

            /*
             * When standing on an edge, the entities bottom center might be hanging in the air.
             * Find the true floor position by iterating downward and looking for the floor.
             */
            if (world[blockPos] == 0 && world[blockPos - BlockOffset.UnitY] == 0)
            {
                blockPos  -= BlockOffset.UnitY;
                entityPos -= EntityOffset.UnitY;

                if (world[blockPos - new BlockOffset(0, 2, 0)] == 0)
                {
                    blockPos  -= BlockOffset.UnitY;
                    entityPos -= EntityOffset.UnitY;
                }
            }

            var entityOffset = entityPos - blockPos;

            double yOffset = 0;

            /*
             * Take the integral of all floor heights in a 2 by 2 area around the center.
             * Since the height is piecewise constant, this is a weighted sum of the heights around the entity position.
             */

            yOffset += (1 - entityOffset.X) * FindHeight(world, blockPos - BlockOffset.UnitX);
            yOffset += entityOffset.X * FindHeight(world, blockPos + BlockOffset.UnitX);
            yOffset += (1 - entityOffset.Z) * FindHeight(world, blockPos - BlockOffset.UnitZ);
            yOffset += entityOffset.Z * FindHeight(world, blockPos + BlockOffset.UnitZ);
            yOffset += (1 - entityOffset.X) * (1 - entityOffset.Z) * FindHeight(world, blockPos + new BlockOffset(-1, 0, -1));
            yOffset += (1 - entityOffset.X) * entityOffset.Z * FindHeight(world, blockPos + new BlockOffset(-1, 0, 1));
            yOffset += entityOffset.X * (1 - entityOffset.Z) * FindHeight(world, blockPos + new BlockOffset(1, 0, -1));
            yOffset += entityOffset.X * entityOffset.Z * FindHeight(world, blockPos + new BlockOffset(1, 0, 1));

            // Normalize.
            yOffset *= 0.25;

            entityPos += new EntityOffset(0, yOffset, 0);
            positionData.Placement.Pos = entityPos;
        }
예제 #6
0
        public Obstacle CreateJumpObstacle(LevelElementPlacement placement, float groundY)
        {
            float centerOfObstacle = GetXPositionByTime(placement.SynchroStartTime) +
                                     PhysicsValues.GetPlainJumpLength() / 2.0f;

            float halfObstacleWidth = LevelGenerationValues.GetJumpObstacleWidth() / 2.0f;

            float leftX  = centerOfObstacle - halfObstacleWidth;
            float rightX = centerOfObstacle + halfObstacleWidth;

            float topY = groundY + LevelGenerationValues.GetJumpObstacleHeight();

            return(new Obstacle(new Vector2(leftX, topY), new Vector2(rightX, groundY)));
        }
예제 #7
0
        private static bool MoveY(PhysicsValues physicsValues, World world, PositionComponent positionData, double distance)
        {
            EntityPos position = positionData.InternalPos;
            long      p        = position.Y;

            int  cx0         = GetBlockCoordinate(position.X - (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) + 1);
            int  cx1         = GetBlockCoordinate(position.X + (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) - 1);
            int  cz0         = GetBlockCoordinate(position.Z - (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) + 1);
            int  cz1         = GetBlockCoordinate(position.Z + (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) - 1);
            bool hasCollided = MoveInternal(p, distance > 0 ? physicsValues.PlayerHeight : 0, distance, cy => AllPassable(world, new BlockPos(cx0, cy, cz0), new BlockPos(cx1, cy, cz1)), out p);

            position.Y = p;

            positionData.InternalPos = position;
            return(hasCollided);
        }
예제 #8
0
        private static bool MoveZ(PhysicsValues physicsValues, World world, PositionData positionData, double distance)
        {
            EntityPos position = positionData.InternalPos;
            long      p        = position.Z;

            int  cx0         = GetBlockCoordinate(position.X - (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) + 1);
            int  cx1         = GetBlockCoordinate(position.X + (long)(0.5 * physicsValues.PlayerWidth * (1L << 32)) - 1);
            int  cy0         = GetBlockCoordinate(position.Y + 1);
            int  cy1         = GetBlockCoordinate(position.Y + (long)(physicsValues.PlayerHeight * (1L << 32)) - 1);
            bool hasCollided = MoveInternal(p, physicsValues.PlayerWidth * 0.5, distance, cz => AllPassable(world, new BlockPos(cx0, cy0, cz), new BlockPos(cx1, cy1, cz)), out p);

            position.Z = p;

            positionData.InternalPos = position;
            return(hasCollided);
        }
예제 #9
0
        private void DeflectProjectile(Projectile projectile)
        {
            float yVelocity = MyMath.GetRandomNumber() * PhysicsValues.ProjectileMaximumYVelocity;

            if (MyMath.GetRandomNumber() > 0.5f)
            {
                yVelocity *= -1;
            }

            float xVelocity = (float)Math.Sqrt(Math.Pow(PhysicsValues.GetProjectileVelocity()
                                                        * 3, 2) - Math.Pow(yVelocity, 2));

            Vector2 deflectionDirection = new Vector2(xVelocity, yVelocity);

            GetLevelProgression().DeflectProjectile(projectile, deflectionDirection);
        }
예제 #10
0
        private void SetNewProjectilePositions()
        {
            LevelProgression levelProgression = GetLevelProgression();

            foreach (Projectile projectile in levelAttempt.Level.Projectiles)
            {
                Vector2 movementDelta;

                if (levelProgression.IsProjectileDeflected(projectile))
                {
                    movementDelta = levelProgression.GetProjectileDeflectionDirection(projectile) / GeneralValues.FPS;
                }
                else
                {
                    movementDelta = new Vector2(-PhysicsValues.GetProjectileVelocityPerFrame(), 0);
                }

                levelProgression.MoveProjectile(projectile, movementDelta);
            }
        }
예제 #11
0
        public static float GetJumpObstacleWidth()
        {
            float minimumHorizontalDistanceRequired = 0;

            for (float time = 0; time < 100; time += 1.0f / GeneralValues.FPS)
            {
                if (GetYDifferenceAfterJump(time) > GetJumpObstacleHeight())
                {
                    minimumHorizontalDistanceRequired = time * PhysicsValues.GetHorizontalPlayerVelocity();
                    break;
                }
            }

            float halfJumpObstacleWidth = PhysicsValues.GetPlainJumpLength() / 2.0f;

            halfJumpObstacleWidth -= MaximumJumpObstacleJumpTimingOffset * PhysicsValues.GetHorizontalPlayerVelocity();
            halfJumpObstacleWidth -= minimumHorizontalDistanceRequired;
            halfJumpObstacleWidth -= PhysicsValues.GetHalfPlayerHitboxWidth();

            return(halfJumpObstacleWidth * 2 * GeneralValues.DifficultyFactor);
        }
예제 #12
0
        public void HandleGameEvent(GameEvent gameEvent)
        {
            if (gameEvent == null)
            {
                return;
            }

            if (gameEvent.IsDisconnected)
            {
                return;
            }

            if (gameEvent.EntityInfos != null)
            {
                EntityInfos = gameEvent.EntityInfos;
            }

            if (gameEvent.PhysicsValues != null)
            {
                PhysicsValues = gameEvent.PhysicsValues;
            }

            if (gameEvent.ChunkDataList != null)
            {
                foreach (var chunkData in gameEvent.ChunkDataList)
                {
                    World.PasteChunkData(chunkData);
                }
            }

            if (gameEvent.BlockUpdates != null)
            {
                foreach (var blockUpdate in gameEvent.BlockUpdates)
                {
                    World[blockUpdate.Pos] = blockUpdate.Material;
                }
            }
        }
예제 #13
0
 public static float GetPlainJumpDuration()
 {
     return(PhysicsValues.GetPlainJumpDuration());
 }
예제 #14
0
 public BehaviorContext(PhysicsValues physicsValues, GameDuration elapsedDuration)
 {
     PhysicsValues   = physicsValues;
     ElapsedDuration = elapsedDuration;
 }
예제 #15
0
 public BehaviorContext(PhysicsValues physicsValues, GameDuration elapsedDuration, IEnumerable <Entity> otherEntities)
 {
     PhysicsValues   = physicsValues;
     ElapsedDuration = elapsedDuration;
     OtherEntities   = otherEntities;
 }
예제 #16
0
        public static void MoveEntity(PhysicsValues physicsValues, World world, PositionData positionData, GameDuration elapsedDuration, EntityOffset offset)
        {
            offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity;
            if (MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds))
            {
                positionData.IsFalling = false;
            }
            else
            {
                if (!positionData.IsFalling)
                {
                    /* Re-evaluate the fall from the apparent position. */
                    positionData.InternalPos = positionData.Placement.Pos;
                    MoveY(physicsValues, world, positionData, offset.Y * elapsedDuration.Seconds);
                    positionData.IsFalling = true;
                }
            }

            if (positionData.IsFalling)
            {
                offset.Y -= 0.5 * elapsedDuration.Seconds * physicsValues.Gravity;
            }
            else
            {
                if (Math.Abs(offset.Y) > Math.Sqrt(2 * physicsValues.Gravity * physicsValues.TerminalHeight))
                {
                    Respawn(positionData);
                }

                offset.Y = 0;
            }

            if (offset.X != 0 || offset.Z != 0)
            {
                long savedY = positionData.InternalPos.Y;
                if (!positionData.IsFalling && world[(BlockPos)positionData.InternalPos - BlockOffset.UnitY] != 0)
                {
                    // Temporarily move the character up a block so that it can climb up stairs.
                    MoveY(physicsValues, world, positionData, 1);
                }

                EntityPos positionBeforeMovement = positionData.InternalPos;
                double    moveX = offset.X * elapsedDuration.Seconds;
                double    moveZ = offset.Z * elapsedDuration.Seconds;

                if (offset.X > offset.Z)
                {
                    MoveX(physicsValues, world, positionData, moveX);
                    MoveZ(physicsValues, world, positionData, moveZ);
                }
                else
                {
                    MoveZ(physicsValues, world, positionData, moveZ);
                    MoveX(physicsValues, world, positionData, moveX);
                }

                var moveDelta = positionData.InternalPos - positionBeforeMovement;
                moveX -= moveDelta.X;
                moveZ -= moveDelta.Z;

                if (!positionData.IsFalling)
                {
                    // Attempt to move the character back down to the ground in case we didn't climb a stair.
                    MoveY(physicsValues, world, positionData, (savedY - positionData.InternalPos.Y) / (double)(1L << 32));

                    savedY = positionData.InternalPos.Y;

                    // Attempt to move the caracter down an additional block so that it can walk down stairs.
                    if (!MoveY(physicsValues, world, positionData, -((1L << 32) + 1) / (double)(1L << 32)))
                    {
                        positionData.InternalPos.Y = savedY;
                        positionData.IsFalling     = true;
                    }
                }

                // Attempt to continue movement at this new (lower) Y position.
                if (offset.X > offset.Z)
                {
                    if (MoveX(physicsValues, world, positionData, moveX))
                    {
                        offset.X = 0;
                    }
                    if (MoveZ(physicsValues, world, positionData, moveZ))
                    {
                        offset.Z = 0;
                    }
                }
                else
                {
                    if (MoveZ(physicsValues, world, positionData, moveZ))
                    {
                        offset.Z = 0;
                    }
                    if (MoveX(physicsValues, world, positionData, moveX))
                    {
                        offset.X = 0;
                    }
                }
            }

            positionData.Velocity = offset;
            SetPositionFromCollisionPosition(physicsValues, world, positionData);
        }
예제 #17
0
 public static float GetHighCollectibleYOffset()
 {
     return(PhysicsValues.GetPlainJumpHeight() + PhysicsValues.PlayerHitboxHeight * 0.8f);
 }
예제 #18
0
 public static float GetPlayerVelocity()
 {
     return(PhysicsValues.GetHorizontalPlayerVelocity());
 }
예제 #19
0
 private float GetPlayerRightEdgeXByTime(float time)
 {
     return(GetXPositionByTime(time) + PhysicsValues.GetHalfPlayerHitboxWidth());
 }