public virtual void CheckCollision(Level level)
        {
            foreach (CellObject levelObject in level.collidableObjects)
            {
                if (levelObject.isCollidable && Hitbox.Intersects(levelObject.Hitbox) && levelObject != this)
                {
                    /**Determining what side was hit**/
                    float wy = (levelObject.Hitbox.Width + Hitbox.Width)
                             * (((levelObject.Hitbox.Y + levelObject.Hitbox.Height) / 2) - (Hitbox.Y + Hitbox.Height) / 2);
                    float hx = (Hitbox.Height + levelObject.Hitbox.Height)
                             * (((levelObject.Hitbox.X + levelObject.Hitbox.Width) / 2) - (Hitbox.X + Hitbox.Width) / 2);

                    Button tmpButton = levelObject as Button;
                    if (tmpButton != null) //if it is a button
                    {
                        Button button = (Button)levelObject as Button;
                        button.IsPressed = true;
                    }
                    if (!levelObject.IsPassable)
                    { //same logic as Character- if levelObject is passable, no need to handle physics
                        if (wy > hx)
                        {
                            if (wy > -hx) //hitting something above
                            {
                                //Game1.boxHitState = "Box Top";//top
                                Position = new Vector3(Position.X, levelObject.Hitbox.Bottom - this.Hitbox.Height, 0); //clip to the top of the colliding object

                                //end all downward acceleration (eg. gravity) and velocity
                                //TransAccel = Vector3.Zero;
                                TransVelocity = new Vector3(TransVelocity.X, Math.Min(TransVelocity.Y, GameConstants.SINGLE_CELL_SIZE * 2), TransVelocity.Z); //cease upward velocity
                            }
                            else
                            {
                                //boxHitState = "Box Left";// left
                                Position = new Vector3(levelObject.Hitbox.Right, Position.Y, 0);
                                TransVelocity = new Vector3(Math.Max(TransVelocity.X, -GameConstants.SINGLE_CELL_SIZE * 2), TransVelocity.Y, TransVelocity.Z); //cease velocity
                                //adjacentObj = levelObject;
                            }
                        }
                        else
                        {
                            if (wy > -hx)
                            {
                                //boxHitState = "Box Right";// right
                                Position = new Vector3(levelObject.Hitbox.Left - this.Hitbox.Width, Position.Y, 0);
                                TransVelocity = new Vector3(Math.Min(TransVelocity.X, GameConstants.SINGLE_CELL_SIZE * 2), TransVelocity.Y, TransVelocity.Z); //cease velocity
                                //adjacentObj = levelObject;
                            }
                            else
                            { //hitting something below
                                //boxHitState = "Box Bottem";//bottem
                                //Game1.boxPosition = "{"+Position.X+", "+Position.Y+", "+Position.Z+"}";
                                Position = new Vector3(Position.X, levelObject.Hitbox.Bottom, 0); //clip to the top of the colliding object
                                TransVelocity = new Vector3(TransVelocity.X, Math.Max(TransVelocity.Y, -GameConstants.SINGLE_CELL_SIZE * 2), TransVelocity.Z); //cease velocity
                                /*Note that not all velocity is reset, to avoid an issue with 'box shaking,' due to:
                                 *  when velocity would be reset, there would be at least one frame where
                                 *  box would change position (eg. from gravity), that position would be large enough to make a difference in how it's drawn
                                 *  while not reaching a value that would lead to collision (ie. an intersection of hitboxes (which would be truncated
                                 *  integers representing position)
                                 *  and another frame where box would be in its original position due to the collision
                                */
                                //jumping = false;
                            }
                        }
                    }
                }
                //boxHitState = "No box";
            }
        }
        /// <summary>
        /// Builds a new level.
        /// </summary>
        /// <param name="levelNum"></param>
        /// <param name="renderContext"></param>
        /// <returns></returns>
        public static Level MakeBasicLevel(int levelNum, RenderContext renderContext)
        {
            Level level = new Level();
            levelSelect = "level" + levelNum.ToString();

            //read level from text file - width and height of level will depend on the text file's characters
            /*
             Legend:
             * @ - Exit
             * B - box; 2 - box dropper with 2 boxes (and any other non-zero digit would be a box dropper with said # boxes);
             * T - toggle switch (can repeatedly use); t - toggle switch (only can use once);
             * S - button switch
             * X - Level wall/block
             * d - door (open by default); D - door (closed by default)
             * r - trapdoor (open by default); R - trapdoor (closed by default)
             * P - player; G - goal
             * L - laser turret
             *   - empty space
             * m - message event
             *
             * In order to match trapdoors/doors with switches, can have at the end of the txt file the (row,col) coordinates of each of the paired objects to be linked, in the following format:
             * [row,col]:[row,col];
             * (It's either this, or not have simple characters for the properties ... I think I may prefer this, unless there is a tool that allows easy parsing of XML data or such.)
             * Format for moving platforms:
             * [row,col]:[platform distance]
             */

            //Note: The levels' txt files currently have a new line at the very end of it. Don't delete it.

            string leveltxtfile = FromFile("Levels/" + levelSelect + ".txt");
            string backtxt = FromFile("Levels/" + levelSelect + "Back.txt");

            //get object pairs (for links between switches and doors/boxes)
            // The format used to link buttons to doors "ButtonCoord linked to 1 or more DoorCoord" - Steven

            //differentiate level and link strings
            string leveltxt = null; //everything above the line of "~" in Level.txt
            string linktxt = null; //everything below the line of "~" in Level.txt
                                   //split leveltxtfile into leveltxt and linktxt, with the text enclosed by any number of "~" characters as the delimiter

            int pos = leveltxtfile.IndexOf("~"); //go to the "~" line
            leveltxt = leveltxtfile.Substring(0, pos);
            //put pos on the next line after the last "~" line
            pos = leveltxtfile.LastIndexOf("~"); //go to last ~
            pos = leveltxtfile.IndexOf("\n", pos) + 1; //go to next line, after the last ~
            linktxt = leveltxtfile.Substring(pos);

            Dictionary<string, int> _firstobject = new Dictionary<string, int>();
            Dictionary<string, int> _linkedobjects = new Dictionary<string, int>();

            String newline = "\r\n"; //in case a newline were to be used
            levelheight = leveltxt.Length - leveltxt.Replace("\n", "").Length;
            levelwidth = 0; //reset this each time a new level is made

            CellObject lastXBlock = new CellObject(0, 0);
            CellObject DoorAfterXBlock = new CellObject(0, 0);
            Enemy e = new Enemy();
            bool lookForNextXBlock = false;

            //there will be walls and floor enclosing the aforementioned level
            //iterate through level string, find the level height and width from iterating through the txt file
            int row = startFloor + levelheight - 1, col = startWall;
            foreach (char c in leveltxt)
            {

                switch (c) //convert char to level object at the coordinate iterated through
                {
                    case ' ':
                        col++;
                        break;
                    case 'E':
                        e = new Enemy(col++, row, renderContext);
                        level.AddChild(e);
                        e.wallsToCheck.Add(lastXBlock);
                        lookForNextXBlock = true;
                        level.enemyList.Add(e);
                        break;
                    case 'M':
                        level.AddChild(new MovingPlatform(col++, row));
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        break;
                    case 'm':
                        MessageEvent message = new MessageEvent(col++, row, renderContext);
                        level.AddChild(message);
                        level.Messages.Add("" + row + ":" + (col - startWall), message);
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        break;
                    case 'B':
                        PickableBox p = new PickableBox(col++, row);
                        level.AddChild(p); //replace BasicBlock with the actual object once implemented
                        break;
                    case 'T': //Toggleable lever switch
                        level.AddChild(new ToggleSwitch(col++, row, true));
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1); // Adds the coordinates and actual index of the button
                        break;
                    case 't': //One-time lever switch
                        level.AddChild(new ToggleSwitch(col++, row, false));
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1); // Adds the coordinates and actual index of the button
                        break;
                    case 'S':
                        level.AddChild(new Button(col++, row));
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1); // Adds the coordinates and actual index of the button
                        break;
                    case 'X':
                        BasicBlock blockToAdd = new BasicBlock(col++, row);
                        level.AddChild(blockToAdd);
                        level.ForegroundBlocks.Add(blockToAdd);
                        lastXBlock = (CellObject)blockToAdd;
                        if (lookForNextXBlock)
                        {
                            lookForNextXBlock = false;
                            e.wallsToCheck.Add(lastXBlock);
                        }
                        break;
                    case 'L':
                        level.AddChild(new LaserTurret(col++, row, true, GameConstants.POINTDIR.pointLeft));
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        break;
                    case 'd':
                        level.AddChild(new Door(col++, row, true)); //Starting open door
                        _linkedobjects.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        break;
                    case 'D':
                        //closed = new Door(col++, row, true);
                        level.AddChild(new Door(col++, row, false)); //Starting closed door
                        _linkedobjects.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        break;
                    case 'r':
                        level.AddChild(new Trapdoor(col++, row, true));
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        _linkedobjects.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        break;
                    case 'R':
                        level.AddChild(new Trapdoor(col++, row, false));
                        _firstobject.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        _linkedobjects.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                        break;
                    case 'P':
                        level.PlayerPoint = new Point(col++, row); //set player position
                        break;
                    case '@':
                        level.AddChild(new ExitBlock(col++, row));
                        break;
                    case 'G':
                        level.AddChild(new BasicBlock(col++, row));
                        break;
                    case '\n': //the '\n' of the new line/row
                        row--;
                        if (col > levelwidth + startWall) //to get max # columns found - check if greater than largest levelwidth found;
                            levelwidth = col - startWall;
                        col = startWall;
                        break;
                }
                if (c >= '1' && c <= '9')
                { //BoxDropper case
                    level.AddChild(new BoxDropper(col++, row, c - '0')/*new BoxDropper(c - '0')*/ );
                    _linkedobjects.Add("" + row + ":" + (col - startWall), level.Children.Count - 1);
                }
            }

            level.collidableObjects = new List<GameObject3D>();
            level.collidableObjects.AddRange(level.Children); // All objects that will be colliding with the player in the same Z axis - Steven
            level.Position = new Vector3(-185, -350, 0);
            level.HitboxWidth = levelwidth * 48;
            level.HitboxHeight = -levelheight * 48 * 2;

            // Interates through the link text to find objects, and:
            // -their links to other objects (eg. doors, boxdroppers)
            // and/or
            // -other properties set to those objects
            // Steven, Jacob
            if (linktxt.Length != 0)
            {
                string[] buttonLinks = linktxt.Split('\n'); //Each line

                foreach (string links in buttonLinks)
                {
                    string[] ObjectAndSettings = links.Split('|');
                    string[] LinkedObjects = ObjectAndSettings[1].Split('&');
                    int index = _firstobject[ObjectAndSettings[0]];

                    //Parse the links for button and switch
                    if (level.Children[index].GetType() == typeof(Button))
                    {
                        Button button = (Button)level.Children[index];
                        foreach (string door in LinkedObjects)
                        {
                            index = _linkedobjects[door];
                            SwitchableObject doorToAdd = (SwitchableObject)level.Children[index];
                            button.LinkedDoors.Add(doorToAdd);
                        }
                    }
                    else if (level.Children[index].GetType() == typeof(ToggleSwitch))
                    {
                        ToggleSwitch toggleSwitch = (ToggleSwitch)level.Children[index];
                        if (ObjectAndSettings[1].Contains(':')) //check if the settings are regarding coordinates, or the number of possible toggle times
                        {
                            foreach (string door in LinkedObjects) //add each linked object to the doors list
                            {
                                index = _linkedobjects[door];
                                SwitchableObject doorToAdd = (SwitchableObject)level.Children[index];
                                toggleSwitch.LinkedDoors.Add(doorToAdd);

                                //if linked item is BoxDropper, set the toggle switch's number of possible toggles to the number of boxes that the box dropper has, by default
                                if (doorToAdd.GetType() == typeof(BoxDropper))
                                {
                                    toggleSwitch.RemainingToggles = ((BoxDropper)doorToAdd).NumberOfBoxes;
                                }
                            }
                        }
                        else
                        {   //if the settings are regarding toggle times, parse that as toggle times
                            int ToggleTimes = 0;
                            bool isInt = Int32.TryParse(ObjectAndSettings[1], out ToggleTimes);
                            if (isInt)
                            {
                                toggleSwitch.RemainingToggles = ToggleTimes;
                            }
                        }
                    }

                    //Jacob - For moving platform - set moving platform initial direction and distance
                    if (level.Children[index].GetType() == typeof(MovingPlatform))
                    {
                        string[] Settings = ObjectAndSettings[1].Split(',');
                        MovingPlatform movingPlatform = (MovingPlatform)level.Children[index];
                        //set initial direction of moving platform
                        if (Settings[0] == "L")
                        {
                            movingPlatform.movingDirection = GameConstants.DIRECTION.Left;
                        }
                        else if (Settings[0] == "R")
                        {
                            movingPlatform.movingDirection = GameConstants.DIRECTION.Right;
                        }
                        else if (Settings[0] == "U")
                        {
                            movingPlatform.movingDirection = GameConstants.DIRECTION.Up;
                        }
                        else if (Settings[0] == "D")
                        {
                            movingPlatform.movingDirection = GameConstants.DIRECTION.Down;
                        }
                        movingPlatform.maxDistance = Int32.Parse(Settings[1]) * GameConstants.SINGLE_CELL_SIZE;
                    }
                    //Jacob - Set Laser turret direction
                    if (level.Children[index].GetType() == typeof(LaserTurret))
                    {
                        LaserTurret laserTurret = (LaserTurret)level.Children[index];
                        string[] Settings = ObjectAndSettings[1].Split(',');
                        //set initial direction of moving platform
                        if (Settings[0] == "L")
                        {
                            laserTurret.direction = GameConstants.POINTDIR.pointLeft;
                        }
                        else
                            if (Settings[0] == "R")
                        {
                            laserTurret.direction = GameConstants.POINTDIR.pointRight;
                        }
                        //optional 2nd setting - set starting offset of laser turret, in milliseconds.
                        if (Settings.Length >= 2)
                        {
                            laserTurret.elapsedFireTimeOffset = Int32.Parse(Settings[1]);
                        }
                    }

                    //Message event
                    if (level.Children[index].GetType() == typeof(MessageEvent))
                    {
                        level.Messages[ObjectAndSettings[0]].Message = ObjectAndSettings[1];
                    }

                    //Trapdoor
                    if (level.Children[index].GetType() == typeof(Trapdoor))
                    {
                        Trapdoor trapDoor = (Trapdoor)level.Children[index];

                        //Update trapdoors to face the bottom instead
                        if (ObjectAndSettings[1] == "B")
                            trapDoor.faceBottom();
                    }
                }
            }

            //DRAWS BACKGROUND
            row = startFloor + levelheight - 1;
            col = startWall;
            foreach (char c2 in backtxt)
            {
                switch (c2) //convert char to level object at the coordinate iterated through
                {
                    case '1': //White tile
                        level.Background[1].Add(new BackgroundBlock(col++, row));
                        break;
                    case '2': //Metal Vent
                        level.Background[2].Add(new BackgroundBlock(col++, row));
                        break;
                    case '3': //pipe arrangement 1 on bluish gray tile
                        level.Background[3].Add(new BackgroundBlock(col++, row));
                        break;
                    case '4': //pipe arrangement 2 on bluish gray tile
                        level.Background[4].Add(new BackgroundBlock(col++, row));
                        break;
                    case '5': //Black tile
                        level.Background[5].Add(new BackgroundBlock(col++, row));
                        break;
                    case '6': //Black tile
                        level.Background[6].Add(new BackgroundBlock(col++, row));
                        break;
                    case '7': //Black tile
                        level.Background[7].Add(new BackgroundBlock(col++, row));
                        break;
                    case '8': //Black tile
                        level.Background[8].Add(new BackgroundBlock(col++, row));
                        break;
                    case '9': //Black tile
                        level.Background[9].Add(new BackgroundBlock(col++, row));
                        break;
                    case 's': //emcsqaure
                        level.Background[10].Add(new BackgroundBlock(col++, row));
                        break;
                    case 'e': //einstien
                        level.Background[11].Add(new BackgroundBlock(col++, row));
                        break;
                    case 'a': //atom1
                        level.Background[12].Add(new BackgroundBlock(col++, row));
                        break;
                    case 'q': //atom2
                        level.Background[13].Add(new BackgroundBlock(col++, row));
                        break;
                    case 'z': //chalkboard1
                        level.Background[14].Add(new BackgroundBlock(col++, row));
                        break;
                    case 'x': //chalkboard2
                        level.Background[15].Add(new BackgroundBlock(col++, row));
                        break;
                    case 'c': //chalkboard3
                        level.Background[16].Add(new BackgroundBlock(col++, row));
                        break;
                    case 'v': //chalkboard4
                        level.Background[17].Add(new BackgroundBlock(col++, row));
                        break;

                    case '\n': //new line/row
                        row--;
                        col = startWall;
                        break;
                    default: //Regular bluish gray tile
                        level.Background[0].Add(new BackgroundBlock(col++, row));
                        break;
                }
            }

            return level;
        }