Game Programming Class6

esse quam videri
Revision as of 18:28, 25 January 2016 by Jeff (talk | contribs) (Text replacement - "</csharp>" to "</syntaxhighlight>")
Jump to: navigation, search


Portability

Separation of Concerns

Single Responsibility Principle

PacMan Class Simplified and Generalized

 1 public enum PacManState { Spawning, Still, Chomping, SuperPacMan }
 2 
 3     public class PacMan 
 4     {
 5 
 6         protected PacManState _state;
 7         public PacManState State
 8         {
 9             get { return _state; }
10             set
11             {
12                 if (_state != value)
13                 {
14                     this.Log(string.Format("{0} was: {1} now {2}", this.ToString(), _state, value));
15                     
16                     _state = value;
17                 }
18             }
19         }
20 
21         public PacMan()
22         {
23             
24             //Set default state will call notify so make sure this.Ghosts is intitialized first
25             this.State = PacManState.Still;
26 
27         }
28 
29         //Extra method for logging state change
30         public virtual void Log(string s)
31         {
32             //nothing
33             Console.WriteLine(s);
34         }
35     }

MovementController in Monogame

In MonogameDemos Project is IntroPacManMovementController

file is PacManController.cs

  1 sealed class PacManController
  2     {
  3         InputHandler input; //game service to handle input
  4         public Vector2 Direction {get; private set;}
  5         public float Rotate { get; private set;}
  6 
  7         //Checks to see if there is anymovement
  8         public bool hasInputForMoverment
  9         {
 10             get
 11             {
 12                 
 13                 if (Direction.Length() == 0) return false;
 14                 return true;
 15             }
 16         }
 17 
 18         public PacManController(Game game)
 19         {
 20             //get input handler from game services
 21             input = (InputHandler)game.Services.GetService<IInputHandler>();
 22             if (input == null)
 23             {
 24                 throw new Exception("PacMan controller depends on InputHandler service please add Input Handler as a service first");
 25             }
 26         }
 27 
 28         public void Update()
 29         {
 30             //Input for update from analog stick
 31             GamePadState gamePad1State = input.GamePads[0]; //HACK hard coded player index
 32             #region LeftStick
 33             Vector2 pacStickDir = Vector2.Zero;
 34             if (gamePad1State.ThumbSticks.Left.Length() > 0.0f)
 35             {
 36                 pacStickDir = gamePad1State.ThumbSticks.Left;
 37                 pacStickDir.Y *= -1;      //Invert Y Axis
 38 
 39                 float RotationAngle = (float)Math.Atan2(
 40                     gamePad1State.ThumbSticks.Left.X,
 41                     gamePad1State.ThumbSticks.Left.Y);
 42 
 43                 Rotate = (float)MathHelper.ToDegrees(RotationAngle - (float)(Math.PI / 2));
 44             }
 45             #endregion
 46 
 47             //Update for input from DPad
 48             #region DPad
 49             Vector2 PacManDPadDir = Vector2.Zero;
 50             if (gamePad1State.DPad.Left == ButtonState.Pressed)
 51             {
 52                 //Orginal Position is Right so flip X
 53                 PacManDPadDir += new Vector2(-1, 0);
 54             }
 55             if (gamePad1State.DPad.Right == ButtonState.Pressed)
 56             {
 57                 //Original Position is Right
 58                 PacManDPadDir += new Vector2(1, 0);
 59             }
 60             if (gamePad1State.DPad.Up == ButtonState.Pressed)
 61             {
 62                 //Up
 63                 PacManDPadDir += new Vector2(0, -1);
 64             }
 65             if (gamePad1State.DPad.Down == ButtonState.Pressed)
 66             {
 67                 //Down
 68                 PacManDPadDir += new Vector2(0, 1);
 69             }
 70             if (PacManDPadDir.Length() > 0)
 71             {
 72                 //Angle in radians from vector
 73                 float RotationAngleKey = (float)Math.Atan2(
 74                         PacManDPadDir.X,
 75                         PacManDPadDir.Y * -1);
 76                 //Find angle in degrees
 77                 Rotate = (float)MathHelper.ToDegrees(
 78                     RotationAngleKey - (float)(Math.PI / 2)); //rotated right already
 79 
 80                 //Normalize NewDir to keep agled movement at same speed as horilontal/Vert
 81                 PacManDPadDir = Vector2.Normalize(PacManDPadDir);
 82             }
 83             #endregion
 84 
 85             //Update for input from Keyboard
 86 #if !XBOX360
 87             #region KeyBoard
 88             KeyboardState keyboardState = Keyboard.GetState();
 89             Vector2 PacManKeyDir = new Vector2(0, 0);
 90 
 91             if (keyboardState.IsKeyDown(Keys.Left))
 92             {
 93                 //Flip Horizontal
 94                 PacManKeyDir += new Vector2(-1, 0);
 95             }
 96             if (keyboardState.IsKeyDown(Keys.Right))
 97             {
 98                 //No new sprite Effects
 99                 PacManKeyDir += new Vector2(1, 0);
100             }
101             if (keyboardState.IsKeyDown(Keys.Up))
102             {
103                 PacManKeyDir += new Vector2(0, -1);
104             }
105             if (keyboardState.IsKeyDown(Keys.Down))
106             {
107                 PacManKeyDir += new Vector2(0, 1);
108             }
109             if (PacManKeyDir.Length() > 0)
110             {
111                 float RotationAngleKey = (float)Math.Atan2(
112                         PacManKeyDir.X,
113                         PacManKeyDir.Y * -1);
114 
115                 Rotate = (float)MathHelper.ToDegrees(
116                     RotationAngleKey - (float)(Math.PI / 2));
117 
118                 //Normalize NewDir to keep agled movement at same speed as horilontal/Vert
119                 PacManKeyDir = Vector2.Normalize(PacManKeyDir);
120             }
121             #endregion
122 #endif
123             Direction= PacManKeyDir + PacManDPadDir + pacStickDir;
124             if (Direction.Length() > 0)
125             {
126                 Direction = Vector2.Normalize(Direction);
127             }
128         }
129     }

