Difference between revisions of "Game Programming Class6"

esse quam videri
Jump to: navigation, search
(Animation Classes)
m (Text replacement - "syntaxhighlight lang="csharp" line="1" " to "syntaxhighlight lang="csharp"")
 
(38 intermediate revisions by the same user not shown)
Line 1: Line 1:
==Review SVN==
 
  
*Import
 
*Checkout
 
*Update
 
*Merge
 
  
==Midterm Presentation==
+
==Portability==
  
Discuss Midterm Projects requirements
+
Separation of Concerns
 +
*https://msdn.microsoft.com/en-us/library/ee658124.aspx
 +
*http://en.wikipedia.org/wiki/Separation_of_concerns
  
Midterm Version 1 due on 3/15 game is functional and testable
+
Single Responsibility Principle
*Temp art
+
*http://en.wikipedia.org/wiki/Single_responsibility_principle
*First Pass and Game mechanics may not be fully balanced or perfect but is playable
+
*http://www.butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
*All Major Game features have been implemented
 
**Implementations may not be complete but they should be functonal
 
  
Midterm Version 2 due on 3/29 game is ready for public testing
+
==PacMan Class Simplified and Generalized==
*No Temp art
 
*All Game features are implemented and testable
 
*Audio
 
*Animations
 
  
After the midterms games have been tested internally we will revise and then test them externally.
+
<syntaxhighlight lang="csharp">
 +
public enum PacManState { Spawning, Still, Chomping, SuperPacMan }
  
==Simple Animantion==
+
    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;
  
==Animation Classes==
+
        }
  
Way too many classes for me to type here
+
        //Extra method for logging state change
 +
        public virtual void Log(string s)
 +
        {
 +
            //nothing
 +
            Console.WriteLine(s);
 +
        }
 +
    }
 +
</syntaxhighlight>
  
* PacMan States
+
==MovementController in Monogame==
* PacMan Dying Animation
 
* PacMan Eating
 
  
IntroAnimation Project IntroAnimation.zip
+
In MonogameDemos Project is IntroPacManMovementController
  
Ugly but flexible
+
file is PacManController.cs
* DrawableAnimatableSprite.cs
 
* CelAnimationManager.cs
 
  
==Static Members==
+
<syntaxhighlight lang="csharp">
Another Technique
+
sealed class PacManController
 +
    {
 +
        InputHandler input; //game service to handle input
 +
        public Vector2 Direction {get; private set;}
 +
        public float Rotate { get; private set;}
  
Ghosts as a static List
+
        //Checks to see if there is anymovement
 +
        public bool hasInputForMoverment
 +
        {
 +
            get
 +
            {
 +
               
 +
                if (Direction.Length() == 0) return false;
 +
                return true;
 +
            }
 +
        }
  
==Homework==
+
        public PacManController(Game game)
Proof of concept for Midterm 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");
 +
            }
 +
        }
  
*Make a small demo of the main concept of you game.  
+
        public void Update()
*Temp art and missing elements are fine at this point
+
        {
*Don't worry about intro screens
+
            //Input for update from analog stick
*Collect audio and art assets
+
            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);
 +
            }
 +
        }
 +
    }
 +
</syntaxhighlight>
 +
 
 +
GameConsolePacMan.cs //hadles logging
 +
<syntaxhighlight lang="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);
 +
            }
 +
        }
 +
    }
 +
</syntaxhighlight>
 +
 
 +
MonoGamePacMan.cs
 +
<syntaxhighlight lang="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);
 +
        }
 +
    }
 +
</syntaxhighlight>
 +
 
 +
==MovementController in Unity==
 +
Unity Project is GameProgrammingUnity
 +
   
 +
Package is PacManWithFood.unitypackage
 +
   
 +
script is PlayerController.cs
 +
<syntaxhighlight lang="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();
 +
}
 +
}
 +
</syntaxhighlight>
 +
 
 +
UnityPacMan.cs //Hadles logging
 +
<syntaxhighlight lang="csharp">
 +
public class UnityPacMan : PacMan {
 +
 
 +
    private GameObject _gameObject;
 +
 
 +
    public UnityPacMan(GameObject g) : base()
 +
    {
 +
        _gameObject = g;
 +
    }
 +
 
 +
    public override void Log(string s)
 +
    {
 +
        Debug.Log(s);
 +
    }
 +
 +
}
 +
</syntaxhighlight>
 +
 
 +
 
 +
Player.cs
 +
<syntaxhighlight lang="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");
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
 +
 
 +
 
 +
==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
 +
 
 +
<syntaxhighlight lang="csharp">
 +
if (pac.LocationRect.Intersects(TealGhost.LocationRect))
 +
            {
 +
                //Rectangle Collision
 +
                TealGhost.SwitchToGhostHit();
 +
            }
 +
            else
 +
            {
 +
                //No Rectagle Collison
 +
                TealGhost.SwitchToNormalGhost();
 +
            }
 +
</syntaxhighlight>
 +
 
 +
==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.
 +
 
 +
[http://creators.xna.com/en-US/sample/chaseevade Better example not yet implemented]
 +
 
 +
PacMan Chase and Evade example in repo '''IntroChaseEvade''' demostratea
 +
*Collision
 +
*State for feeble AI
 +
*Sprite Markers

Latest revision as of 03:23, 9 February 2016


Portability

Separation of Concerns

Single Responsibility Principle

PacMan Class Simplified and Generalized

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);
        }
    }

MovementController in Monogame

In MonogameDemos Project is IntroPacManMovementController

file is PacManController.cs

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);
            }
        }
    }

GameConsolePacMan.cs //hadles logging

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);
            }
        }
    }

MonoGamePacMan.cs

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);
        }
    }

MovementController in Unity

Unity Project is GameProgrammingUnity

Package is PacManWithFood.unitypackage

script is PlayerController.cs

    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();
	}
}

UnityPacMan.cs //Hadles logging

public class UnityPacMan : PacMan {

    private GameObject _gameObject;

    public UnityPacMan(GameObject g) : base()
    {
        _gameObject = g;
    }

    public override void Log(string s)
    {
        Debug.Log(s);
    }
	
}


Player.cs

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");
    }
}


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

if (pac.LocationRect.Intersects(TealGhost.LocationRect))
            {
                //Rectangle Collision
                TealGhost.SwitchToGhostHit();
            }
            else
            {
                //No Rectagle Collison
                TealGhost.SwitchToNormalGhost();
            }

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