четверг, 15 марта 2012 г.

How To Make A Game

In this blog I will talk about how to create a computer game step by step using the Microsoft XNA. I start my story from the simple to the complex. And at the end of the story we will create a full 3D game.






As a result, we get this game:



 So let's get started and good luck to everyone who wants to learn how to create games with their own hands.

Menu Creation

Our future game would consist of three main modules. This menu, a physical module and render. First, we look at how to create a menu for our, as well as for any other game. To run the menu, we need to create the following classes:

AnimeFont.cs;
BackGround.cs;
Button.cs;
Cursor.cs;
Delegates.cs;
MainMenu.cs;

From the title it should be clear that each class will do.

namespace _MENU_
{
  class AnimeFont : DrawableGameComponent
  {
    SpriteBatch spriteBatch;
    private Texture2D Texture1;
    int PositionX1;
    int PositionY1;
    Rectangle Rectangle1;
    private Texture2D Texture2;
    int PositionX2;
    int PositionY2;
    Rectangle Rectangle2;
    private Texture2D Texture3;
    int PositionX3;
    int PositionY3;
    Rectangle Rectangle3;
    private Texture2D Texture4;
    int PositionX4;
    int PositionY4;
    Rectangle Rectangle4;
    private Texture2D gameName;
    public AnimeFont(Game game) : base(game)
    {
      spriteBatch = new SpriteBatch(Game.GraphicsDevice);
      Texture1 = Game.Content.Load<Texture2D>(@"Menu/RB1");
      PositionX1 = game.GraphicsDevice.Viewport.Width - Texture1.Width;
      PositionY1 = game.GraphicsDevice.Viewport.Height - Texture1.Height / 2;
      Texture2 = Game.Content.Load<Texture2D>(@"Menu/RB2");
      PositionX2 = -game.GraphicsDevice.Viewport.Width / 2;
      PositionY2 = game.GraphicsDevice.Viewport.Height - Texture2.Height * 2;
      Texture3 = Game.Content.Load<Texture2D>(@"Menu/RB3");
      PositionX3 = game.GraphicsDevice.Viewport.Width - Texture3.Width / 2;
      PositionY3 = 100;
      Texture4 = Game.Content.Load<Texture2D>(@"Menu/RB4");
      PositionX4 = 50;
      PositionY4 = -Game.GraphicsDevice.Viewport.Height;
      gameName = Game.Content.Load<Texture2D>(@"Menu/GameName");
    }
    public override void Initialize()
    {
      base.Initialize();
    }
    public override void Update(GameTime gameTime)
    {
      PositionY1--;
      Rectangle1 = new Rectangle(PositionX1, PositionY1, Texture1.Width, Texture1.Height);
      if (PositionY1 < -800)
      {
        PositionY1 = Game.GraphicsDevice.Viewport.Height - Texture1.Height / 6;
      }
      PositionX2++;
      Rectangle2 = new Rectangle(PositionX2, PositionY2, Texture2.Width, Texture2.Height);
      if (PositionX2 > Game.GraphicsDevice.Viewport.Width)
      {
        PositionX2 = -Game.GraphicsDevice.Viewport.Width / 2;
      }
      PositionX3--;
      Rectangle3 = new Rectangle(PositionX3, PositionY3, Texture3.Width, Texture3.Height);
      if (PositionX3 < -Game.GraphicsDevice.Viewport.Width / 2)
      {
        PositionX3 = Game.GraphicsDevice.Viewport.Width;
      }
      PositionY4++;
      Rectangle4 = new Rectangle(PositionX4, PositionY4, Texture4.Width, Texture4.Height);
      if (PositionY4 > Game.GraphicsDevice.Viewport.Height)
      {
        PositionY4 = -Game.GraphicsDevice.Viewport.Height;
      }
      base.Update(gameTime);
    }
    public override void Draw(GameTime gameTime)
    {
      spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
      spriteBatch.Draw(Texture1, Rectangle1, new Color(255, 255, 255, 70));
      spriteBatch.Draw(Texture2, Rectangle2, new Color(255, 255, 255, 70));
      spriteBatch.Draw(Texture3, Rectangle3, new Color(255, 255, 255, 255));
      spriteBatch.Draw(Texture4, Rectangle4, new Color(255, 255, 255, 100));
      spriteBatch.Draw(gameName, new Rectangle(60, 70, gameName.Width / 2, gameName.Height / 2), new Color(255, 255, 255, 255));
      spriteBatch.End();
      base.Draw(gameTime);
    }
  }
}