GameConsolePacMan.cs //hadles logging

 1 class GameConsolePacMan : PacMan
 2     {
 3         GameConsole console;
 4         public GameConsolePacMan()
 5         {
 6             this.console = null;
 7         }
 8 
 9         public GameConsolePacMan(GameConsole console)
10         {
11             this.console = console;
12         }
13 
14         public override void Log(string s)
15         {
16             if (console != null)
17             {
18                 console.GameConsoleWrite(s);
19             }
20             else
21             {
22                 base.Log(s);
23             }
24         }
25     }

MonoGamePacMan.cs

 1 class MonoGamePacMan : IntroGameLibrary.Sprite2.DrawableSprite2
 2     {
 3         internal PacManController controller { get; private set; }
 4         internal GameConsolePacMan PacMan
 5         {
 6             get;
 7             private set;
 8         }
 9         protected PacManState pacState;
10         public PacManState PacState
11         {
12             get { return this.pacState; }
13             //Change pacman state also
14             set { 
15                 if(this.pacState != value)
16                     this.pacState = this.PacMan.State = value; 
17             }
18         }
19                 
20         public MonoGamePacMan(Game game)
21             : base(game)
22         {
23             this.controller = new PacManController(game);
24             PacMan = new GameConsolePacMan((GameConsole)game.Services.GetService<IGameConsole>());
25         }
26 
27         protected override void LoadContent()
28         {
29             base.LoadContent();
30             this.SpriteTexture = content.Load<Texture2D>("PacManSingle");
31             this.Orgin = new Vector2(this.SpriteTexture.Width / 2, this.SpriteTexture.Height / 2);
32             this.Location = new Microsoft.Xna.Framework.Vector2(100, 100);
33             this.Speed = 200;
34         }
35 
36         public override void Update(GameTime gameTime)
37         {
38             //Elapsed time since last update
39             float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
40             
41             this.controller.Update();
42 
43             this.Location += ((this.controller.Direction * (time / 1000)) * Speed);      //Simple Move 
44             this.Rotate = this.controller.Rotate;
45 
46             //Change State based on movement
47             if (this.controller.hasInputForMoverment)
48             {
49                 if(pacState != PacManState.Spawning && pacState != PacManState.SuperPacMan)
50                     this.PacState = PacManState.Chomping;
51             }
52             else
53             {
54                 if (pacState != PacManState.Spawning && pacState != PacManState.SuperPacMan)
55                     this.PacState = PacManState.Still;
56             }
57 
58             //Keep PacMan On Screen
59             if (this.Location.X > Game.GraphicsDevice.Viewport.Width - (this.spriteTexture.Width / 2))
60             {
61                 this.Location.X = Game.GraphicsDevice.Viewport.Width - (this.spriteTexture.Width / 2);
62             }
63             if (this.Location.X < (this.spriteTexture.Width / 2))
64                 this.Location.X = (this.spriteTexture.Width / 2);
65 
66             if (this.Location.Y > Game.GraphicsDevice.Viewport.Height - (this.spriteTexture.Height / 2))
67                 this.Location.Y = Game.GraphicsDevice.Viewport.Height - (this.spriteTexture.Height / 2);
68 
69             if (this.Location.Y < (this.spriteTexture.Height / 2))
70                 this.Location.Y = (this.spriteTexture.Height / 2);
71 
72             base.Update(gameTime);
73         }
74     }

MovementController in Unity

Unity Project is GameProgrammingUnity

Package is PacManWithFood.unitypackage

