using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using FarseerPhysics.DebugViews; using FarseerPhysics.Dynamics; using FarseerPhysics.Dynamics.Contacts; using FarseerPhysics.Dynamics.Joints; using FarseerPhysics.Factories; using FarseerPhysics.Collision; using FarseerPhysics.Collision.Shapes; using FarseerPhysics.Common; using FarseerPhysics.SamplesFramework; namespace RunGun { class Hero { protected World world; protected Body rect; protected Vector2 rectSize = new Vector2(0.5f, 0.5f); protected Body circ; protected float circRadius = 0.4f; protected RevoluteJoint revJoint; protected FixedAngleJoint angJoint; protected float xVelocityGround = 10; protected float jumpForceGround = -900f * 1.4f; protected bool onWall; protected HashSet wallCache; protected bool onGround; protected HashSet groundCache; private static Vector2 MAX_VELOCITY = new Vector2(200f, 200f); private static Vector2 MIN_VELOCITY = new Vector2(-200f, -200f); public Hero(World world, Vector2 position) { this.world = world; onWall = false; wallCache = new HashSet(); onGround = false; groundCache = new HashSet(); rect = BodyFactory.CreateBody(world, position); rect.BodyType = BodyType.Dynamic; rect.Friction = 0f; rect.Mass = 1f; Vertices rectVerts = PolygonTools.CreateRectangle(rectSize.X, rectSize.Y); PolygonShape rectShape = new PolygonShape(rectVerts, 1.0f); Fixture rectFix = rect.CreateFixture(rectShape); rectFix.OnCollision += OnRectCollision; rectFix.OnSeparation += OnRectSeparation; rectFix.CollisionCategories = Category.Cat1; rectFix.CollidesWith = Category.All & ~Category.Cat1; circ = BodyFactory.CreateBody(world, new Vector2(position.X, position.Y + 0.5f)); circ.Mass = 100f; circ.BodyType = BodyType.Dynamic; circ.Friction = 1000f; CircleShape circShape = new CircleShape(circRadius, 1f); Fixture circFix = circ.CreateFixture(circShape); revJoint = JointFactory.CreateRevoluteJoint(world, rect, circ, rect.LocalCenter); circFix.OnCollision += OnCircleCollision; circFix.OnSeparation += OnCircleSeparation; circFix.CollisionCategories = Category.Cat1; circFix.CollidesWith = Category.All & ~Category.Cat1; revJoint.MotorEnabled = true; revJoint.MaxMotorTorque = 1000f; revJoint.CollideConnected = false; // Make sure the body (rect) never rotates. angJoint = JointFactory.CreateFixedAngleJoint(world, rect); } private bool OnRectCollision(Fixture fixtureA, Fixture fixtureB, Contact contact) { onWall = true; wallCache.Add(fixtureB); return true; } private void OnRectSeparation(Fixture fixtureA, Fixture fixtureB) { if (wallCache.Contains(fixtureB)) { wallCache.Remove(fixtureB); if (wallCache.Count == 0) { onWall = false; } } } private bool OnCircleCollision(Fixture fixtureA, Fixture fixtureB, Contact contact) { groundCache.Add(fixtureB); onGround = true; return true; } private void OnCircleSeparation(Fixture fixtureA, Fixture fixtureB) { if (groundCache.Contains(fixtureB)) { groundCache.Remove(fixtureB); if (groundCache.Count == 0) { onGround = false; } } } public void Update(GameTime gameTime) { MathHelper.Clamp(circ.LinearVelocity.X, MIN_VELOCITY.X, MAX_VELOCITY.X); MathHelper.Clamp(circ.LinearVelocity.Y, MIN_VELOCITY.Y, MAX_VELOCITY.Y); MathHelper.Clamp(rect.LinearVelocity.X, MIN_VELOCITY.X, MAX_VELOCITY.X); MathHelper.Clamp(rect.LinearVelocity.Y, MIN_VELOCITY.Y, MAX_VELOCITY.Y); } public void HandleInput(InputHelper input, GameTime gameTime) { GamePadState padState = input.GamePadState; float stickY = padState.ThumbSticks.Left.Y; float stickX = padState.ThumbSticks.Left.X; if (onGround) { // On ground if (padState.Buttons.LeftShoulder == ButtonState.Pressed) { circ.AngularVelocity = 0f; revJoint.MotorSpeed = 0f; if (onGround) { rect.LinearVelocity = Vector2.Zero; circ.LinearVelocity = new Vector2(0, 0); circ.Awake = false; } } else if (stickX < -InputHelper.STICK_DEAD_ZONE) { // Left revJoint.MotorSpeed = -xVelocityGround / circRadius; } else if (stickX > InputHelper.STICK_DEAD_ZONE) { // Right revJoint.MotorSpeed = xVelocityGround / circRadius; } else { revJoint.MotorSpeed = 0f; circ.AngularVelocity = 0f; // Prevent Hero from bouncing when coming to stop when // moving up a hill if (onGround) { rect.LinearVelocity = Vector2.Zero; circ.LinearVelocity = new Vector2(0, 0); circ.Awake = false; } else { circ.LinearVelocity = new Vector2(0, circ.LinearVelocity.Y); } } } else if (!onWall) { // In air revJoint.MotorSpeed = 0f; if (input.GamePadState.ThumbSticks.Left.X < -InputHelper.STICK_DEAD_ZONE) { // Left if (rect.LinearVelocity.X > 0) { // Player is moving right, make them slowly move left rect.LinearVelocity = new Vector2(-xVelocityGround / 8, rect.LinearVelocity.Y); } else { // Just move rect.LinearVelocity = new Vector2(-xVelocityGround, rect.LinearVelocity.Y); } } else if (input.GamePadState.ThumbSticks.Left.X > InputHelper.STICK_DEAD_ZONE) { // Right if (rect.LinearVelocity.X < 0) { rect.LinearVelocity = new Vector2(xVelocityGround / 8, rect.LinearVelocity.Y); } else { rect.LinearVelocity = new Vector2(xVelocityGround, rect.LinearVelocity.Y); } } } else if (onWall) { rect.LinearVelocity = new Vector2(0, rect.LinearVelocity.Y); } } } }