namespace _MENU_
{
  public class BackGround : Microsoft.Xna.Framework.DrawableGameComponent
  {
    private SpriteBatch spriteBatch;
    private VideoPlayer videoPlayer;
    private Texture2D BackGroundTexture = null;
    private Video BackGroundVideo = null;
    private Rectangle BackGroundRectangle;
    private string BackGroundFilePath;
    public BackGround(Game game, Rectangle BackGroundRectangle, string BackGroundFilePath) : base(game)
    {
      this.BackGroundRectangle = BackGroundRectangle;
      this.BackGroundFilePath = BackGroundFilePath;
    }
    public override void Initialize()
    {
      spriteBatch = new SpriteBatch(Game.GraphicsDevice);
      try
      {
        BackGroundTexture = Game.Content.Load<Texture2D>(BackGroundFilePath);
      }
      catch
      {
        BackGroundVideo = Game.Content.Load<Video>(BackGroundFilePath);
        videoPlayer = new VideoPlayer();
        videoPlayer.IsLooped = true;
        videoPlayer.Play(BackGroundVideo);
      }
      base.Initialize();
    }
   
    public override void Draw(GameTime gameTime)
    {
      spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
      if (BackGroundTexture != null)
      {
        spriteBatch.Draw(BackGroundTexture, BackGroundRectangle, Color.White);
      }
      if (BackGroundVideo != null)
      {
        spriteBatch.Draw(videoPlayer.GetTexture(), BackGroundRectangle, Color.White);
      }
      spriteBatch.End();
      base.Draw(gameTime);
    }
  }
}

namespace _MENU_
{
  public class MenuButton : Microsoft.Xna.Framework.DrawableGameComponent
  {
    private SpriteBatch spriteBatch;
    private SpriteFont spriteFont;
   
    private Texture2D ButtonTexture;
    private Rectangle ButtonRectangle;
    private Color ButtonColor = Color.White;
    private string TexturePath;
    private string SpriteFontPath = string.Empty;
    private string Name = string.Empty;
    public event OnMenuButtonClick OnButtonClick;
    public MenuButton(Game game, Rectangle ButtonRectangle, string TexturePath)
      : base(game)
    {     
      this.ButtonRectangle = ButtonRectangle;
      this.TexturePath = TexturePath;
    }
    public MenuButton(Game game, Rectangle ButtonRectangle, string TexturePath, string SpriteFontPath, string Name)
      : base(game)
    {
      this.ButtonRectangle = ButtonRectangle;
      this.TexturePath = TexturePath;
      this.SpriteFontPath = SpriteFontPath;
      this.Name = Name;
    }
    protected override void LoadContent()
    {
      spriteBatch = new SpriteBatch(GraphicsDevice);
      ButtonTexture = Game.Content.Load<Texture2D>(TexturePath);
      if (SpriteFontPath != string.Empty)
      {
        spriteFont = Game.Content.Load<SpriteFont>(SpriteFontPath);
      }
      base.LoadContent();
    }
    public override void Update(GameTime gameTime)
    {
      Rectangle MouseRectangle = new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 1, 1);
      if (MouseRectangle.Intersects(ButtonRectangle))
      {
        ButtonColor = Color.White;
        if (Mouse.GetState().LeftButton == ButtonState.Pressed)
        {
          OnButtonClick();
        }
      }
      else
      {
        ButtonColor = Color.Gray;
      }
      base.Update(gameTime);
    }
    public override void Draw(GameTime gameTime)
    {
      spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
      spriteBatch.Draw(ButtonTexture, ButtonRectangle, ButtonColor);
      if (Name != string.Empty)
      {
        spriteBatch.DrawString(spriteFont, Name, new Vector2(ButtonRectangle.X, ButtonRectangle.Y + 8), Color.AliceBlue);
      }
      spriteBatch.End();
      base.Draw(gameTime);
    }
  }
}