script is PlayerController.cs

 1     public class PlayerController : MonoBehaviour {
 2 
 3 	public Vector2 direction = new Vector2();
 4     private Vector2 keyDirection;
 5     private Vector2 padDirection;
 6 	public bool hasInputForMoverment {
 7 		get {
 8             //Debug.Log(direction.sqrMagnitude);
 9             if (direction.magnitude == 0) return false;
10 			return true;}
11 	}
12 
13     public PlayerController()
14     {
15         keyDirection = new Vector2();
16     }
17 	
18 	// Use this for initialization
19 	void Start () {
20 		
21 	}
22 	
23 	// Update is called once per frame
24 	void Update () {
25 		
26         keyDirection.x = keyDirection.y = 0;
27 		
28         //Keyboard
29         if (Input.GetKey("right"))
30         {
31             keyDirection.x += 1;
32         }
33 		if (Input.GetKey ("left")) {
34             keyDirection.x += -1;
35 		}
36 
37         if (Input.GetKey("up"))
38         {
39             keyDirection.y += 1;
40         }
41 		if (Input.GetKey ("down")) {
42             keyDirection.y += -1;
43 		}
44         direction = keyDirection;
45 
46         //Gamepad
47         padDirection.x = Input.GetAxis("Horizontal");
48         padDirection.y = Input.GetAxis("Vertical");
49 
50         if (padDirection.magnitude > 0)
51         {
52             //Debug.Log(padDirection + " " + padDirection.magnitude + " " + (padDirection.magnitude > 0));
53             direction += padDirection;
54         }
55 
56         //normalize
57         direction.Normalize();
58 	}
59 }

UnityPacMan.cs //Hadles logging

 1 public class UnityPacMan : PacMan {
 2 
 3     private GameObject _gameObject;
 4 
 5     public UnityPacMan(GameObject g) : base()
 6     {
 7         _gameObject = g;
 8     }
 9 
10     public override void Log(string s)
11     {
12         Debug.Log(s);
13     }
14 	
15 }


Player.cs

 1 public class Player : MonoBehaviour {
 2 
 3     private PlayerController controller;
 4     public Vector2 Direction = new Vector2(1, 0);
 5     public float Speed = 10;
 6     public float Angle;
 7 
 8     public UnityPacMan PacMan { get; private set; }
 9 
10     private Vector3 moveTranslation;
11     
12     // Use this for initialization
13 	void Start () {
14         //Get PlayerController from game object
15 		controller = GetComponent<PlayerController>();
16 		//Log error if controller is null will throw null refernece exception eventually
17 		if (controller == null) {
18 			Debug.LogWarning( "GetComponent of type " + typeof( PlayerController ) + " failed on " + this.name, this );
19 		}
20 
21 		//or
22 		//Util.GetComponentIfNull<PlayerController> (this, ref controller);
23 
24         PacMan = new UnityPacMan(this.gameObject);
25 	}
26 	
27 	// Update is called once per frame
28 	void Update () {
29         if (this.controller.hasInputForMoverment) 
30         {
31 			this.Direction = this.controller.direction;
32 			Angle = Mathf.Atan2 (this.Direction.y, this.Direction.x) * Mathf.Rad2Deg;
33 			this.transform.eulerAngles = new Vector3 (0, 0, Angle);
34             if (this.PacMan.State != PacManState.SuperPacMan)
35             {
36                 this.PacMan.State = PacManState.Chomping;
37             }
38 		}
39 		else
40 		{
41 			this.Direction = new Vector2(0,0);
42             if (this.PacMan.State != PacManState.SuperPacMan)
43             {
44                 this.PacMan.State = PacManState.Still;
45             }
46 		}
47 		
48 		this.moveTranslation = new Vector3(this.Direction.x, this.Direction.y) * Time.deltaTime * this.Speed;
49 		this.transform.position += new Vector3(this.moveTranslation.x, this.moveTranslation.y);
50         
51 	}
52 
53     public virtual void PowerUp()
54     {
55         this.PacMan.State = PacManState.SuperPacMan;
56         this.StartCoroutine("PowerUpTimer");
57     }
58 
59     
60 
61     IEnumerator PowerUpTimer()
62     {
63         this.PacMan.Notify("SuperPacMan");
64         yield return new WaitForSeconds(3);
65         this.PacMan.State = PacManState.Still;
66         this.PacMan.Notify("SuperPacMan End");
67     }
68 }


Advanced Sprites/Collision

Simple Collision

Check if two rectangles intersect. By adding a rectangle that represents the area of the sprite it's easy to ask XNA if two rectangles intersect

3 tutorial on App Hub


Rectangle Collision

Demo

Create two simple DrawableSprite2 objects then check for triangle collision

 1 if (pac.LocationRect.Intersects(TealGhost.LocationRect))
 2             {
 3                 //Rectangle Collision
 4                 TealGhost.SwitchToGhostHit();
 5             }
 6             else
 7             {
 8                 //No Rectagle Collison
 9                 TealGhost.SwitchToNormalGhost();
10             }

PerPixelCollision

Load both textures into a color array. Make a rectangle of the intersection of the two textures. Check all the pixels in intersection of the color arrays for intersecting pixels.

The definition for both methods is in the Sprite class (Sprite.cs)

Chase and Evade

Example of simple states and simple vector geometry.

Better example not yet implemented

PacMan Chase and Evade example in repo IntroChaseEvade demostratea

  • Collision
  • State for feeble AI
  • Sprite Markers