1 using System;
    2 using System.Collections.Generic;
    3 using Microsoft.Xna.Framework;
    4 using Microsoft.Xna.Framework.Graphics;
    5 using Microsoft.Xna.Framework.Input;
    6 
    7 namespace DreamLibrary
    8 {
    9     public class Player : Sprite
   10     {
   11         #region Player Variables
   12         protected Vector2 v2Dim;          // dimension for the single frame of sprite
   13         private Face playerFace;        // face for the player
   14         private Arm playerArm;          // arm object for player
   15         private int healthNodes;
   16         public State prevState;        // previous state of player
   17         private float speedModifier;
   18         private bool enemiesVis;
   19         private bool reachPeak = false;
   20         public bool hasLanded = false;      // determine if player has landed from a jump
   21         public bool isDying = false;        // true if player is in death animation
   22 
   23         double hurtTimer;
   24         public bool hurt;
   25         bool speedBoostAvailable;
   26         bool useSpeedBoost;
   27         #endregion
   28 
   29         #region Properties
   30         public float SpeedModifier
   31         {
   32             get { return speedModifier; }
   33             set { speedModifier = value; }
   34         }
   35 
   36         public bool SpeedBoostAvailable
   37         {
   38             get { return speedBoostAvailable; }
   39             set { speedBoostAvailable = value; }
   40         }
   41 
   42         public bool UseSpeedBoost
   43         {
   44             get { return useSpeedBoost; }
   45             set { useSpeedBoost = value; }
   46         }
   47 
   48         public int HealthNodes
   49         {
   50             get { return healthNodes; }
   51             set { healthNodes = value; }
   52         }
   53 
   54         public bool EnemiesVisible
   55         {
   56             get { return enemiesVis; }
   57         }
   58 
   59         /// <summary>
   60         /// Returns the arm object attached to the player.
   61         /// </summary>
   62         public Arm PlayerArm
   63         {
   64             get { return playerArm; }
   65         }
   66 
   67         public Face PlayerFace
   68         {
   69             get { return playerFace; }
   70         }
   71         #endregion
   72 
   73         #region Initialize
   74         public Player(Sprite sprite)
   75         {
   76             Type = sprite.Type;
   77             Position = sprite.Position;
   78             v2Dim = new Vector2(64, 64);
   79             Origin = new Vector2(32, 32);
   80             Name = sprite.Name;
   81             TextureAsset = sprite.TextureAsset;
   82             Rotation = sprite.Rotation;
   83             Scale = sprite.Scale;
   84             Attitude = 0;
   85             this.Texture = sprite.Texture;
   86             Velocity = Vector2.Zero;
   87             eDirection = Direction.Right;
   88             LayerDepth = sprite.LayerDepth;
   89             healthNodes = 4;
   90             Health = healthNodes * 2;
   91             playerFace = new Face(this);        // create attached face object
   92             playerArm = new Arm(this);          // create attached arm object
   93             SetAnimations();
   94             speedModifier = 1;
   95             Collidable = true;
   96         }
   97         #endregion
   98 
   99         #region Update
  100         public override void Update(GameTime gameTime, List<Sprite> sprites)
  101         {
  102             if (eHealth <= 0)
  103             {
  104                 if (VelocityY > 0)
  105                     VelocityY = 0;
  106                 Collidable = false;
  107                 playerFace.IsVisible = false;
  108                 playerArm.CurrentAnimation = "Invis";
  109                 isDying = true;
  110 
  111                 eState = State.Dead;
  112                 CurrentAnimation = "Dead";
  113                 if (!IsVisible || PositionY > 720)
  114                     IsAlive = false;
  115                 eForces.Add(new Force(12.0, 90));
  116                 Rotation = 0;
  117                 double teste = Math.Cos(gameTime.TotalGameTime.Milliseconds);
  118                 eForces.Add(new Force(teste * 100, 0));
  119             }
  120             else // If the player IS ALIVE
  121             {
  122                 isDying = false;
  123                 ApplyAnimations();
  124 
  125                 if (eState == State.Hurting)
  126                     hurtTimer = gameTime.TotalGameTime.TotalSeconds;
  127 
  128                 if (hurtTimer != 0 && gameTime.TotalGameTime.TotalSeconds - hurtTimer < 1)
  129                 {
  130                     hurt = true;
  131                     Invulnerable = true;
  132                 }
  133                 else
  134                 {
  135                     hurt = false;
  136                     Invulnerable = false;
  137                 }
  138 
  139                 // Rotate sprite with ground collision
  140                 if (eState == State.OnGround)
  141                 {
  142                     float distance = float.MaxValue;
  143                     for (int x = (int)(Position.X - Origin.X); x < (int)(Position.X + Width) && x < iHeightMap.Length; x++)
  144                         if (SpriteHelpers.GetDistance(Position, new Vector2(x, iHeightMap[x])) < distance)
  145                         {
  146                             Vector2 place = new Vector2(x, iHeightMap[x]);
  147                             distance = SpriteHelpers.GetDistance(Position, place);
  148                             Rotation = SpriteHelpers.SetRotation(Position, place);
  149                         }
  150                     if (eDirection == Direction.Left)
  151                         Rotation -= MathHelper.PiOver2;
  152                     else
  153                         Rotation -= MathHelper.PiOver2;
  154                 }
  155                 else
  156                     Rotation = 0;
  157 
  158                 // Clamp player X velocity
  159                 VelocityX = MathHelper.Clamp(VelocityX, -100f, 100f);
  160 
  161                 enemiesVis = false;
  162                 foreach (Sprite s in sprites)
  163                 {
  164                     if (s.Type == "Enemy")
  165                         if (s.IsVisible)
  166                         {
  167                             enemiesVis = true;
  168                             // If the player is in range to do damage
  169                             if (Math.Abs(ePosition.X - s.PositionX) < (s.Width + 48) && Math.Abs(ePosition.Y - s.PositionY) < (s.Height + 48))
  170                             {
  171                                 // If player is attacking
  172                                 if (playerArm.attacking)
  173                                 {
  174                                     // If the player's arm has collided with enemy
  175                                     if (playerArm.IntersectPixels(s))
  176                                     {
  177                                         if (!s.Invulnerable)
  178                                             // Cause the enemy damage
  179                                             s.Health--;
  180 
  181                                         s.eState = State.Hurting;
  182                                         if (eDirection == Direction.Left)
  183                                             s.AddForce(new Force(200.0, 170));
  184                                         else
  185                                             s.AddForce(new Force(200.0, 10));
  186                                         s.Invulnerable = true;
  187                                         break;
  188                                     }
  189                                 }
  190                             }
  191                         }
  192                 }
  193 
  194                 DebugString = eState.ToString();
  195 
  196                 playerFace.Update(this, gameTime);                    // update face animation
  197                 playerArm.UpdateArm(this, gameTime);        // update arm attack and animation
  198                 base.Update(gameTime, sprites);
  199             }
  200         }
  201 
  202         /// <summary>
  203         /// Calculates all of the player sprite animations.
  204         /// </summary>
  205         public void ApplyAnimations()
  206         {
  207             if (IsAlive)
  208             {
  209                 // If player is beginning or in a jump
  210                 if (eState == State.Jumping)
  211                 {
  212                     reachPeak = false;
  213                     // If the player is beginnign a jump
  214                     if (CurrentAnimation != "Jump")
  215                         CurrentAnimation = "Jump";
  216                     // Else, if player has reached the end of jump animation
  217                     else if (CurrentFrameAnimation.IsAtEnd)
  218                         eState = State.Falling;
  219                 }
  220                 // Else, if player is in falling or rising
  221                 else if (eState == State.Falling)
  222                 {
  223                     // If peak activation hasn't been triggered
  224                     if (!reachPeak)
  225                     {
  226                         // If player is reaching the peak of the jump
  227                         if (VelocityY > -160 && VelocityY < 0)
  228                         {
  229                             reachPeak = true// trigger peak activation
  230                             // Do peak animation
  231                             if (CurrentAnimation != "Peak")
  232                                 CurrentAnimation = "Peak";
  233                         }
  234                         // Else, if the player is rising or falling
  235                         else
  236                             if (CurrentAnimation != "Fall")
  237                                 CurrentAnimation = "Fall";
  238                     }
  239                     else  // Else, if peak has already been triggered
  240                     {
  241                         if (CurrentAnimation == "Peak")
  242                             if (CurrentFrameAnimation.PlayCount > 0)
  243                                 CurrentAnimation = "Fall"// Do fall animation
  244                     }
  245                 }
  246                 // Else, if player is on the ground
  247                 else if (eState == State.OnGround)
  248                 {
  249                     // If player was previously FALLING
  250                     if (prevState == State.Falling)
  251                         hasLanded = true;   // allow for landing sound
  252                     else
  253                         hasLanded = false;
  254 
  255                     reachPeak = false;
  256                     // If the player is NOT moving
  257                     if (Math.Abs(VelocityX) < 10)
  258                     {
  259                         // Do idle animation
  260                         if (CurrentAnimation != "Idle")
  261                             CurrentAnimation = "Idle";
  262                     }
  263                     // Else, if the player IS moving
  264                     else
  265                     {
  266                         // Do move animation
  267                         if (CurrentAnimation != "Move")
  268                             CurrentAnimation = "Move";
  269                     }
  270                 }
  271             }
  272             prevState = eState;
  273         }
  274         #endregion
  275 
  276         #region Methods
  277         /// <summary>
  278         /// Manually creates all of the animations from the sprite sheet.
  279         /// </summary>
  280         public void SetAnimations()
  281         {
  282             AddAnimation("Idle", 0, 0, (int)v2Dim.X, (int)v2Dim.Y, 4, 0.2f, "Idle");
  283             AddAnimation("Move", 0, (int)v2Dim.Y, (int)v2Dim.X, (int)v2Dim.Y, 12, 0.1f, "Move");
  284             AddAnimation("Jump", (int)v2Dim.X * 2, (int)v2Dim.Y * 2, (int)v2Dim.X, (int)v2Dim.Y, 3, 0.08f, "Fall");
  285             AddAnimation("Peak", (int)v2Dim.X * 5, (int)v2Dim.Y * 2, (int)v2Dim.X, (int)v2Dim.Y, 3, 0.15f, "Fall");
  286             AddAnimation("Fall", (int)v2Dim.X * 4, (int)v2Dim.Y * 2, (int)v2Dim.X, (int)v2Dim.Y, 1, 0.1f, "Fall");
  287             AddAnimation("Dead", 0, (int)v2Dim.Y * 4, (int)v2Dim.X, (int)v2Dim.Y, 1, 1.0f, "Dead");
  288 
  289             CurrentAnimation = "Idle";
  290             IsAnimating = true;
  291         }
  292         public override void OnFirstPass(List<Sprite> sprites)
  293         {
  294             sprites.Add(playerArm);
  295         }
  296         #endregion
  297 
  298         #region Draw
  299         /// <summary>
  300         /// Draws the sprite to the screen
  301         /// </summary>
  302         /// <param name="spriteBatch">SpriteBatch</param>
  303         public override void Draw(SpriteBatch spriteBatch)
  304         {
  305             base.Draw(spriteBatch);
  306 
  307             playerFace.Draw(spriteBatch);       // call face object's draw method
  308             //playerArm.Draw(spriteBatch);        // call arm object's draw method
  309         }
  310         #endregion
  311     }
  312 }