namespace _MENU_
{
  public class Cursor : Microsoft.Xna.Framework.DrawableGameComponent
  {
    SpriteBatch spriteBatch;
    private Texture2D CursorTexture;
    private Rectangle CursorRectangle;
    private string CursorFilePath;
    public Cursor(Game game, Rectangle CursorRectangle, string CursorFilePath) : base(game)
    {
      this.CursorRectangle = CursorRectangle;
      this.CursorFilePath = CursorFilePath;
    }
    public override void Initialize()
    {
      spriteBatch = new SpriteBatch(Game.GraphicsDevice);
      CursorTexture = Game.Content.Load<Texture2D>(CursorFilePath);
      base.Initialize();
    }
    public override void Update(GameTime gameTime)
    {
      CursorRectangle = new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 50, 50);
      base.Update(gameTime);
    }
    public override void Draw(GameTime gameTime)
    {
      spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
      spriteBatch.Draw(CursorTexture, CursorRectangle, Color.White);     
      spriteBatch.End();
      base.Draw(gameTime);
    }
  }
}


namespace _MENU_
{
  public delegate void OnMenuButtonClick();
  public delegate void SwitchMainMenuToNewGame();
  public delegate void SwitchMainMenuToOptionsMenu();
  public delegate void SwitchMainMenuToTitleMenu();
  public delegate void SwitchTitleMenuToMainMenu();
  public delegate void SwitchMainMenuToExit();
}
namespace _MENU_
{
  public class MainMenu
  {
    public event SwitchMainMenuToNewGame SwitchMainMenuToGame;
    public event SwitchMainMenuToTitleMenu SwitchMainMenuToTitleMenu;
    public event SwitchMainMenuToExit SwitchMainMenuToExit;
    BackGround FirstBackGround;
    AnimeFont AFont;
    MenuButton StartNewGameButton;
    MenuButton OptionsGameButton;
    MenuButton TitleButton;
    MenuButton ExitGameButton;
    public MainMenu(Game game)
    {
      FirstBackGround = new BackGround(game, new Rectangle(0, 0, game.GraphicsDevice.Viewport.Width, game.GraphicsDevice.Viewport.Height), @"Menu/menu");
      game.Components.Add(FirstBackGround);
      AFont = new AnimeFont(game);
      game.Components.Add(AFont);
      StartNewGameButton = new MenuButton(game, new Rectangle(80, 150, 200, 40), @"Menu/Button3", @"Menu/DefaultFont", "       START");
      StartNewGameButton.OnButtonClick += new OnMenuButtonClick(StartNewGameButton_OnButtonClick);
      game.Components.Add(StartNewGameButton);
      OptionsGameButton = new MenuButton(game, new Rectangle(80, 200, 200, 40), @"Menu/Button3", @"Menu/DefaultFont", "      OPTIONS");
      OptionsGameButton.OnButtonClick += new OnMenuButtonClick(OptionsGameButton_OnButtonClick);
      game.Components.Add(OptionsGameButton);
      TitleButton = new MenuButton(game, new Rectangle(80, 250, 200, 40), @"Menu/Button3", @"Menu/DefaultFont", "       TITLE");
      TitleButton.OnButtonClick += new OnMenuButtonClick(TitleButton_OnButtonClick);
      game.Components.Add(TitleButton);
      ExitGameButton = new MenuButton(game, new Rectangle(80, 300, 200, 40), @"Menu/Button3", @"Menu/DefaultFont", "        EXIT");
      ExitGameButton.OnButtonClick += new OnMenuButtonClick(ExitButton_OnButtonClick);
      game.Components.Add(ExitGameButton);
      game.Components.Add(new Cursor(game, new Rectangle(),@"Menu/cursor"));
    }
    void TitleButton_OnButtonClick()
    {
      SwitchMainMenuToTitleMenu();
    }
    void OptionsGameButton_OnButtonClick()
    {
    }
    void StartNewGameButton_OnButtonClick()
    {
      SwitchMainMenuToGame();
    }
    void ExitButton_OnButtonClick()
    {
      SwitchMainMenuToExit();
    }

  }
}

The result of these classes you can see in the pictures above. Using delegates used in menu, we can switch between various modes of our future game engine. Need to immediately say that this game is based on the physical engine PhysX, and actually to the NET version of these libraries:

PhysXLoader.dll
NxCooking.dll
NxCharacter.dll

These libraries are available online for download.

