示例#1
0
文件: Physics.cs 项目: kevincos/Vexed
        /* Test for collision between player and blocks, and adjust player's position and velocity accordingly.
         * There's some tricky order of operations here that is explained inline*/
        public static void CollisionCheck(Room r, Player p, int gameTime)
        {
            // Variables used for entire collision test method.
            Physics.BlockUnfold(r, p.center.normal, p.center.direction);
            List<Vector3> playerVertexList = new List<Vector3>();
            List<Vector3> playerGroundBox = new List<Vector3>();
            List<Vector3> playerLeftBox = new List<Vector3>();
            List<Vector3> playerRightBox = new List<Vector3>();
            Vector3 up = p.center.direction;
            Vector3 right = Vector3.Cross(up, p.center.normal);

            /* Stores the result of friction calculations, to be applied at the END of the function. Must be done at the end
             * because during the algorithm, it isn't fully determined what the player's state is, and friction is only applied
             * in certain cases. Specifically, it isn't known if the player has landed on the ground until the algorithm completes.
             */

            Vector3 frictionAdjustment = Vector3.Zero;
            /* Perform the basic algorithm several times, each time taking only the most powerful contribution. I'm assuming for now
             * that it is EXTREMELY unlikely for the player to have meaningful collisions simultaneously with > 3 blocks.
             * The purpose of this is that sometimes two collisions will be detected, but only one needs to be resolved. For example,
             * if two blocks are adjacent to one another such that their edges form a single, straight edge, we only need (and want)
             * to use the projection from one of them*/

            #region player-block collision

            if(p.state != State.Phase && p.state != State.PhaseFail && p.state != State.Tunnel && p.state != State.Jump && p.state != State.Death)
            {
                for (int attempt = 0; attempt < 2; attempt++)
                {
                    playerVertexList = p.GetCollisionRect();

                    List<Vector3> projectionList = new List<Vector3>();
                    List<Vector3> relVelList = new List<Vector3>();
                    List<EdgeProperties> edgePropertiesList = new List<EdgeProperties>();

                    foreach (Block baseBlock in r.blocks)
                    {
                        foreach (Block b in baseBlock.unfoldedBlocks)
                        {
                            if (p.CollisionFirstPass(b))
                                continue;

                            List<Vector3> blockVertexList = b.GetCollisionRect();
                            Vector3 projection = Collide(playerVertexList, blockVertexList, p.center.normal);
                            // If a collision is found, save the necessary data and continue.
                            if (projection.Length() > 0f)
                            {
                                projectionList.Add(projection);
                                relVelList.Add(b.GetVelocity());
                                EdgeProperties eTemp = b.GetProperties(projection);
                                edgePropertiesList.Add(b.GetProperties(projection));
                            }
                        }
                    }
                    foreach (Doodad d in r.doodads)
                    {
                        if (p.CollisionFirstPass(d))
                            continue;
                        if (d.type == VL.DoodadType.BridgeGate)
                        {
                            List<Vector3> doodadVertexList = d.GetCollisionRect();
                            Vector3 projection = Collide(playerVertexList, doodadVertexList, p.center.normal);

                            d.ActivateDoodad(r, projection.Length() > 0f);
                        }
                        if (d.hasCollisionRect && d.type != VL.DoodadType.PowerPlug)
                        {
                            List<Vector3> doodadVertexList = d.GetCollisionRect();
                            Vector3 projection = Collide(playerVertexList, doodadVertexList, p.center.normal);

                            if (projection.Length() > 0f)
                            {
                                projectionList.Add(projection);
                                relVelList.Add(d.position.velocity);
                                edgePropertiesList.Add(new EdgeProperties());
                            }
                        }
                    }
                    foreach (Monster m in r.monsters)
                    {
                        if (p.CollisionFirstPass(m))
                            continue;
                        if (m.dead == true)
                            continue;
                        if (m.moveType == VL.MovementType.SnakeBoss)
                        {
                            List<Vector3> monsterVertexList = m.GetCollisionRect();
                            Vector3 projection = Collide(playerVertexList, monsterVertexList, Engine.player.center.normal);
                            if (projection.Length() > 0f)
                            {
                                projectionList.Add(projection);
                                relVelList.Add(m.position.velocity);
                                edgePropertiesList.Add(new EdgeProperties());
                            }
                        }
                    }

                    // Compute the most powerful collision and resolve it.
                    CollisionResult result = ResolveCollision(projectionList, relVelList, edgePropertiesList, p.center.velocity, p.HasTraction());

                    if (result.properties != null && result.properties.type == VL.EdgeType.Ice && Vector3.Dot(result.projection, p.center.direction) > 0)
                        p.sliding = true;
                    else
                        p.sliding = false;
                    p.center.velocity += result.velocityAdjustment;
                    frictionAdjustment += result.frictionAdjustment;
                    if(result.projection != Vector3.Zero)
                    {
                        p.center.position += result.projection;

                        if (result.properties.type == VL.EdgeType.Spikes || (result.properties.type == VL.EdgeType.Electric && result.properties.primaryValue > 0)
                            || (result.properties.type == VL.EdgeType.Fire && result.properties.primaryValue > 0))
                        {
                            p.Damage(result.projection, false);
                        }
                        if (result.projection.Length() > p.playerHalfWidth)
                        {
                            if (p.boosting == true)
                                p.boosting = false;
                            else
                                p.Damage(result.projection,true);
                        }
                    }
                    else
                        break;
                }

                List<Vector3> pVertexList = p.GetCollisionRect();
                foreach (Projectile s in r.projectiles)
                {
                    if (s.active == true && s.exploding == false && (s.type != ProjectileType.EyeLaser || Math.Abs(s.depth - p.depth) < .5f))
                    {
                        if (s.srcMonster == null && (s.type == ProjectileType.Missile || s.type == ProjectileType.Bomb))
                            continue;
                        s.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));
                        if (p.CollisionFirstPass(s) == false)
                        {
                            List<Vector3> projectileVertexList = s.GetCollisionRect();
                            Vector3 projection = Collide(pVertexList, projectileVertexList, Engine.player.center.normal);
                            if (projection != Vector3.Zero)
                            {
                                p.Damage(projection,false);
                                s.Detonate();

                                s.position.velocity = Vector3.Zero;
                            }
                        }
                    }
                }
                foreach (Monster m in r.monsters)
                {
                    if (m.dead == true)
                        continue;
                    m.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));
                    if (p.CollisionFirstPass(m) == false)
                    {
                        if (m.moveType == VL.MovementType.ChaseBoss)
                        {
                            List<Vector3> monsterVertexList = m.GetCollisionRect();
                            Vector3 projection = Collide(playerVertexList, monsterVertexList, Engine.player.center.normal);
                            if (projection.Length() > 0f)
                            {
                                if (m.position.velocity != Vector3.Zero)
                                    p.Damage(m.position.velocity,false);
                                else
                                    p.Damage(projection,false);
                            }
                        }
                        else if (m.moveType != VL.MovementType.SnakeBoss)
                        {
                            Vector3 distance = (p.center.position - m.unfoldedPosition.position);
                            if (distance.Length() < (p.playerHalfHeight + m.halfHeight))
                            {
                                Vector3 projection = Vector3.Normalize(distance) * ((p.playerHalfHeight + m.halfHeight) - distance.Length());
                                p.Damage(projection, false);
                            }
                        }
                    }
                }
                foreach (Doodad d in r.doodads)
                {
                    if (d.type == VL.DoodadType.Beam)
                    {
                        d.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));
                        if (p.CollisionFirstPass(d) == false)
                        {
                            List<Vector3> doodadVertexList = d.GetCollisionRect();
                            Vector3 projection = Collide(pVertexList, doodadVertexList, Engine.player.center.normal);
                            if (projection != Vector3.Zero)
                            {
                                p.Damage(projection,false);
                            }
                        }
                    }
                }

                // Now that player position is stabilized, use the special rects to detect if it is grounded
                // or prepped for a wall jump.

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            #region special-blocks for ground and walljump detection
            playerGroundBox.Add(p.center.position + p.playerHalfWidth * right);
            playerGroundBox.Add(p.center.position - p.playerHalfWidth * right);
            playerGroundBox.Add(p.center.position - (p.playerHalfHeight + .1f) * up - p.playerHalfWidth * right);
            playerGroundBox.Add(p.center.position - (p.playerHalfHeight + .1f) * up + p.playerHalfWidth * right);
            playerLeftBox.Add(p.center.position);
            playerLeftBox.Add(p.center.position - (p.playerHalfWidth + .1f) * right);
            playerLeftBox.Add(p.center.position - (p.playerHalfHeight - .1f) * up - (p.playerHalfWidth + .1f) * right);
            playerLeftBox.Add(p.center.position - (p.playerHalfHeight - .1f) * up);
            playerRightBox.Add(p.center.position + (p.playerHalfWidth + .1f) * right);
            playerRightBox.Add(p.center.position);
            playerRightBox.Add(p.center.position - (p.playerHalfHeight - .1f) * up);
            playerRightBox.Add(p.center.position - (p.playerHalfHeight - .1f) * up + (p.playerHalfWidth + .1f) * right);

            p.leftWall = false;
            p.rightWall = false;

            //p.platformVelocity = Vector3.Zero;
            foreach (Block baseBlock in r.blocks)
            {
                foreach (Block b in baseBlock.unfoldedBlocks)
                {
                    if (p.boundingBoxBottom > b.boundingBoxTop + 1 ||
                            p.boundingBoxTop < b.boundingBoxBottom - 1 ||
                            p.boundingBoxLeft > b.boundingBoxRight + 1 ||
                            p.boundingBoxRight < b.boundingBoxLeft - 1)
                        continue;
                    // if block intesects with rectVertexList
                    List<Vector3> blockVertexList = b.GetCollisionRect();

                    Vector3 groundProjection = Collide(playerGroundBox, blockVertexList, p.center.normal);
                    Vector3 leftProjection = Collide(playerLeftBox, blockVertexList, p.center.normal);
                    Vector3 rightProjection = Collide(playerRightBox, blockVertexList, p.center.normal);

                    //if (Vector3.Dot(groundProjection, up) > 0)
                    //if (groundProjection != Vector3.Zero)
                    if (groundProjection.Length() > .001f)
                    {
                        p.grounded = true;
                        EdgeProperties properties = b.GetProperties(groundProjection);
                        p.platformVelocity = b.GetVelocity();
                        if (properties.type == VL.EdgeType.ConveyorBelt)
                        {
                            Vector3 lateralDirection = Vector3.Cross(groundProjection, p.center.normal);
                            lateralDirection.Normalize();
                            p.platformVelocity += .001f * properties.primaryValue * lateralDirection;
                        }
                    }
                    if (Vector3.Dot(leftProjection, right) > 0)
                    {
                        p.leftWall = true;
                        EdgeProperties properties = b.GetProperties(leftProjection);
                        p.platformVelocity = b.GetVelocity();
                        if (properties.type == VL.EdgeType.Magnet)
                        {
                            p.Spin(leftProjection / leftProjection.Length());
                        }
                    }
                    if (Vector3.Dot(rightProjection, -right) != 0)
                    {
                        p.rightWall = true;
                        EdgeProperties properties = b.GetProperties(rightProjection);
                        p.platformVelocity = b.GetVelocity();
                        if (properties.type == VL.EdgeType.Magnet)
                        {
                            p.Spin(rightProjection / rightProjection.Length());
                        }
                    }
                }
            }

            foreach (Doodad b in r.doodads)
            {
                if (b.hasCollisionRect && b.type != VL.DoodadType.PowerPlug)
                {
                    b.UpdateBoundingBox(p.center.direction, p.right);
                    if (p.boundingBoxBottom > b.boundingBoxTop +2f ||
                        p.boundingBoxTop < b.boundingBoxBottom-2f ||
                        p.boundingBoxLeft > b.boundingBoxRight+2f ||
                        p.boundingBoxRight < b.boundingBoxLeft-2f)
                        continue;
                    // if block intesects with rectVertexList
                    List<Vector3> brickVertexList = b.GetCollisionRect();

                    Vector3 groundProjection = Collide(playerGroundBox, brickVertexList, p.center.normal);
                    Vector3 leftProjection = Collide(playerLeftBox, brickVertexList, p.center.normal);
                    Vector3 rightProjection = Collide(playerRightBox, brickVertexList, p.center.normal);

                    if (Vector3.Dot(groundProjection, up) > 0)
                    {
                        p.grounded = true;
                        p.platformVelocity = b.position.velocity;
                    }
                    if (Vector3.Dot(leftProjection, right) > 0)
                    {
                        p.leftWall = true;
                        p.platformVelocity = b.position.velocity;
                    }
                    if (Vector3.Dot(rightProjection, -right) != 0)
                    {
                        p.rightWall = true;
                        p.platformVelocity = b.position.velocity;
                    }
                }
            }

            foreach (Monster m in r.monsters)
            {
                if (p.CollisionFirstPass(m))
                    continue;
                if (m.dead == true)
                    continue;
                if (m.moveType == VL.MovementType.SnakeBoss || m.moveType == VL.MovementType.ChaseBoss)
                {
                    m.UpdateBoundingBox(p.center.direction, p.right);
                    if (p.boundingBoxBottom > m.boundingBoxTop + 2f ||
                        p.boundingBoxTop < m.boundingBoxBottom - 2f ||
                        p.boundingBoxLeft > m.boundingBoxRight + 2f ||
                        p.boundingBoxRight < m.boundingBoxLeft - 2f)
                        continue;
                    // if block intesects with rectVertexList
                    List<Vector3> brickVertexList = m.GetCollisionRect();

                    Vector3 groundProjection = Collide(playerGroundBox, brickVertexList, p.center.normal);
                    Vector3 leftProjection = Collide(playerLeftBox, brickVertexList, p.center.normal);
                    Vector3 rightProjection = Collide(playerRightBox, brickVertexList, p.center.normal);

                    if (Vector3.Dot(groundProjection, up) > 0)
                    {
                        p.grounded = true;
                        p.platformVelocity = m.position.velocity;
                    }
                    if (Vector3.Dot(leftProjection, right) > 0)
                    {
                        p.leftWall = true;
                        p.platformVelocity = m.position.velocity;
                    }
                    if (Vector3.Dot(rightProjection, -right) != 0)
                    {
                        p.rightWall = true;
                        p.platformVelocity = m.position.velocity;
                    }
                }
            }
            #endregion

                // Now that we know if the player is grounded or not, we can use the walking property to determine whether or
                // not we should apply friction.
                if (!p.walking && !p.boosting)
                    p.center.velocity += frictionAdjustment;
            }
            #endregion

            #region doodad-activation
            // Test and activate doodads.

            foreach (Doodad d in r.doodads)
            {
                if (d.type == VL.DoodadType.DialogPoint)
                {
                    if (d.active == false && d.ActivationRange(p))
                    {
                        DialogBox.SetDialog(d.targetObject);
                        d.active = true;
                    }
                }
                if (d.type == VL.DoodadType.TriggerPoint)
                {
                    if (d.active == false && d.id.Contains("Dialog") && d.ActivationRange(p))
                    {
                        DialogBox.SetDialog(d.targetObject);
                        d.active = true;
                    }
                    if (d.id.Contains("Rock2Trigger") && d.ActivationRange(p))
                        RockBoss.triggered = true;
                }
                if (d.type == VL.DoodadType.Checkpoint)
                {
                    d.ActivateDoodad(r, d == p.respawnPoint);
                }
                if (d.type == VL.DoodadType.Vortex || d.type == VL.DoodadType.JumpPad || d.type == VL.DoodadType.ItemBlock || d.isStation)
                {
                    if(Engine.player.state != State.Upgrade && Engine.player.state != State.Save)
                        d.ActivateDoodad(r, d.ActivationRange(p));
                }
                if (d.type == VL.DoodadType.Holoprojector)
                {
                    d.ActivateDoodad(r, d.ActivationRange(p));
                }
                if( (d.position.position - p.center.position).Length() < 3f*d.triggerDistance)
                {
                    if (d.isOrb && d.active)
                    {
                        d.tracking = true;
                    }
                }
                if ((d.position.position - p.center.position).Length() < d.triggerDistance)
                {
                    if (d.type == VL.DoodadType.PowerOrb)
                    {
                        if(d.active == true)
                        {
                            d.ActivateDoodad(r, false);
                            d.position.direction = Vector3.Zero;
                            d.position.normal = Vector3.Zero;
                            d.position.position = Vector3.Zero;
                            d.refreshVertexData = true;
                            foreach (Doodad powerup in d.currentRoom.doodads)
                                powerup.RefreshPowerLevels();
                            r.currentOrbs++;
                            r.parentSector.currentOrbs++;
                            r.refreshVertices = true;
                            p.orbsCollected++;
                            SoundFX.CollectOrb();
                        }
                    }
                    if (d.type == VL.DoodadType.RedCube)
                    {
                        if (d.active == true)
                        {
                            d.ActivateDoodad(r, false);
                            r.currentRedOrbs++;

                            r.parentSector.currentRedOrbs++;
                            r.refreshVertices = true;
                            p.redOrbsCollected++;
                            if (p.redOrbsCollected % 5 == 0)
                            {
                                p.naturalShield.maxAmmo = p.naturalShield.maxAmmo + 1;
                                p.naturalShield.ammo = p.naturalShield.maxAmmo;
                            }
                            SoundFX.CollectOrb();
                        }
                    }
                    if (d.type == VL.DoodadType.BlueCube)
                    {
                        if (d.active == true)
                        {
                            d.ActivateDoodad(r, false);
                            r.currentBlueOrbs++;
                            r.parentSector.currentBlueOrbs++;
                            r.refreshVertices = true;
                            SoundFX.CollectOrb();
                        }
                    }
                    if (d.type == VL.DoodadType.Checkpoint)
                    {
                        if (p.respawnPoint != d)
                        {
                            LevelLoader.QuickSave();
                            p.respawnPoint = d;
                            p.respawnPlayer = new Player();
                            p.respawnPlayer.currentRoom = p.currentRoom;
                            p.respawnPlayer.center = new Vertex(d.position.position, p.center.normal, Vector3.Zero, p.center.direction);
                        }

                    }
                    if(d.type == VL.DoodadType.WallSwitch)
                    {
                        d.Activate();
                    }
                }
            }
            #endregion

            #region doodadCollisionDetection

            foreach(Doodad d in r.doodads)
            {
                if (d.freeMotion == true)
                {
                    frictionAdjustment = Vector3.Zero;
                    for (int attempt = 0; attempt < 2; attempt++)
                    {
                        List<Vector3> projectionList = new List<Vector3>();
                        List<Vector3> relVelList = new List<Vector3>();
                        List<EdgeProperties> edgePropertiesList = new List<EdgeProperties>();

                        List<Vector3> doodadVertexList = d.GetCollisionRect();
                        d.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));
                        foreach (Block baseBlock in r.blocks)
                        {
                            foreach (Block b in baseBlock.unfoldedBlocks)
                            {
                                if (d.CollisionFirstPass(b))
                                    continue;
                                List<Vector3> blockVertexList = b.GetCollisionRect();
                                Vector3 projection = Collide(doodadVertexList, blockVertexList, p.center.normal);

                                if (projection.Length() > 0f)
                                {
                                    projectionList.Add(projection);
                                    relVelList.Add(b.GetVelocity());
                                    edgePropertiesList.Add(b.GetProperties(projection));
                                }
                            }
                        }

                        foreach (Doodad b in r.doodads)
                        {
                            b.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));

                            if (b.hasCollisionRect && b != d)
                            {
                                if (d.CollisionFirstPass(b))
                                        continue;
                                List<Vector3> brickVertexList = b.GetCollisionRect();
                                Vector3 projection = Collide(doodadVertexList, brickVertexList, p.center.normal);

                                if (projection.Length() > 0f)
                                {
                                    projectionList.Add(projection);
                                    relVelList.Add(b.position.velocity);
                                    edgePropertiesList.Add(new EdgeProperties());
                                }
                            }
                        }

                        CollisionResult result = ResolveCollision(projectionList, relVelList, edgePropertiesList, d.unfoldedPosition.velocity, false);
                        if(result.projection != Vector3.Zero)
                        {
                            d.AdjustVertex(result.projection, result.velocityAdjustment + result.frictionAdjustment, p.center.normal, p.center.direction);
                            d.position.Update(p.currentRoom, 0);
                            d.unfoldedPosition.position += result.projection;
                            d.unfoldedPosition.velocity += result.velocityAdjustment;
                            d.unfoldedPosition.velocity += result.frictionAdjustment;
                        }
                        else
                            break;
                    }

                }
            }
            foreach (Doodad d in r.doodads)
            {
                if (d.freeMotion)
                {
                    foreach (Doodad b in r.doodads)
                    {
                        if ((d.position.position - b.position.position).Length() < b.triggerDistance)
                        {
                            if (b.type == VL.DoodadType.WallSwitch)
                            {
                                b.Activate();
                            }
                            if (b.type == VL.DoodadType.PlugSlot && d.type == VL.DoodadType.PowerPlug)
                            {
                                d.position.position = b.position.position;
                                if (d.active == false)
                                {
                                    d.SetTargetBehavior();
                                }
                                d.active = true;

                            }
                        }
                    }
                }
            }

            #endregion

            #region monsters

            bool smashRockBarrier = false;

            foreach (Monster m in r.monsters)
            {
                if (m.moveType == VL.MovementType.FaceBoss)
                    continue;
                if (m.dead == true)
                    continue;
                frictionAdjustment = Vector3.Zero;
                for (int attempt = 0; attempt < 2; attempt++)
                {

                    List<Vector3> projectionList = new List<Vector3>();
                    List<Vector3> relVelList = new List<Vector3>();
                    List<EdgeProperties> edgePropertiesList = new List<EdgeProperties>();

                    List<Vector3> monsterVertexList = m.GetCollisionRect();
                    m.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));
                    foreach (Block baseBlock in r.blocks)
                    {
                        foreach (Block b in baseBlock.unfoldedBlocks)
                        {
                            if (m.CollisionFirstPass(b))
                                continue;
                            List<Vector3> blockVertexList = b.GetCollisionRect();
                            Vector3 projection = Collide(monsterVertexList, blockVertexList, p.center.normal);

                            if (projection.Length() > 0f)
                            {
                                projectionList.Add(projection);
                                relVelList.Add(b.GetVelocity());
                                edgePropertiesList.Add(b.GetProperties(projection));
                            }
                        }
                    }

                    foreach (Doodad b in r.doodads)
                    {
                        b.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));

                        if (b.hasCollisionRect && b.type != VL.DoodadType.PowerPlug)
                        {
                            if (m.CollisionFirstPass(b))
                                continue;

                            if (m.moveType == VL.MovementType.RockBoss && b.id.Contains("RockBarrier"))
                            {
                                smashRockBarrier = true;
                            }
                            if (m.moveType == VL.MovementType.ChaseBoss && b.id.Contains("ChaseBarrier"))
                            {
                                smashRockBarrier = true;
                            }
                            if (m.moveType == VL.MovementType.ChaseBoss && b.id.Contains("ChaseStop"))
                            {
                                ChaseBoss.studder = true;
                            }
                            if (m.moveType == VL.MovementType.ChaseBoss && b.type == VL.DoodadType.Brick)
                            {
                                b.ActivateDoodad(r, true);
                                continue;
                            }

                            List<Vector3> brickVertexList = b.GetCollisionRect();
                            Vector3 projection = Collide(monsterVertexList, brickVertexList, p.center.normal);

                            if (projection.Length() > 0f)
                            {
                                if (m.moveType == VL.MovementType.RockBoss && b.type == VL.DoodadType.Crate)
                                {
                                    if (m.rockBoss.rockHits > 0)
                                    {
                                        m.impactVector = projection;
                                        m.lastHitType = ProjectileType.Impact;
                                    }
                                    continue;
                                }
                                projectionList.Add(projection);
                                relVelList.Add(b.position.velocity);
                                edgePropertiesList.Add(new EdgeProperties());
                            }
                        }
                    }

                    CollisionResult result = ResolveCollision(projectionList, relVelList, edgePropertiesList, m.unfoldedPosition.velocity, false);
                    if (result.projection != Vector3.Zero)
                    {
                        m.AdjustVertex(result.projection, result.velocityAdjustment, p.center.normal, p.center.direction);
                        m.position.Update(p.currentRoom, 0);
                        m.unfoldedPosition.position += result.projection;
                        m.unfoldedPosition.velocity += result.velocityAdjustment;
                        if (result.properties.type == VL.EdgeType.Spikes)
                        {
                            m.impactVector = Monster.AdjustVector(result.projection, m.position.normal, Engine.player.center.normal, Engine.player.center.direction, true);
                            m.lastHitType = ProjectileType.Spikes;
                        }
                        if (result.projection.Length() > m.halfWidth)
                        {
                            m.impactVector = Monster.AdjustVector(result.projection, m.position.normal, Engine.player.center.normal, Engine.player.center.direction, true);
                            m.lastHitType = ProjectileType.Spikes;
                        }

                        if (Vector3.Dot(m.position.direction, Monster.AdjustVector(result.projection, m.position.normal, p.center.normal, p.center.direction, true)) <= 0)
                        {
                            m.AdjustVertex(Vector3.Zero, result.frictionAdjustment, p.center.normal, p.center.direction);
                            m.unfoldedPosition.velocity += result.frictionAdjustment;
                        }
                    }
                    else
                        break;
                }

                List<Vector3> mVertexList = m.GetCollisionRect();

                m.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));

                foreach (Monster m2 in r.monsters)
                {
                    if (m == m2 || m2.dead == true)
                        continue;
                    if (m.moveType == VL.MovementType.SnakeBoss && m2.moveType == VL.MovementType.SnakeBoss)
                        continue;
                    m2.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));

                    if (m.CollisionFirstPass(m2))
                        continue;
                    List<Vector3> brickVertexList = m2.GetCollisionRect();
                    Vector3 projection = Collide(mVertexList, brickVertexList, p.center.normal);

                    if (projection.Length() > 0f)
                    {
                        m.AdjustVertex(.3f*projection, Vector3.Zero, p.center.normal, p.center.direction);
                        m.position.Update(p.currentRoom, 0);
                        m.unfoldedPosition.position += .3f * projection;
                        m2.AdjustVertex(-.3f * projection, Vector3.Zero, p.center.normal, p.center.direction);
                        m2.position.Update(p.currentRoom, 0);
                        m2.unfoldedPosition.position -= .3f * projection;
                    }
                }

                foreach (Projectile s in r.projectiles)
                {
                    if (s.type == ProjectileType.EyeLaser)
                        continue;
                    if (s.type == ProjectileType.Missile && s.srcMonster == null && (s.position.position - m.position.position).Length() < 7f)
                    {
                        s.SetTarget(m.position.position);
                    }
                    //if (s.active == true || m != s.srcMonster)
                    if (s.srcMonster != null && s.srcMonster.moveType == VL.MovementType.SnakeBoss && m.moveType == VL.MovementType.SnakeBoss)
                        continue;
                    if (m != s.srcMonster)
                    {
                        s.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));
                        if (m.CollisionFirstPass(s) == false)
                        {
                            List<Vector3> projectileVertexList = s.GetCollisionRect();
                            Vector3 projection = Collide(mVertexList, projectileVertexList, Engine.player.center.normal);
                            if (projection != Vector3.Zero)
                            {
                                s.Detonate();
                                m.impactVector = Monster.AdjustVector(s.position.velocity, m.position.normal, Engine.player.center.normal, Engine.player.center.direction, true);
                                m.lastHitType = s.type;
                                s.position.velocity = Vector3.Zero;
                            }
                        }

                    }
                }

                List<Vector3> monsterGroundBox = m.GetGroundCollisionRect();
                List<Vector3> monsterForwardGroundBox = m.GetForwardGroundCollisionRect();
                List<Vector3> monsterForwardBox = m.GetForwardCollisionRect();

                m.groundProjection = Vector3.Zero;
                m.forwardGroundProjection = Vector3.Zero;
                m.forwardProjection = Vector3.Zero;
                foreach (Block baseBlock in r.blocks)
                {
                    foreach (Block b in baseBlock.unfoldedBlocks)
                    {
                        if (m.boundingBoxBottom > b.boundingBoxTop + 2 ||
                                m.boundingBoxTop < b.boundingBoxBottom - 2 ||
                                m.boundingBoxLeft > b.boundingBoxRight + 2 ||
                                m.boundingBoxRight < b.boundingBoxLeft - 2)
                            continue;
                        // if block intesects with rectVertexList
                        List<Vector3> blockVertexList = b.GetCollisionRect();

                        Vector3 groundProjection = Collide(monsterGroundBox, blockVertexList, p.center.normal);
                        Vector3 forwardGroundProjection = Collide(monsterForwardGroundBox, blockVertexList, p.center.normal);
                        Vector3 forwardProjection = Collide(monsterForwardBox, blockVertexList, p.center.normal);

                        if (forwardGroundProjection != Vector3.Zero)
                            m.forwardGroundProjection = Monster.AdjustVector(forwardGroundProjection, m.position.normal, p.center.normal, p.center.direction, true);
                        if (forwardProjection != Vector3.Zero)
                            m.forwardProjection = Monster.AdjustVector(forwardProjection, m.position.normal, p.center.normal, p.center.direction, true);
                        if (groundProjection != Vector3.Zero)
                            m.groundProjection = Monster.AdjustVector(groundProjection, m.position.normal, p.center.normal, p.center.direction, true);
                    }
                }
                foreach (Monster m2 in r.monsters)
                {
                    if (m == m2 || m2.dead == true)
                        continue;
                    if (m.boundingBoxBottom > m2.boundingBoxTop + 2 ||
                            m.boundingBoxTop < m2.boundingBoxBottom - 2 ||
                            m.boundingBoxLeft > m2.boundingBoxRight + 2 ||
                            m.boundingBoxRight < m2.boundingBoxLeft - 2)
                        continue;
                    // if block intesects with rectVertexList
                    List<Vector3> blockVertexList = m2.GetCollisionRect();

                    Vector3 forwardProjection = Collide(monsterForwardBox, blockVertexList, p.center.normal);

                    if (forwardProjection != Vector3.Zero)
                    {
                        m.forwardProjection = Monster.AdjustVector(forwardProjection, m.position.normal, p.center.normal, p.center.direction, true);
                    }

                }
            }

            if (smashRockBarrier == true)
            {
                foreach (Doodad d in r.doodads)
                {
                    if (d.id.Contains("RockBarrier") || d.id.Contains("ChaseBarrier"))
                    {
                        d.ActivateDoodad(r, true);
                    }
                }
            }

            #endregion

            #region projectile-collisions
            foreach (Projectile s in r.projectiles)
            {
                if (s.type == ProjectileType.EyeLaser)
                    continue;
                frictionAdjustment = Vector3.Zero;

                List<Vector3> projectionList = new List<Vector3>();
                List<Vector3> relVelList = new List<Vector3>();
                List<EdgeProperties> edgePropertiesList = new List<EdgeProperties>();

                List<Vector3> doodadVertexList = s.GetCollisionRect();
                s.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));
                foreach (Block baseBlock in r.blocks)
                {
                    foreach (Block b in baseBlock.unfoldedBlocks)
                    {
                        if (s.CollisionFirstPass(b))
                            continue;
                        List<Vector3> blockVertexList = b.GetCollisionRect();
                        Vector3 projection = Collide(doodadVertexList, blockVertexList, p.center.normal);
                        if (projection != Vector3.Zero)
                        {
                            s.Detonate();
                            s.position.velocity = Vector3.Zero;
                        }
                    }
                }

                foreach (Doodad b in r.doodads)
                {
                    b.UpdateBoundingBox(p.center.direction, Vector3.Cross(p.center.direction, p.center.normal));

                    if ((b.hasCollisionRect && b.type != VL.DoodadType.PowerPlug) || (b.type == VL.DoodadType.LaserSwitch && s.type == ProjectileType.Laser && b.active == false))
                    {
                        if (s.CollisionFirstPass(b))
                            continue;
                        List<Vector3> brickVertexList = b.GetCollisionRect();
                        Vector3 projection = Collide(doodadVertexList, brickVertexList, p.center.normal);
                        if (projection != Vector3.Zero)
                        {
                            s.Detonate();
                            s.position.velocity = Vector3.Zero;

                            if (b.type == VL.DoodadType.LaserSwitch && s.type == ProjectileType.Laser)
                            {
                                b.ActivateDoodad(r, true);
                                b.SetTargetBehavior();
                            }
                            if ((s.type == ProjectileType.Bomb || s.type == ProjectileType.Missile) && s.exploding == true && b.type == VL.DoodadType.Brick)
                            {
                                b.ActivateDoodad(r, true);
                            }
                        }
                    }
                }

            }
            #endregion

            p.center.Update(r, 0);
        }