/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit // Allows user to exit the game by using Escape Button if (Keyboard.GetState().IsKeyDown(Keys.Escape)) { this.Exit(); } // TODO: Add your update logic here // Making "GOKU" character following the mouse state MouseState mouse = Mouse.GetState(); goku.Update(gameTime, mouse); // Update every objects in the game every milisecond foreach (Superman superfat in supermen) { superfat.Update(gameTime); } foreach (Weapon weapon in weapons) { weapon.Update(gameTime); } foreach (Explosion explosion in explosions) { explosion.Update(gameTime); } // Check and Update the collisions between enemies for (int i = 0; i < supermen.Count; i++) { for (int j = i + 1; j < supermen.Count; j++) { if (supermen[i].Alive && supermen[j].Alive) { EnemiesCollisionInfor collis = CollisionUtils.CheckCollision( gameTime.ElapsedGameTime.Milliseconds, GameVariables.SCREEN_WIDTH, GameVariables.SCREEN_WIDTH, supermen[i].sVelocity, supermen[i].sRectangle, supermen[j].sVelocity, supermen[j].sRectangle); if (collis != null) { if (collis.firstOutBounds) { supermen[i].Alive = false; } else { supermen[i].sVelocity = collis.getFirstVelocity; supermen[i].sRectangle = collis.getFirstRectangle; } if (collis.firstOutBounds) { supermen[j].Alive = false; } else { supermen[j].sVelocity = collis.getSecondVelocity; supermen[j].sRectangle = collis.getSecondRectangle; } } } } } // Check and Update what happen if the Goku's fire hits a superman foreach (Superman superfat in supermen) { foreach (Weapon weapon in weapons) { if (weapon.Type == WeaponType.GokuWeapon && weapon.Active && superfat.Alive && superfat.getRectangle.Intersects(weapon.wRectangle)) { weapon.Active = false; superfat.Alive = false; score += GameVariables.KILLED_SUPERMAN_AWARD; // Make a new Explosion when the superfat is not Alive Explosion newExplode = new Explosion(explosionSprite, superfat.currentLocation.X, superfat.currentLocation.Y); newExplode.Sound = explosion; // Add the Explosion to the Array List explosions.Add(newExplode); //play sound if (!Game1.IsLosing) { newExplode.Sound.Play(); } } } } // Check if Goku gets hit by touching the superman foreach (Superman superfat in supermen) { if (superfat.Alive && goku.getRectangle.Intersects(superfat.sRectangle)) { goku.health -= GameVariables.SUPERMAN_DAMAGES_HIMSELF; superfat.Alive = false; score += GameVariables.KILLED_SUPERMAN_AWARD; explosions.Add(new Explosion(explosionSprite, superfat.currentLocation.X, superfat.currentLocation.Y)); if (!Game1.IsLosing) { GokuGetHit.Play(); explosion.Play(); } } } // Check if Goku gets hit by touch the superman's fires foreach (Weapon weapon in weapons) { if (weapon.Type == WeaponType.SupermanWeapon && weapon.wRectangle.Intersects(goku.getRectangle)) { weapon.Active = false; goku.health -= GameVariables.SUPERMAN_SHOOTING_DAMAGES; if (!Game1.IsLosing) { GokuGetHit.Play(); } } } // Clean out the superman objects which has the Aclive status is false for (int i = supermen.Count - 1; i >= 0; i--) // remove from the back of the list { if (!supermen[i].Alive) { supermen.RemoveAt(i); } } while (supermen.Count < GameVariables.MAX_NUM_SUPERMEN) { SpawnSuperman(); } // Clean out the weapon objects which has the Aclive status is false for (int i = weapons.Count - 1; i >= 0; i--) // remove from the back of the list { if (!weapons[i].Active) { weapons.RemoveAt(i); } } // Clean out the explosion when it finishes for (int i = explosions.Count - 1; i >= 0; i--) // remove from the back of the list { if (explosions[i].Finish) { explosions.RemoveAt(i); } } // display current score and health healthString = GameVariables.HEALTH + goku.health; scoreString = GameVariables.SCORE + score; // Always check if we are losing or not IsLostAlready(); base.Update(gameTime); }
/// <summary> /// Check where and which direction should the enemies collide to /// </summary> /// <param name="timeStep"></param> /// <param name="screenWidth"></param> /// <param name="screenHeight"></param> /// <param name="firstObjectVelocity"></param> /// <param name="secondObjectVelocity"></param> /// <param name="firstObjectRectangle"></param> /// <param name="secondObjectRectangle"></param> /// <returns></returns> public static EnemiesCollisionInfor CheckCollisions(int timeStep, int screenWidth, int screenHeight, Vector2 firstObjectVelocity, Vector2 secondObjectVelocity, Rectangle firstObjectRectangle, Rectangle secondObjectRectangle) { Rectangle initialFirstObject; Rectangle initialSecondObject; Rectangle finalfirstObject; Rectangle finalSecondObject; Rectangle collisionRectangle; //checking if they are overlap bool detectedCollision = firstObjectRectangle.Intersects(secondObjectRectangle); if (detectedCollision) { // getting the same size of the rectangle finalfirstObject.Width = firstObjectRectangle.Width; finalfirstObject.Height = firstObjectRectangle.Height; finalSecondObject.Width = secondObjectRectangle.Width; finalSecondObject.Height = secondObjectRectangle.Height; // Getting the information right at the moment they overlap float firstXSpeed = (firstObjectVelocity.X * timeStep); float firstYSpeed = (firstObjectVelocity.Y * timeStep); initialFirstObject.X = (int)(firstObjectRectangle.X - firstXSpeed); initialFirstObject.Y = (int)(firstObjectRectangle.Y - firstYSpeed); initialFirstObject.Width = firstObjectRectangle.Width; initialFirstObject.Height = firstObjectRectangle.Height; float secondXSpeed = (secondObjectRectangle.X * timeStep); float secondYSpeed = (secondObjectRectangle.Y * timeStep); initialSecondObject.X = (int)(secondObjectRectangle.X - secondXSpeed); initialSecondObject.Y = (int)(secondObjectRectangle.Y - secondYSpeed); initialSecondObject.Width = secondObjectRectangle.Width; initialSecondObject.Height = secondObjectRectangle.Height; // Constantly, the time step is 60 frames per second, time will increament by the power of 2 int timeIncrement = timeStep / 2; int collisionDeltaT = timeStep; // rate of change of time int DeltaT = timeIncrement; // rate of change of time at a certain moment while (timeIncrement > 0) { // Move the objects firstXSpeed = firstObjectVelocity.X * DeltaT; firstYSpeed = firstObjectVelocity.Y * DeltaT; secondXSpeed = secondObjectVelocity.X * DeltaT; secondYSpeed = secondObjectVelocity.Y * DeltaT; // Updating current Location for the objects finalfirstObject.X = (int)(initialFirstObject.X + firstXSpeed); finalfirstObject.Y = (int)(initialFirstObject.Y + firstYSpeed); finalSecondObject.X = (int)(initialSecondObject.X + secondXSpeed); finalSecondObject.Y = (int)(initialSecondObject.Y + secondYSpeed); // decreasing the time increament timeIncrement /= 2; // check if they bound again or not detectedCollision = finalfirstObject.Intersects(finalSecondObject); if (detectedCollision) { // if the collision happens again collisionDeltaT = DeltaT; DeltaT -= timeIncrement; Rectangle.Intersect(ref finalfirstObject, ref finalSecondObject, out collisionRectangle); } else { DeltaT += timeIncrement; } } // Start the Collision int collisionStartTime = collisionDeltaT; firstXSpeed = firstObjectVelocity.X * collisionStartTime; firstYSpeed = firstObjectVelocity.Y * collisionStartTime; secondXSpeed = secondObjectVelocity.X * collisionStartTime; secondYSpeed = secondObjectVelocity.Y * collisionStartTime; finalfirstObject.X = (int)(initialFirstObject.X + firstXSpeed); finalfirstObject.Y = (int)(initialFirstObject.Y + firstYSpeed); finalSecondObject.X = (int)(initialSecondObject.X + secondXSpeed); finalSecondObject.Y = (int)(initialSecondObject.Y + secondYSpeed); // Check the side of the collision Rectangle collisionIntersection = Rectangle.Intersect(finalfirstObject, finalSecondObject); EnemiesCollisionSide possibleSide = checkCollisionSide(finalSecondObject, collisionIntersection, firstObjectVelocity, secondObjectVelocity); // Let the object move over the time Step int preCollisionTime = collisionStartTime - 1; int postCollisionTime = timeStep - preCollisionTime; EnemiesCollisionInfor enemiesBounce = getBounceObjects(firstObjectVelocity, initialFirstObject, secondObjectVelocity, initialSecondObject, preCollisionTime, postCollisionTime, possibleSide); enemiesBounce.firstOutBounds = IsOutOfBounds(firstObjectRectangle, screenWidth, screenHeight); enemiesBounce.SecondOutBounds = IsOutOfBounds(secondObjectRectangle, screenWidth, screenHeight); return(enemiesBounce); } else { // no collision happens -> no enemiesCollisionInfor return(null); } }
/// <summary> /// Returns the collision resolution info object associated with a detected collision or null if no collision /// is detected /// /// Ref: David M. Bourg, Physics for Game Developers, pages 207 and 209 /// </summary> /// <param name="timeStep">the time step, in milliseconds</param> /// <param name="windowWidth">the width of the game window</param> /// <param name="windowHeight">the height of the game window</param> /// <param name="firstVelocity">the velocity of the first object</param> /// <param name="firstDrawRectangle">the draw rectangle of the first object</param> /// <param name="secondVelocity">the velocity of the second object</param> /// <param name="secondDrawRectangle">the draw rectangle of the second object</param> /// <returns>the collision resolution info object for a detected collision or null if no collision is detected</returns> public static EnemiesCollisionInfor CheckCollision(int timeStep, int windowWidth, int windowHeight, Vector2 firstVelocity, Rectangle firstDrawRectangle, Vector2 secondVelocity, Rectangle secondDrawRectangle) { Rectangle initialFirstAabr; Rectangle initialSecondAabr; Rectangle currentFirstAabr; Rectangle currentSecondAabr; Rectangle collisionRectangle; // overlap test bool collisionDetected = firstDrawRectangle.Intersects(secondDrawRectangle); if (collisionDetected) { // initialize non-changing properties currentFirstAabr.Width = firstDrawRectangle.Width; currentFirstAabr.Height = firstDrawRectangle.Height; currentSecondAabr.Width = secondDrawRectangle.Width; currentSecondAabr.Height = secondDrawRectangle.Height; // back up both objects to their locations before the time step float firstDx = (firstVelocity.X * timeStep); float firstDy = (firstVelocity.Y * timeStep); initialFirstAabr.X = (int)(firstDrawRectangle.X - firstDx); initialFirstAabr.Y = (int)(firstDrawRectangle.Y - firstDy); initialFirstAabr.Width = firstDrawRectangle.Width; initialFirstAabr.Height = firstDrawRectangle.Height; float secondDx = (secondVelocity.X * timeStep); float secondDy = (secondVelocity.Y * timeStep); initialSecondAabr.X = (int)(secondDrawRectangle.X - secondDx); initialSecondAabr.Y = (int)(secondDrawRectangle.Y - secondDy); initialSecondAabr.Width = secondDrawRectangle.Width; initialSecondAabr.Height = secondDrawRectangle.Height; // at fixed time step of 60 fps, time increment can only be 8, 4, 2, or 1 int timeIncrement = timeStep / 2; int collisionDt = timeStep; // we know we have a collision or we wouldn't be here int dt = timeIncrement; while (timeIncrement > 0) { // move both objects forward by dt from their initial positions firstDx = firstVelocity.X * dt; firstDy = firstVelocity.Y * dt; secondDx = secondVelocity.X * dt; secondDy = secondVelocity.Y * dt; // update axis-aligned bounding rectangles currentFirstAabr.X = (int)(initialFirstAabr.X + firstDx); currentFirstAabr.Y = (int)(initialFirstAabr.Y + firstDy); currentSecondAabr.X = (int)(initialSecondAabr.X + secondDx); currentSecondAabr.Y = (int)(initialSecondAabr.Y + secondDy); // cut time increment in half as we search for the time of collision timeIncrement /= 2; collisionDetected = currentFirstAabr.Intersects(currentSecondAabr); if (collisionDetected) { // collision detected, so save collision dt and reduce dt to make it earlier collisionDt = dt; dt -= timeIncrement; // save the collision rectangle in case we don't find any other collisions Rectangle.Intersect(ref currentFirstAabr, ref currentSecondAabr, out collisionRectangle); } else { // no collision detected, so increase dt to make it later dt += timeIncrement; } } // get rectangle locations at start of collision int collisionStartTime = collisionDt; firstDx = firstVelocity.X * collisionStartTime; firstDy = firstVelocity.Y * collisionStartTime; secondDx = secondVelocity.X * collisionStartTime; secondDy = secondVelocity.Y * collisionStartTime; currentFirstAabr.X = (int)(initialFirstAabr.X + firstDx); currentFirstAabr.Y = (int)(initialFirstAabr.Y + firstDy); currentSecondAabr.X = (int)(initialSecondAabr.X + secondDx); currentSecondAabr.Y = (int)(initialSecondAabr.Y + secondDy); // use square collision normals Rectangle intersection = Rectangle.Intersect(currentFirstAabr, currentSecondAabr); EnemiesCollisionSide collisionSide = GetCollisionSide(currentSecondAabr, intersection, firstVelocity, secondVelocity); // move objects through complete time step int preCollisionDuration = collisionStartTime - 1; int postCollisionDuration = timeStep - collisionStartTime + 1; EnemiesCollisionInfor colInfor = BounceObjects(firstVelocity, initialFirstAabr, secondVelocity, initialSecondAabr, preCollisionDuration, postCollisionDuration, collisionSide); // check out of bounds and return colInfor.firstOutBounds = OutOfBounds(firstDrawRectangle, windowWidth, windowHeight); colInfor.SecondOutBounds = OutOfBounds(secondDrawRectangle, windowWidth, windowHeight); return(colInfor); } else { // no collision return(null); } }