This class fully configures the physics of the game, and synchronizes with the game render.
namespace _GAME_
{
  public delegate void ContactCallback(Actor a, Actor b, ContactPairFlag events);
  public class PhysX
  {
    private Model _box;
    private Model _sphere;
    public Core _core;
    public static Scene _scene;
    public static Actor Bitok;
    public static Actor ball1, ball2, ball3, ball4,
                        ball5, ball6, ball7, ball8,
                        ball9, ball10, ball11, ball12,
                        ball13, ball14, ball15, ball16;
    public static Actor Border1, Border2, Border3, Border4, Border5, Border6;  
    public PhysX(Game game)
    {
      _core = new Core();
      _core.SetParameter(PhysicsParameter.VisualizationScale, 2.0f);
      _core.SetParameter(PhysicsParameter.VisualizationScale, 1.0f);
      _core.SetParameter(PhysicsParameter.VisualizeCollisionShapes, true);
      _core.SetParameter(PhysicsParameter.VisualizeClothMesh, true);
      _core.SetParameter(PhysicsParameter.VisualizeJointLocalAxes, true);
      _core.SetParameter(PhysicsParameter.VisualizeJointLimits, true);
      _core.SetParameter(PhysicsParameter.VisualizeFluidPosition, true);
      _core.SetParameter(PhysicsParameter.VisualizeFluidEmitters, false); // Slows down rendering a bit to much
      _core.SetParameter(PhysicsParameter.VisualizeForceFields, true);
      _core.SetParameter(PhysicsParameter.VisualizeSoftBodyMesh, true);
      _core.SetParameter(PhysicsParameter.DefaultSleepLinearVelocitySquared, 2.0f * 2.0f);
      _core.SetParameter(PhysicsParameter.DefaultSleepAngularVelocitySquared, 2.0f * 2.0f);
      _core.SetParameter(PhysicsParameter.SkinWidth, 0.01f);
      _core.SetParameter(PhysicsParameter.VisualizeActorAxes, true);
      SceneDescription sceneDesc = new SceneDescription();
      sceneDesc.SimulationType = SimulationType.Software;
      sceneDesc.Gravity = new Vector3(0.0f, -50f, 0.0f);
      _scene = _core.CreateScene(sceneDesc);
      // Create the default material
      Material defaultMaterial = _scene.Materials[0];
      defaultMaterial.Restitution = 0.5f;
      defaultMaterial.StaticFriction = 0.1f;
      defaultMaterial.DynamicFriction = 0.1f;
    }
   
