Difference between revisions of "Game Programming Class6"
m (Text replacement - "<csharp>" to "<syntaxhighlight lang="csharp" line="1" >") |
m (Text replacement - "</csharp>" to "</syntaxhighlight>") |
||
Line 49: | Line 49: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
==MovementController in Monogame== | ==MovementController in Monogame== | ||
Line 187: | Line 187: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
GameConsolePacMan.cs //hadles logging | GameConsolePacMan.cs //hadles logging | ||
Line 216: | Line 216: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
MonoGamePacMan.cs | MonoGamePacMan.cs | ||
Line 294: | Line 294: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
==MovementController in Unity== | ==MovementController in Unity== | ||
Line 362: | Line 362: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
UnityPacMan.cs //Hadles logging | UnityPacMan.cs //Hadles logging | ||
Line 381: | Line 381: | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
Line 455: | Line 455: | ||
} | } | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
Line 487: | Line 487: | ||
TealGhost.SwitchToNormalGhost(); | TealGhost.SwitchToNormalGhost(); | ||
} | } | ||
− | </ | + | </syntaxhighlight> |
==PerPixelCollision== | ==PerPixelCollision== |
Revision as of 18:28, 25 January 2016
Contents
Portability
Separation of Concerns
- https://msdn.microsoft.com/en-us/library/ee658124.aspx
- http://en.wikipedia.org/wiki/Separation_of_concerns
Single Responsibility Principle
- http://en.wikipedia.org/wiki/Single_responsibility_principle
- http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
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
- http://xbox.create.msdn.com/en-us/education/catalog/tutorial/collision_2d_rectangle
- http://xbox.create.msdn.com/en-US/education/catalog/tutorial/collision_2d_perpixel
- http://xbox.create.msdn.com/en-US/education/catalog/tutorial/collision_2d_perpixel_transformed
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