Game Programming Class6
Contents
Physics
c# Box2D https://code.google.com/p/box2dx/
https://github.com/d-snp/Farseer-Physics
http://farseerphysics.codeplex.com/
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
<csharp> public enum PacManState { Spawning, Still, Chomping, SuperPacMan }
public class PacMan {
protected PacManState _state; public PacManState State { get { return _state; } set { if (_state != value) { this.Log(string.Format("{0} was: {1} now {2}", this.ToString(), _state, value)); _state = value; } } }
public PacMan() { //Set default state will call notify so make sure this.Ghosts is intitialized first this.State = PacManState.Still;
}
//Extra method for logging state change public virtual void Log(string s) { //nothing Console.WriteLine(s); } }
</csharp>
MovementController in Monogame
In MonogameDemos Project is IntroPacManMovementController
file is PacManController.cs
<csharp> sealed class PacManController
{ InputHandler input; //game service to handle input public Vector2 Direction {get; private set;} public float Rotate { get; private set;}
//Checks to see if there is anymovement public bool hasInputForMoverment { get { if (Direction.Length() == 0) return false; return true; } }
public PacManController(Game game) { //get input handler from game services input = (InputHandler)game.Services.GetService<IInputHandler>(); if (input == null) { throw new Exception("PacMan controller depends on InputHandler service please add Input Handler as a service first"); } }
public void Update() { //Input for update from analog stick GamePadState gamePad1State = input.GamePads[0]; //HACK hard coded player index #region LeftStick Vector2 pacStickDir = Vector2.Zero; if (gamePad1State.ThumbSticks.Left.Length() > 0.0f) { pacStickDir = gamePad1State.ThumbSticks.Left; pacStickDir.Y *= -1; //Invert Y Axis
float RotationAngle = (float)Math.Atan2( gamePad1State.ThumbSticks.Left.X, gamePad1State.ThumbSticks.Left.Y);
Rotate = (float)MathHelper.ToDegrees(RotationAngle - (float)(Math.PI / 2)); } #endregion
//Update for input from DPad #region DPad Vector2 PacManDPadDir = Vector2.Zero; if (gamePad1State.DPad.Left == ButtonState.Pressed) { //Orginal Position is Right so flip X PacManDPadDir += new Vector2(-1, 0); } if (gamePad1State.DPad.Right == ButtonState.Pressed) { //Original Position is Right PacManDPadDir += new Vector2(1, 0); } if (gamePad1State.DPad.Up == ButtonState.Pressed) { //Up PacManDPadDir += new Vector2(0, -1); } if (gamePad1State.DPad.Down == ButtonState.Pressed) { //Down PacManDPadDir += new Vector2(0, 1); } if (PacManDPadDir.Length() > 0) { //Angle in radians from vector float RotationAngleKey = (float)Math.Atan2( PacManDPadDir.X, PacManDPadDir.Y * -1); //Find angle in degrees Rotate = (float)MathHelper.ToDegrees( RotationAngleKey - (float)(Math.PI / 2)); //rotated right already
//Normalize NewDir to keep agled movement at same speed as horilontal/Vert PacManDPadDir = Vector2.Normalize(PacManDPadDir); } #endregion
//Update for input from Keyboard
- if !XBOX360
#region KeyBoard KeyboardState keyboardState = Keyboard.GetState(); Vector2 PacManKeyDir = new Vector2(0, 0);
if (keyboardState.IsKeyDown(Keys.Left)) { //Flip Horizontal PacManKeyDir += new Vector2(-1, 0); } if (keyboardState.IsKeyDown(Keys.Right)) { //No new sprite Effects PacManKeyDir += new Vector2(1, 0); } if (keyboardState.IsKeyDown(Keys.Up)) { PacManKeyDir += new Vector2(0, -1); } if (keyboardState.IsKeyDown(Keys.Down)) { PacManKeyDir += new Vector2(0, 1); } if (PacManKeyDir.Length() > 0) { float RotationAngleKey = (float)Math.Atan2( PacManKeyDir.X, PacManKeyDir.Y * -1);
Rotate = (float)MathHelper.ToDegrees( RotationAngleKey - (float)(Math.PI / 2));
//Normalize NewDir to keep agled movement at same speed as horilontal/Vert PacManKeyDir = Vector2.Normalize(PacManKeyDir); } #endregion
- endif
Direction= PacManKeyDir + PacManDPadDir + pacStickDir; if (Direction.Length() > 0) { Direction = Vector2.Normalize(Direction); } } }
</csharp>
GameConsolePacMan.cs //hadles logging <csharp> class GameConsolePacMan : PacMan
{ GameConsole console; public GameConsolePacMan() { this.console = null; }
public GameConsolePacMan(GameConsole console) { this.console = console; }
public override void Log(string s) { if (console != null) { console.GameConsoleWrite(s); } else { base.Log(s); } } }
</csharp>
MonoGamePacMan.cs <csharp> class MonoGamePacMan : IntroGameLibrary.Sprite2.DrawableSprite2
{ internal PacManController controller { get; private set; } internal GameConsolePacMan PacMan { get; private set; } protected PacManState pacState; public PacManState PacState { get { return this.pacState; } //Change pacman state also set { if(this.pacState != value) this.pacState = this.PacMan.State = value; } } public MonoGamePacMan(Game game) : base(game) { this.controller = new PacManController(game); PacMan = new GameConsolePacMan((GameConsole)game.Services.GetService<IGameConsole>()); }
protected override void LoadContent() { base.LoadContent(); this.SpriteTexture = content.Load<Texture2D>("PacManSingle"); this.Orgin = new Vector2(this.SpriteTexture.Width / 2, this.SpriteTexture.Height / 2); this.Location = new Microsoft.Xna.Framework.Vector2(100, 100); this.Speed = 200; }
public override void Update(GameTime gameTime) { //Elapsed time since last update float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds; this.controller.Update();
this.Location += ((this.controller.Direction * (time / 1000)) * Speed); //Simple Move this.Rotate = this.controller.Rotate;
//Change State based on movement if (this.controller.hasInputForMoverment) { if(pacState != PacManState.Spawning && pacState != PacManState.SuperPacMan) this.PacState = PacManState.Chomping; } else { if (pacState != PacManState.Spawning && pacState != PacManState.SuperPacMan) this.PacState = PacManState.Still; }
//Keep PacMan On Screen if (this.Location.X > Game.GraphicsDevice.Viewport.Width - (this.spriteTexture.Width / 2)) { this.Location.X = Game.GraphicsDevice.Viewport.Width - (this.spriteTexture.Width / 2); } if (this.Location.X < (this.spriteTexture.Width / 2)) this.Location.X = (this.spriteTexture.Width / 2);
if (this.Location.Y > Game.GraphicsDevice.Viewport.Height - (this.spriteTexture.Height / 2)) this.Location.Y = Game.GraphicsDevice.Viewport.Height - (this.spriteTexture.Height / 2);
if (this.Location.Y < (this.spriteTexture.Height / 2)) this.Location.Y = (this.spriteTexture.Height / 2);
base.Update(gameTime); } }
</csharp>
MovementController in Unity
Unity Project is GameProgrammingUnity
Package is PacManWithFood.unitypackage
script is PlayerController.cs <csharp>
public class PlayerController : MonoBehaviour {
public Vector2 direction = new Vector2();
private Vector2 keyDirection; private Vector2 padDirection;
public bool hasInputForMoverment { get {
//Debug.Log(direction.sqrMagnitude); if (direction.magnitude == 0) return false;
return true;} }
public PlayerController() { keyDirection = new Vector2(); }
// Use this for initialization void Start () {
}
// Update is called once per frame void Update () {
keyDirection.x = keyDirection.y = 0;
//Keyboard if (Input.GetKey("right")) { keyDirection.x += 1; }
if (Input.GetKey ("left")) {
keyDirection.x += -1;
}
if (Input.GetKey("up")) { keyDirection.y += 1; }
if (Input.GetKey ("down")) {
keyDirection.y += -1;
}
direction = keyDirection;
//Gamepad padDirection.x = Input.GetAxis("Horizontal"); padDirection.y = Input.GetAxis("Vertical");
if (padDirection.magnitude > 0) { //Debug.Log(padDirection + " " + padDirection.magnitude + " " + (padDirection.magnitude > 0)); direction += padDirection; }
//normalize direction.Normalize();
} } </csharp>
UnityPacMan.cs //Hadles logging <csharp> public class UnityPacMan : PacMan {
private GameObject _gameObject;
public UnityPacMan(GameObject g) : base() { _gameObject = g; }
public override void Log(string s) { Debug.Log(s); }
} </csharp>
Player.cs
<csharp>
public class Player : MonoBehaviour {
private PlayerController controller; public Vector2 Direction = new Vector2(1, 0); public float Speed = 10; public float Angle;
public UnityPacMan PacMan { get; private set; }
private Vector3 moveTranslation; // Use this for initialization
void Start () {
//Get PlayerController from game object
controller = GetComponent<PlayerController>(); //Log error if controller is null will throw null refernece exception eventually if (controller == null) { Debug.LogWarning( "GetComponent of type " + typeof( PlayerController ) + " failed on " + this.name, this ); }
//or //Util.GetComponentIfNull<PlayerController> (this, ref controller);
PacMan = new UnityPacMan(this.gameObject);
}
// Update is called once per frame void Update () {
if (this.controller.hasInputForMoverment) {
this.Direction = this.controller.direction; Angle = Mathf.Atan2 (this.Direction.y, this.Direction.x) * Mathf.Rad2Deg; this.transform.eulerAngles = new Vector3 (0, 0, Angle);
if (this.PacMan.State != PacManState.SuperPacMan) { this.PacMan.State = PacManState.Chomping; }
} else { this.Direction = new Vector2(0,0);
if (this.PacMan.State != PacManState.SuperPacMan) { this.PacMan.State = PacManState.Still; }
}
this.moveTranslation = new Vector3(this.Direction.x, this.Direction.y) * Time.deltaTime * this.Speed; this.transform.position += new Vector3(this.moveTranslation.x, this.moveTranslation.y);
}
public virtual void PowerUp() { this.PacMan.State = PacManState.SuperPacMan; this.StartCoroutine("PowerUpTimer"); }
IEnumerator PowerUpTimer() { this.PacMan.Notify("SuperPacMan"); yield return new WaitForSeconds(3); this.PacMan.State = PacManState.Still; this.PacMan.Notify("SuperPacMan End"); }
} </csharp>
Simple Animation
what extra fields do we need for animation?
http://create.msdn.com/en-US/education/catalog/sample/sprite_sheet
Platformer Example
Show platformer starter kit
http://msdn.microsoft.com/en-us/library/dd254918(v=xnagamestudio.31).aspx
simple and elegant but not that flexible
Animation Classes
Way too many classes for me to type here
- PacMan States
- PacMan Dying Animation
- PacMan Eating
IntroAnimation Project IntroAnimation.zip
Complicated but flexible
- DrawableAnimatableSprite.cs
- CelAnimationManager.cs
Homework
/* Shooting Game
- must use game components
- must be multiplayer (both on keyboard or multiple game pads) don't use networking
- must be able to shoot at each other or work together to shoot enemies
- include shot manager and or shot manager
- /