    public void Dispose()
    {
      _core.Dispose();
      _scene.Dispose();
    }
    public void LoadPhysX(ContentManager Content)
    {
      _box = Content.Load<Model>(@"PhysicsMeshes/cube");
      _sphere = Content.Load<Model>(@"PhysicsMeshes/sphere");
      SetupPhysicsScene();
    }
    void SetupPhysicsScene()
    {
      // --- Borders ---
      Border1 = CreateBox(new Vector3(0, -15, 44), new Vector3(20.5f, 10, 2), 0);
      Border1.Name = "b";
      Border2 = CreateBox(new Vector3(0, -15, -44), new Vector3(20.5f, 10, 2), 0);
      Border2.Name = "b";
      Border3 = CreateBox(new Vector3(24, -15, 20.75f), new Vector3(2, 10, 19.75f), 0);
      Border3.Name = "b";
      Border4 = CreateBox(new Vector3(24, -15, -20.75f), new Vector3(2, 10, 19.75f), 0);
      Border4.Name = "b";
      Border5 = CreateBox(new Vector3(-24, -15, 20.75f), new Vector3(2, 10, 19.75f), 0);
      Border5.Name = "b";
      Border6 = CreateBox(new Vector3(-24, -15, -20.75f), new Vector3(2, 10, 19.75f), 0);
      Border6.Name = "b";
      // --- Planes ---
      Actor Box = CreateBox(new Vector3(0, -18, 0), new Vector3(22, 10.35f, 42), 0);
      Box = CreateBox(new Vector3(0, -50, 0), new Vector3(2500, 10f, 2500), 0);
      // --- zaplatki ---
      Box = CreateBox(new Vector3(25, -15, 45), new Vector3(6, 10f, 2), 0);
      Box.GlobalOrientation = Matrix.Transform(Box.GlobalOrientation, Quaternion.CreateFromRotationMatrix(Matrix.CreateRotationY(MathHelper.PiOver4)));
      Box = CreateBox(new Vector3(-25, -15, 45), new Vector3(2, 10f, 6), 0);
      Box.GlobalOrientation = Matrix.Transform(Box.GlobalOrientation, Quaternion.CreateFromRotationMatrix(Matrix.CreateRotationY(MathHelper.PiOver4)));
      Box = CreateBox(new Vector3(25, -15, -45), new Vector3(2, 10f, 6), 0);
      Box.GlobalOrientation = Matrix.Transform(Box.GlobalOrientation, Quaternion.CreateFromRotationMatrix(Matrix.CreateRotationY(MathHelper.PiOver4)));
      Box = CreateBox(new Vector3(-25, -15, -45), new Vector3(6, 10f, 2), 0);
      Box.GlobalOrientation = Matrix.Transform(Box.GlobalOrientation, Quaternion.CreateFromRotationMatrix(Matrix.CreateRotationY(MathHelper.PiOver4)));
      Box = CreateBox(new Vector3(27, -15, 0), new Vector3(2, 10f, 10), 0);
      Box = CreateBox(new Vector3(-27, -15, 0), new Vector3(2, 10f, 10), 0);
      // --- Balls ---
      float AngDump = 100f;
      float Mass = 300f;
      Bitok = CreateSphere(new Vector3(0, 2.6f, 20), 1, 1);
      Bitok.AngularDamping = AngDump;
      Bitok.Mass = Mass;
      Bitok.Name = "Bitok";
      Bitok.Sleep();
      ball1 = CreateSphere(new Vector3(-2, 2.6f, -20), 1, 1);
      ball1.AngularDamping = AngDump;
      ball1.Mass = Mass;
      ball1.Name = "ball1";
      ball1.Sleep();
      ball2 = CreateSphere(new Vector3(0, 2.6f, -20), 1, 1);
      ball2.AngularDamping = AngDump;
      ball2.Mass = Mass;
      ball2.Name = "ball2";
      ball2.Sleep();
      ball3 = CreateSphere(new Vector3(2, 2.6f, -20), 1, 1);
      ball3.AngularDamping = AngDump;
      ball3.Mass = Mass;
      ball3.Name = "ball3";
      ball3.Sleep();
      ball4 = CreateSphere(new Vector3(-3, 2.6f, -21.8f), 1, 1);
      ball4.AngularDamping = AngDump;
      ball4.Mass = Mass;
      ball4.Name = "ball4";
      ball4.Sleep();
      ball5 = CreateSphere(new Vector3(-1, 2.6f, -21.8f), 1, 1);
      ball5.AngularDamping = AngDump;
      ball5.Mass = Mass;
      ball5.Name = "ball5";
      ball5.Sleep();
      ball6 = CreateSphere(new Vector3(1, 2.6f, -21.8f), 1, 1);
      ball6.AngularDamping = AngDump;
      ball6.Mass = Mass;
      ball6.Name = "ball6";
      ball6.Sleep();
      ball7 = CreateSphere(new Vector3(3, 2.6f, -21.8f), 1, 1);
      ball7.AngularDamping = AngDump;
      ball7.Mass = Mass;
      ball7.Name = "ball7";
      ball7.Sleep();
      ball8 = CreateSphere(new Vector3(-4, 2.6f, -23.6f), 1, 1);
      ball8.AngularDamping = AngDump;
      ball8.Mass = Mass;
      ball8.Name = "ball8";
      ball8.Sleep();
      ball9 = CreateSphere(new Vector3(-2, 2.6f, -23.6f), 1, 1);
      ball9.AngularDamping = AngDump;
      ball9.Mass = Mass;
      ball9.Name = "ball9";
      ball9.Sleep();
      ball10 = CreateSphere(new Vector3(0, 2.6f, -23.6f), 1, 1);
      ball10.AngularDamping = AngDump;
      ball10.Mass = Mass;
      ball10.Name = "ball10";
      ball10.Sleep();
      ball11 = CreateSphere(new Vector3(2, 2.6f, -23.6f), 1, 1);
      ball11.AngularDamping = AngDump;
      ball11.Mass = Mass;
      ball11.Name = "ball11";
      ball11.Sleep();
      ball12 = CreateSphere(new Vector3(4, 2.6f, -23.6f), 1, 1);
      ball12.AngularDamping = AngDump;
      ball12.Mass = Mass;
      ball12.Name = "ball12";
      ball12.Sleep();
      ball13 = CreateSphere(new Vector3(-1, 2.6f, -18.2f), 1, 1);
      ball13.AngularDamping = AngDump;
      ball13.Mass = Mass;
      ball13.Name = "ball13";
      ball13.Sleep();
      ball14 = CreateSphere(new Vector3(1, 2.6f, -18.2f), 1, 1);
      ball14.AngularDamping = AngDump;
      ball14.Mass = Mass;
      ball14.Name = "ball14";
      ball14.Sleep();
      ball15 = CreateSphere(new Vector3(0, 2.6f, -16.4f), 1, 1);
      ball15.AngularDamping = AngDump;
      ball15.Mass = Mass;
      ball15.Name = "ball15";
      ball15.Sleep();

      _scene.UserContactReport = new ContactReport();
      _scene.SetActorGroupPairFlags(0, 0, ContactPairFlag.OnTouch);
    }
    public void UpdatePhysX(GameTime gameTime)
    {
      _scene.Simulate((float)gameTime.ElapsedGameTime.TotalMilliseconds / 300f);     
      _scene.FetchResults(SimulationStatus.RigidBodyFinished, true);
    }
    public void DrawPhysX()
    {
      foreach (Actor actor in _scene.Actors)
      {
        Vector3 actualColor = new Vector3(1, 1, 1);
        foreach (Shape shape in actor.Shapes)
        {
          switch (shape.Type)
          {
            case ShapeType.Box:
              DrawPhysicsBox((BoxShape)shape, actualColor);
              break;
            case ShapeType.Sphere:
              if (actor.IsSleeping)
              {
                DrawPhysicsSphere((SphereShape)shape, /*new Vector3(0, 0, 1)*/actualColor, true);
              }
              else
              {
                DrawPhysicsSphere((SphereShape)shape, actualColor, false);
              }
                break;
          }
        }
      }
    }
    Actor CreateKinematicBox(Vector3 pos, Vector3 boxDim, string name, float mass)
    {
      BodyDescription bodyDescription = new BodyDescription(mass);
      bodyDescription.BodyFlags = BodyFlag.Kinematic;
      ActorDescription actorDesc = new ActorDescription();
      actorDesc.GlobalPose = Matrix.CreateTranslation(pos);
      actorDesc.BodyDescription = bodyDescription;
      actorDesc.Name = name;
      actorDesc.Shapes.Add(new BoxShapeDescription(boxDim));
      return _scene.CreateActor(actorDesc);
    }
    Actor CreateBox(Vector3 pos, Vector3 boxDim, float density)
    {
      ActorDescription actorDesc = new ActorDescription();
      BodyDescription bodyDesc = new BodyDescription();
      BoxShapeDescription boxShapeDesc = new BoxShapeDescription();
      boxShapeDesc.Dimensions = new Vector3(boxDim.X, boxDim.Y, boxDim.Z);
      boxShapeDesc.LocalPose = Matrix.CreateTranslation(0, boxDim.Y, 0);
      actorDesc.Shapes.Add(boxShapeDesc);
      actorDesc.GlobalPose = Matrix.CreateTranslation(pos);
      if (density > 0)
      {
        actorDesc.BodyDescription = bodyDesc;
        actorDesc.Density = density;
      }
      //if (!actorDesc.IsValid())
      //  throw new InvalidDataException();
      return _scene.CreateActor(actorDesc);
    }
    void DrawPhysicsBox(BoxShape shape, Vector3 color)
    {
      {
        Matrix[] transforms = new Matrix[_box.Bones.Count];
        _box.CopyAbsoluteBoneTransformsTo(transforms);
        foreach (ModelMesh mesh in _box.Meshes)
        {
          foreach (BasicEffect effect in mesh.Effects)
          {
            effect.DiffuseColor = color;
            effect.EnableDefaultLighting();
            effect.World = Matrix.CreateScale(shape.Dimensions.X, shape.Dimensions.Y, shape.Dimensions.Z) * transforms[mesh.ParentBone.Index] * shape.GlobalPose;
            effect.View = Camera.ViewMatrix;
            effect.Projection = Camera.ProjectionMatrix;
          }
          mesh.Draw();
        }
      }
    }
    Actor CreateSphere(Vector3 pos, float radius, float density)
    {
      // Add a single-shape actor to the scene
      ActorDescription actorDesc = new ActorDescription();
      BodyDescription bodyDesc = new BodyDescription();
      // The actor has one shape, a sphere
      SphereShapeDescription sphereDesc = new SphereShapeDescription(radius);
      sphereDesc.LocalPose = Matrix.CreateTranslation(new Vector3(0, radius, 0));
      actorDesc.Shapes.Add(sphereDesc);
      if (density > 0)
      {
        actorDesc.BodyDescription = bodyDesc;
        actorDesc.Density = density;
      }
      actorDesc.GlobalPose = Matrix.CreateTranslation(pos);
      Actor pActor = _scene.CreateActor(actorDesc);
      return pActor;
    }
    void DrawPhysicsSphere(SphereShape sphereShape, Vector3 color, bool IsSleeping)
    {
      Matrix[] transforms = new Matrix[_sphere.Bones.Count];
      _sphere.CopyAbsoluteBoneTransformsTo(transforms);
      foreach (ModelMesh mesh in _sphere.Meshes)
      {
        foreach (BasicEffect effect in mesh.Effects)
        {
          effect.World = Matrix.CreateScale(sphereShape.Radius, sphereShape.Radius, sphereShape.Radius) * transforms[mesh.ParentBone.Index] * sphereShape.GlobalPose;
          effect.View = Camera.ViewMatrix;
          effect.Projection = Camera.ProjectionMatrix;
          effect.DiffuseColor = Color.White.ToVector3();
          //effect.DiffuseColor = color;
          effect.EnableDefaultLighting();
        }
        mesh.Draw();
      }
    }
  }
 
