XNA Development - A 2D Game Starter - part 4

The modified ship class will need to keep track of both it's position and it's velocity. The player input will cause the ships velocity to increase by small amounts. In this example, I set the maximum velocity of the ship at 5. This means that at full speed, the ship will move 5 pixels the X and/or Y direction each time the update method is called. I then arbitrarily picked the acceleration to be 0.125. This means it will take consecutive 40 calls to the update function to reach full speed.

Here is the Move() function from Ship.cs and it's helper function clamp. The move function adds to velocity based on what we pass in. The clamp function just makes sure the value stays between a specified high and low value. In this case maxVel is 5, is it keeps the velocity between -5 and 5.

public void Move(float x, float y)
{
     velocityX += x;
     velocityX = clamp(velocityX, -maxVel, maxVel);
     velocityY += y;
     velocityY = clamp(velocityY, -maxVel, maxVel);
}

private float clamp(float f, float low, float hi)
{
     float retVal = f;
     if (retVal >= hi)
          retVal = hi;
     if (retVal <= low)
          retVal = low;
     return retVal;
}

The Update function of the ship class call adds the velocity to the ships position. It then applied the 'drag' or friction if that is option turned on. The applyDrag function needs to check to see if the velocity is positive or negative, then move the velocity towards zero by a tiny fraction (maxVel / 50 or 0.1) If the velocity is close to zero (less than +/- 0.1), it just sets it to zero.

public void Update(GameTime gameTime)
{
     shipX += velocityX;
     if (drag)
          velocityX = applyDrag(velocityX);
     shipY += velocityY;
     if (drag)
          velocityY = applyDrag(velocityY);
     }

private float applyDrag(float f)
{
     float retVal = f;
     if (retVal > 0)
     {
          if (retVal > maxVel / 50f)
               retVal -= (maxVel / 50f);
          else
               retVal = 0;
     }
     else if (retVal < 0)
     {
          if (retVal < -maxVel / 50)
               retVal += (maxVel / 50f);
          else
               retVal = 0;
     }
     return retVal;
}

Then only other bit is the bounds checking. In Game1.cs, we call the ships Update() function, then it's CheckBounds() function. The CheckBounds() function checks to see if the ship has hit an edge of the rectangle we give it check. If it has hit, it then calls the HitWall() function. The HitWall() function then calls a different function based on the bounds behavior. In this example we define bounce, stop and wrap as things that can happen when hitting a ball. Bounce and stop are pretty simple; wrap simply moves the ship to the other side of the screen, wrapping it around like in Asteroids.

internal void CheckBounds(Rectangle bounds)
{
     if (shipX < bounds.X)
          HitWall(Wall.left, bounds);
     else if (shipX + shipTexture.Width > bounds.Width)
          HitWall(Wall.right, bounds);

     if (shipY < bounds.Y)
          HitWall(Wall.top, bounds);
     else if (shipY + shipTexture.Height > bounds.Height)
          HitWall(Wall.bottom, bounds);
}

private void HitWall(Wall wall, Rectangle bounds)
{
     switch (border)
     {
          case BorderBehavior.bounce:
               Bounce(wall, bounds);
               break;

          case BorderBehavior.stop:
               Stop(wall, bounds);
          break;

          case BorderBehavior.wrap:
               Wrap(wall, bounds);
               break;
     }
}

private void Wrap(Wall wall, Rectangle bounds)
{
     switch (wall)
     {
          case Wall.top:
               shipY = bounds.Height - shipTexture.Height;
               break;

          case Wall.bottom:
               shipY = bounds.Y;
               break;

          case Wall.left:
               shipX = bounds.Width - shipTexture.Width;
               break;

          case Wall.right:
               shipX = bounds.X;
               break;
     }
}

private void Stop(Wall wall, Rectangle bounds)
{
     switch (wall)
     {
          case Wall.top:
               shipY = bounds.Y;
               velocityY = 0;
               break;

          case Wall.bottom:
               shipY = bounds.Height - shipTexture.Height;
               velocityY = 0;
               break;

          case Wall.left:
               shipX = bounds.X;
               velocityX = 0;
               break;

          case Wall.right:
               shipX = bounds.Width - shipTexture.Width;
               velocityX = 0;
               break;
     }
}

private void Bounce(Wall wall, Rectangle bounds)
{
     switch (wall)
     {
          case Wall.top:
               shipY = bounds.Y;
               velocityY = -velocityY;
               break;

          case Wall.bottom:
               shipY = bounds.Height - shipTexture.Height;
               velocityY = -velocityY;
               break;

          case Wall.left:
               shipX = bounds.X;
               velocityX = -velocityX;
               break;

          case Wall.right:
               shipX = bounds.Width - shipTexture.Width;
               velocityX = -velocityX;
               break;
     }
}



<< Home >>