/// <summary> /// Loads the room into memory. /// If IsPersistant is set to true, loads up the previously saved State file /// </summary> /// <param name="doorIndex">Represents which door the player is entering from. /// If set to -1, player will enter at the default spawning location.</param> public void Load(string filePath, int doorIndex) { if (filePath != "" && filePath != null) { try { int numberOfDoors; int numberOfEnemies; int numberOfEnvironmentObjects; using (Stream stream = TitleContainer.OpenStream(filePath)) { using (StreamReader sr = new StreamReader(stream)) { longName = GameResources.getNextDataLine(sr, "#"); graphicsName = GameResources.getNextDataLine(sr, "#"); spawnLocation = new Vector2(Convert.ToInt16(GameResources.getNextDataLine(sr, "#")), Convert.ToInt16(GameResources.getNextDataLine(sr, "#"))); isPersistant = bool.Parse(GameResources.getNextDataLine(sr, "#")); hasLighting = bool.Parse(GameResources.getNextDataLine(sr, "#")); musicName = GameResources.getNextDataLine(sr, "#"); numberOfDoors = Convert.ToInt16(GameResources.getNextDataLine(sr, "#")); doorArray = new Door[numberOfDoors]; for (int i = 0; i < numberOfDoors; i++) { Door.DoorOrientations orientation = (Door.DoorOrientations)byte.Parse(GameResources.getNextDataLine(sr, "#")); string roomName = GameResources.getNextDataLine(sr, "#"); int connectedDoorIndex = Convert.ToInt16(GameResources.getNextDataLine(sr, "#")); Locks lockType = (Locks)byte.Parse(GameResources.getNextDataLine(sr, "#")); doorArray[i] = new Door(Content, soundEngine, orientation, roomName, connectedDoorIndex, lockType); doorArray[i].Spawn(new Vector2(float.Parse(GameResources.getNextDataLine(sr, "#")), float.Parse(GameResources.getNextDataLine(sr, "#")))); } numberOfEnemies = Int16.Parse(GameResources.getNextDataLine(sr, "#")); enemyArray = new Enemy[numberOfEnemies]; for (int i = 0; i < numberOfEnemies; i++) { String enemyName = GameResources.getNextDataLine(sr, "#"); enemyArray[i] = new Enemy(enemyName, Content); enemyArray[i].Spawn(new Vector2(Int16.Parse(GameResources.getNextDataLine(sr, "#")), Int16.Parse(GameResources.getNextDataLine(sr, "#")))); } numberOfEnvironmentObjects = Int16.Parse(GameResources.getNextDataLine(sr, "#")); environmentArray = new PhysicsObject[numberOfEnvironmentObjects]; for (int i = 0; i < numberOfEnvironmentObjects; i++) { String objectName = GameResources.getNextDataLine(sr, "#"); bool objHasGraphics = bool.Parse(GameResources.getNextDataLine(sr, "#")); environmentArray[i] = new PhysicsObject(objectName, Content, new Vector2(0,0), objHasGraphics, soundEngine, false); environmentArray[i].IsSolid = bool.Parse(GameResources.getNextDataLine(sr, "#")); environmentArray[i].Spawn(new Vector2(Int16.Parse(GameResources.getNextDataLine(sr, "#")), Int16.Parse(GameResources.getNextDataLine(sr, "#")))); } objectArray = new GameObject[numberOfDoors + numberOfEnemies + numberOfEnvironmentObjects]; int arrayIndex = 0; for (int i = 0; i < numberOfDoors; i++) { objectArray[i + arrayIndex] = doorArray[i + arrayIndex]; } arrayIndex += numberOfDoors; for (int i = 0; i < numberOfEnemies; i++) { objectArray[i + arrayIndex] = enemyArray[i]; } arrayIndex += numberOfEnemies; for (int i = 0; i < numberOfEnvironmentObjects; i++) { objectArray[i + arrayIndex] = environmentArray[i]; } if (doorIndex != -1) { spawnLocation = doorArray[doorIndex].Position; if (doorArray[doorIndex].Orientation == Door.DoorOrientations.FacingLeft) spawnLocation.X -= Player.PLAYER_WIDTH; else spawnLocation.X += doorArray[doorIndex].HitBox.Width; } sr.Close(); isLoaded = true; } } } catch (Exception e) { System.Diagnostics.Debug.WriteLine("An error occurred: " + e.Message); } } }
/// <summary> /// Another constructor that also specifies position, whether the object is an enemy, /// whether it has graphics that will be drawn, and the source of its sounds, if it produces any. /// </summary> /// <param name="objName">The type of object that is represented.</param> /// <param name="content">The content manager to load assets to.</param> /// <param name="spawnPosition">The coordinates in the room at which the object will start.</param> /// <param name="graphics">Whether the object has graphics that will be drawn to the screen.</param> /// <param name="audioEngine">The AudioEngine object that produces this object's sounds.</param> /// <param name="enemy">Whether the object is an enemy.</param> public PhysicsObject(string objName, ContentManager content, Vector2 spawnPosition, bool graphics, AudioEngine audioEngine, bool enemy) : base(objName, content, spawnPosition, graphics, audioEngine) { CheckObjectType(); if (isPhysicsObject) { velocityX = 0; velocityY = 0; accelerationX = 0; accelerationY = 0; velocityLimitX = 0; velocityLimitY = 0; displacementX = 0; displacementY = 0; isOnGround = false; currentHealth = maxHealth; riding = null; LoadObjectData(); } }
/// <summary> /// Changes all of the object's relevant properties to reflect that /// it has just now become airborne (i.e. no longer on ground). /// </summary> public virtual void LeaveGround() { isOnGround = false; riding = null; }
/// <summary> /// Checks to see if an object is stuck inside of a solid region or object at its /// current coordinates, OR if it *will be* stuck if its coordinates are adjusted /// by specified amounts in the x and/or y positions. /// Non-zero values may be input for dX and/or dY to test for stuckness at the /// coordinates equal to the object's coordinates plus the vector (dX, dY). /// </summary> /// <param name="room">The room in which to test for stuckness</param> /// <param name="dX">The value by which to adjust the x-coordinate in the test</param> /// <param name="dY">The value by which to adjust the y-coordinate in the test</param> /// <returns></returns> public virtual bool IsStuck(Room room, int dX, int dY) { //If dX != 0, it's added to the test x-coordinate int CoordinateX = (int)Position.X + dX; //If the leftmost collision points are past the left of the map, or //if the rightmost collision points are past the right of the map, //the object is stuck. if (CoordinateX + collisionXs.First() < 0 || CoordinateX + collisionXs.Last() >= room.CollisionMap.Width) return true; //If dY != 0, it's added to the test y-coordinate int CoordinateY = (int)Position.Y + dY; foreach (int intY in collisionYs) { //Collision points above or below the map will not cause stuckness. if (CoordinateY + intY >= 0 && CoordinateY + intY < room.CollisionMap.Height) { foreach (int intX in collisionXs) { //Walls/grounds/ceilings are black on the collision map, i.e. the R value is 0 if (room.collisionColors[CoordinateX + intX + (CoordinateY + intY) * room.CollisionMap.Width].R == 0) return true; } } } foreach (GameObject obj in room.ObjectArray) { if (obj.IsSolid && obj.IsSpawned && this != obj) { if ((CoordinateX + collisionXs.First() <= obj.Position.X + obj.HitBox.Width) && (CoordinateX + collisionXs.Last() >= obj.Position.X) && (CoordinateY + collisionYs.First() <= obj.Position.Y + obj.HitBox.Height) && (CoordinateY + collisionYs.Last() >= obj.Position.Y)) { if (dX == 0 & obj.IsPhysicsObject) riding = (PhysicsObject)obj; return true; } } } return false; }
/// <summary> /// Checks to see if the object is touching ground at its current coordinates, OR /// if the object *will be* touching ground if its coordinates are adjusted by /// specified amounts in the x and/or y directions. /// Non-zero values may be input for dX and/or dY to test for ground at the coordinates /// equal to the object's coordinates plus the vector (dX, dY). /// </summary> /// <param name="room">The room in which to test for ground</param> /// <param name="dX">The value by which to adjust the x-coordinate in the test</param> /// <param name="dY">The value by which to adjust the y-coordinate in the test</param> /// <returns></returns> public virtual bool CheckGround(Room room, int dX, int dY) { //row is the y-coordinate just beneath the object's hitbox at its //(adjusted) coordinates. int row = (int)Position.Y + dY + collisionYs.Last() + 1; //All space above or below the map is not considered ground. if (row < 0 || row >= room.CollisionMap.Height) return false; //If the row is on the collision map, do a color test on //all collision points in the row: int coordinateX = (int)Position.X + dX; foreach (int intX in collisionXs) { //Walls/grounds/ceilings are black on the collision map, i.e. the R value is 0 if (room.collisionColors[(int)(coordinateX + intX + row * room.CollisionMap.Width)].R == 0) return true; } //If none of the collision points are in a black region, there is no ground. foreach (GameObject obj in room.ObjectArray) { if (obj.IsSolid && obj.IsSpawned && this != obj) { if ((coordinateX + collisionXs.First() <= obj.Position.X + obj.HitBox.Width) && (coordinateX + collisionXs.Last() >= obj.Position.X) && (row >= obj.Position.Y) && (row <= obj.Position.Y + obj.HitBox.Height)) { obj.StandingOn(objectName); if(obj.IsPhysicsObject) riding = (PhysicsObject)obj; return true; } } } return false; }
/// <summary> /// Tests to see if an object's intended x- and y-displacements are fully achievable in its /// current room and position. Causes a collision and modifies the displacement value if /// it would send the object into a collideable surface. /// </summary> /// <param name="obj">The object to be evaluated.</param> /// <param name="room">The room in which the object is located and trying to move.</param> /// <param name="time">The amount of time since the last frame.</param> public static void Update(PhysicsObject obj, Room room, GameTime time) { PhysicsObject ridingAtStart = obj.riding; float totalTime = (float)(time.ElapsedGameTime.TotalSeconds); //All ungrounded, gravity-affected objects will have the displacement caused by //gravity in this frame added to their y-displacement. if (obj.IsGravityAffected && !obj.IsOnGround) obj.DisplacementY = Math.Min(obj.DisplacementY + (GRAVITY / 2) * (totalTime * totalTime), MAX_FALLING_SPEED * totalTime); obj.DisplacementX = (float)((int)(obj.DisplacementX)); obj.DisplacementY = (float)((int)(obj.DisplacementY)); //If the object will get stuck trying to move the originally intended amount, a collision //has occurred. The appropriate velocity & acceleration variables as well as boolean flags //will be reset, by calling the appropriate collision function (HitCeiling(), Land(), or //HitWall()). //Then the intended displacement is decreased by one until the object finds a coordinate //at which it will no longer be stuck. if (obj.DisplacementY < 0) { if (obj.IsStuck(room, 0, (int)obj.DisplacementY)) { obj.HitCeiling(); obj.DisplacementY += 1; while (obj.DisplacementY != 0 && obj.IsStuck(room, 0, (int)obj.DisplacementY)) obj.DisplacementY += 1; } if (obj.SticksToSurfaces && obj.DisplacementX == 0) { if (obj.WillLoseSurface(room)) { while (obj.WillLoseSurface(room)) obj.DisplacementY += 1; } } } else if (obj.DisplacementY > 0) { if (obj.IsStuck(room, 0, (int)obj.DisplacementY)) { obj.Land(); obj.DisplacementY -= 1; while (obj.DisplacementY != 0 && obj.IsStuck(room, 0, (int)obj.DisplacementY)) obj.DisplacementY -= 1; } if (obj.SticksToSurfaces && obj.DisplacementX == 0) { if (obj.WillLoseSurface(room)) { while (obj.WillLoseSurface(room)) obj.DisplacementY -= 1; } } } if (obj.DisplacementX > 0) { if (obj.IsStuck(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) { obj.CollideRight(); obj.DisplacementX -= 1; while (obj.DisplacementX != 0 && obj.IsStuck(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.DisplacementX -= 1; } if (!obj.MovesOffEdges && obj.IsOnGround && obj.DisplacementY == 0) { if (obj.WillMovePastEdge(room)) { obj.VelocityX *= -1; while (obj.WillMovePastEdge(room)) obj.DisplacementX -= 1; } } if (obj.SticksToSurfaces && obj.DisplacementY == 0) { if (obj.WillLoseSurface(room)) { while (obj.WillLoseSurface(room)) obj.DisplacementX -= 1; } } } else if (obj.DisplacementX < 0) { if (obj.IsStuck(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) { obj.CollideLeft(); obj.DisplacementX += 1; while (obj.DisplacementX != 0 && obj.IsStuck(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.DisplacementX += 1; } if (!obj.MovesOffEdges && obj.IsOnGround && obj.DisplacementY == 0) { if (obj.WillMovePastEdge(room)) { obj.VelocityX *= -1; while (obj.WillMovePastEdge(room)) obj.DisplacementX += 1; } } if (obj.SticksToSurfaces && obj.DisplacementY == 0) { if (obj.WillLoseSurface(room)) { while (obj.WillLoseSurface(room)) obj.DisplacementX += 1; } } } else if (obj.DisplacementX == 0 && obj.DisplacementY == 0) { if (obj.IsStuck(room, 0, 0)) { if (obj.WallOnLeft && !obj.WallOnRight) obj.DisplacementX += STUCK_OBJ_DISPLACEMENT; else if (obj.WallOnRight && !obj.WallOnLeft) obj.DisplacementX -= STUCK_OBJ_DISPLACEMENT; } } //Even if a displacement value goes unchanged in the above test, it's still possible that the object //will (not) have a wall beside or ground beneath them after moving their full displacements. This last //test checks to see if this is the case, and changes the appropriate boolean flags accordingly. //If the object is touching a floor in its new position, the appropriate collision-causing function //is called. //If an object was airborne at the beginning of the frame and is still airborne, its y-velocity //is increased by the acceleration due to gravity. //If it's determined that the object is now in the air, it will become airborne. if (!obj.WallOnLeft) { if (obj.CheckWallLeft(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.CollideLeft(); } else { if (!obj.CheckWallLeft(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.WallOnLeft = false; } if (!obj.WallOnRight) { if (obj.CheckWallRight(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.CollideRight(); } else { if (!obj.CheckWallRight(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.WallOnRight = false; } if (!obj.IsOnGround) { if (obj.CheckGround(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.Land(); else if (obj.IsGravityAffected) obj.VelocityY = Math.Min(obj.VelocityY + GRAVITY * totalTime, MAX_FALLING_SPEED); } else { if (!obj.CheckGround(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.LeaveGround(); } if (!obj.CeilingAbove) { if (obj.CheckCeiling(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.HitCeiling(); } else { if (!obj.CheckCeiling(room, (int)obj.DisplacementX, (int)obj.DisplacementY)) obj.LeaveCeiling(); } if ((obj.riding != null) && (obj.riding == ridingAtStart)) { obj.DisplacementX += ridingAtStart.DisplacementX; obj.DisplacementY += ridingAtStart.DisplacementY; } }