  public class ContactReport : UserContactReport
  {
    private List<ContactReportPair> _contactPairs;
    public struct ContactReportPair
    {
      public Actor A, B;
      public ContactCallback Callback;
      public ContactReportPair(Actor a, Actor b, ContactCallback callback)
      {
        A = a;
        B = b;
        Callback = callback;
      }
    }
    public ContactReport()
    {
      _contactPairs = new List<ContactReportPair>();
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball14, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball15, PhysX.Border1, new ContactCallback(CapsuleAndGroundPlaneContact)));

      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball14, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball15, PhysX.Border2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball14, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball15, PhysX.Border3, new ContactCallback(CapsuleAndGroundPlaneContact)));

      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball14, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball15, PhysX.Border4, new ContactCallback(CapsuleAndGroundPlaneContact)));

      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball14, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball15, PhysX.Border5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball14, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball15, PhysX.Border6, new ContactCallback(CapsuleAndGroundPlaneContact)));

      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball1, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball7, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.Bitok, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball2, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball7, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball1, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball3, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball7, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball2, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball4, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball7, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball3, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball5, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball7, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball4, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball6, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball7, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball5, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball7, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball6, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball8, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball7, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.ball9, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball8, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.ball10, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball9, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.ball11, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball10, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.ball12, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball11, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.ball13, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball12, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.ball14, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball13, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
      _contactPairs.Add(new ContactReportPair(PhysX.ball14, PhysX.ball15, new ContactCallback(CapsuleAndGroundPlaneContact)));
    }
    public override void OnContactNotify(ContactPair contactInformation, ContactPairFlag events)
    {
      foreach (ContactReportPair pair in _contactPairs)
      {
        if ((pair.A == contactInformation.ActorA || pair.A == contactInformation.ActorB) && (pair.B == contactInformation.ActorA || pair.B == contactInformation.ActorB))
        {
          pair.Callback(contactInformation.ActorA, contactInformation.ActorB, events);
        }
      }
    }
    private void CapsuleAndGroundPlaneContact(Actor a, Actor b, ContactPairFlag events)
    {     
      if (b.Name == "b")
      {
        float Volume = (a.LinearVelocity.X + a.LinearVelocity.Z) / 2;
        Sound.PlayBoard(Volume);
      }
      else
      {
        float Volume = (a.LinearVelocity.X + a.LinearVelocity.Z) / 2;
        Sound.PlayBall1(Volume);
      }
    }
  }
}

As you can see, in this class also manages audio that sounds when the balls is collide in this game.

namespace _GAME_
{
  public class Sound
  {
    static SoundEffect soundEffectPopadanie;
    static SoundEffect soundEffectBitokLost;
    static SoundEffect soundEffectCue;
    static SoundEffect soundEffectBorder;
    static SoundEffect soundEffectBall1;
    static SoundEffect soundEffectBall2;
    static SoundEffect soundEffectBall3;
    static SoundEffect soundEffectBall4;
    static SoundEffect soundEffectMusik;
    static SoundEffect soundEffectAplod;
    static SoundEffectInstance soundInstancePopadanie;
    static SoundEffectInstance soundInstanceBitokLost;
    static SoundEffectInstance soundInstanceCue;
    static SoundEffectInstance soundInstanceBorder;
    static SoundEffectInstance soundInstanceBall1;
    static SoundEffectInstance soundInstanceBall2;
    static SoundEffectInstance soundInstanceBall3;
    static SoundEffectInstance soundInstanceBall4;
    static SoundEffectInstance soundInstanceMusik;
    static SoundEffectInstance soundInstanceAplod;
    Random rnd = new Random();
    public static void Init(Game game)
    {
      soundEffectBitokLost = game.Content.Load<SoundEffect>("Sound/Piu");
      soundInstanceBitokLost = soundEffectBitokLost.CreateInstance();
      soundEffectPopadanie = game.Content.Load<SoundEffect>("Sound/in");
      soundInstancePopadanie = soundEffectPopadanie.CreateInstance();
      soundEffectCue = game.Content.Load<SoundEffect>("Sound/cue");
      soundInstanceCue = soundEffectCue.CreateInstance();
      soundEffectBorder = game.Content.Load<SoundEffect>("Sound/border");
      soundInstanceBorder = soundEffectBorder.CreateInstance();
      soundEffectBall1 = game.Content.Load<SoundEffect>("Sound/ball1");
      soundInstanceBall1 = soundEffectBall1.CreateInstance();
      soundEffectBall2 = game.Content.Load<SoundEffect>("Sound/ball2");
      soundInstanceBall2 = soundEffectBall2.CreateInstance();
      soundEffectBall3 = game.Content.Load<SoundEffect>("Sound/ball3");
      soundInstanceBall3 = soundEffectBall2.CreateInstance();
      soundEffectBall4 = game.Content.Load<SoundEffect>("Sound/ball4");
      soundInstanceBall4 = soundEffectBall4.CreateInstance();
      soundEffectMusik = game.Content.Load<SoundEffect>("Sound/TwinPeaks");
      soundInstanceMusik = soundEffectMusik.CreateInstance();
      soundInstanceMusik.IsLooped = true;
      soundEffectAplod = game.Content.Load<SoundEffect>("Sound/aplod");
      soundInstanceAplod = soundEffectAplod.CreateInstance();
    }
    public static void PlayCue(float volume)
    {
      soundInstanceCue.Volume = volume;
      soundInstanceCue.Play();
    }
    public static void PlayBall1(float volume)
    {
      //int n = rnd.Next(1, 5);
      float v = Math.Abs(volume / 10);
      //if (n == 1)
      //{
      //  soundInstanceBall1.Volume = Clamp(0, 1, v);
      //  soundInstanceBall1.Play();
      //}
      //else  if (n == 2)
      //{
      //  soundInstanceBall2.Volume = Clamp(0, 1, v);
      //  soundInstanceBall2.Play();
      //}
      //else if (n == 3)
      //{
      //  soundInstanceBall3.Volume = Clamp(0, 1, v);
      //  soundInstanceBall3.Play();
      //}
      //else if (n == 4)
      //{
      //  soundInstanceBall4.Volume = Clamp(0, 1, v);
      //  soundInstanceBall4.Play();
      //}
      if (soundInstanceBall1.State == SoundState.Stopped)
      {
        soundInstanceBall1.Volume = Clamp(0, 1, v);
        soundInstanceBall1.Play();
      }
      else if (soundInstanceBall2.State == SoundState.Stopped)
      {
        soundInstanceBall2.Volume = Clamp(0, 1, v);
        soundInstanceBall2.Play();
      }
      else if (soundInstanceBall3.State == SoundState.Stopped)
      {
        soundInstanceBall3.Volume = Clamp(0, 1, v);
        soundInstanceBall3.Play();
      }
      else if (soundInstanceBall4.State == SoundState.Stopped)
      {
        soundInstanceBall4.Volume = Clamp(0, 1, v);
        soundInstanceBall4.Play();
      }
    }
    public static void PlayBoard(float volume)
    {
      float v = Math.Abs(volume / 2);
      soundInstanceBorder.Volume = Clamp(0, 1, v);
      soundInstanceBorder.Play();
    }
    public static void PlayPopadanie()
    {
      soundInstancePopadanie.Play();
    }
    public static void BitokLost()
    {
      soundInstanceBitokLost.Play();
    }
    public static void PlayMusik()
    {
      soundEffectMusik.Play();
    }
    public static void PlayAplod()
    {
      if (soundInstanceAplod.State == SoundState.Stopped)
      {
        soundInstanceAplod.Play();
      }
    }
    static float Clamp(float min, float max, float value)
    {
      if (value < min)
        value = 0;
      if (value > 1)
        value = 1;     
      return value;
    }
  }
}

To be continue...

Комментариев нет:

Отправить комментарий

Physically Based Rendering