Advertisement
Guest User

Controller2D.cs

a guest
Jan 19th, 2017
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.05 KB | None | 0 0
  1. using System;
  2. using System.Linq;
  3. using Duality;
  4. using Duality.Components.Physics;
  5. using Duality.Components.Renderers;
  6. using Enemy;
  7. using Player;
  8.  
  9. namespace Behavior
  10. {
  11.     /// <summary>
  12.     /// Does a majority of the calculations for the platformer movement system.
  13.     /// </summary>
  14.     public class Controller2D : Component, ICmpInitializable, ICmpUpdatable
  15.     {
  16.         public enum EntityType
  17.         {
  18.             Player,
  19.             GreenAppowl,
  20.             RedAppowl,
  21.             Grapeshooter,
  22.             Dragonfruit
  23.         }
  24.  
  25.         public CollisionInfo Collisions
  26.         {
  27.             get { return collisions; }
  28.         }
  29.  
  30.         public EntityType entityType { get; set; }
  31.         public Vector2 SpriteBoundsOffset { get; set; }  //new Vector2(14.4f, 10.12f); //Bounds calculations get this value subtracted from them.
  32.         public Vector2 SpriteBoundsPositionOffset { get; set; } // new Vector2(7.4f, 10);
  33.         public CollisionCategory CollidesWith { get; set; }
  34.  
  35.         private Rect bounds;
  36.         private CollisionInfo collisions;
  37.         private float horizontalRaySpacing;
  38.         private RayCastOrigins raycastOrigins;
  39.         private float verticalRaySpacing;
  40.         private float SkinWidth { get; } = 0.015f;
  41.         private int HorizontalRayCount { get; set; } = 3;
  42.         private int VerticalRayCount { get; set; } = 3;
  43.         private Enemy.FacingDirection facingDirection;
  44.         private RigidBody rigidBody;
  45.         private PlayerController playerController; //TODO add monster control support
  46.         private EnemyController enemyController;
  47.         private float maxClimbAngle = 60;
  48.  
  49.  
  50.         public void OnInit(InitContext context)
  51.         {
  52.             CalculateBounds();
  53.             CalculateRaySpacing();
  54.             SetCorrectColliderBounds();
  55.             rigidBody = GameObj.GetComponent<RigidBody>();
  56.             if (GameObj.GetComponent<PlayerController>() != null)
  57.                 playerController = GameObj.GetComponent<PlayerController>();
  58.             else
  59.                 enemyController = GameObj.GetComponent<EnemyController>();
  60.         }
  61.  
  62.         public void OnShutdown(ShutdownContext context)
  63.         {
  64.         }
  65.  
  66.         public void OnUpdate()
  67.         {
  68.             if (entityType != EntityType.Player)
  69.             {
  70.                 facingDirection = GameObj.GetComponent<EnemyController>().FacingDirection;
  71.             }
  72.  
  73.             AdjustColliderPosition();
  74.         }
  75.  
  76.         public void Move(Vector2 velocity)
  77.         {
  78.             CalculateBounds();
  79.             CalculateRayCastOrigins();
  80.             collisions.Reset();
  81.  
  82.             if (velocity.X != 0.0)
  83.                 HorizontalCollisions(ref velocity);
  84.             if (velocity.Y != 0.0)
  85.                 VerticalCollisions(ref velocity);
  86.  
  87.             GameObj.Transform.MoveByAbs(velocity);
  88.         }
  89.  
  90.         private void HorizontalCollisions(ref Vector2 velocity)
  91.         {
  92.             var directionX = MathF.Sign(velocity.X);
  93.             var rayLength = MathF.Abs(velocity.X) + SkinWidth;
  94.  
  95.             for (var i = 0; i < HorizontalRayCount; i++)
  96.             {
  97.                 var rayOrigin = directionX == -1 ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
  98.                 rayOrigin -= Vector2.UnitY * (horizontalRaySpacing * i);
  99.  
  100.                 if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor)
  101.                     VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, directionX * rayLength, 0);
  102.  
  103.                 RayCastCallback raycastCallback = data =>
  104.                 {
  105.                     if ((data.Body.CollisionCategory & CollidesWith) != 0)
  106.                         return 1.0f;
  107.                     else
  108.                         return -1.0f;
  109.                 };
  110.                 RayCastData rayCastData; //If statement's data is outputted to here.
  111.  
  112.                 if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitX * directionX * rayLength, raycastCallback,
  113.                     out rayCastData))
  114.                 {
  115.                     float _slopeAngleRad = Vector2.AngleBetween(rayCastData.Normal, new Vector2(0, 1));
  116.                     float _slopeAngleDeg = MathF.Abs(MathF.RadToDeg(_slopeAngleRad) - 180); //Convert to degrees, account for flat angle, get positive value.
  117.  
  118.                     if (i == 0 && _slopeAngleDeg <= maxClimbAngle)
  119.                         ClimbSlope(ref velocity, _slopeAngleDeg);
  120.  
  121.  
  122.                     var distance = (rayOrigin - rayCastData.Pos).Length;
  123.  
  124.                     velocity.X = (distance - SkinWidth) * directionX;
  125.                     rayLength = distance;
  126.  
  127.                     collisions.right = directionX == 1;
  128.                     collisions.left = directionX == -1;
  129.                 }
  130.             }
  131.         }
  132.  
  133.         private void VerticalCollisions(ref Vector2 velocity)
  134.         {
  135.             var directionY = MathF.Sign(velocity.Y);
  136.             var rayLength = MathF.Abs(velocity.Y) + SkinWidth;
  137.  
  138.             for (var i = 0; i < VerticalRayCount; i++)
  139.             {
  140.                 var rayOrigin = directionY == -1 ? raycastOrigins.topLeft : raycastOrigins.bottomLeft;
  141.                 rayOrigin += Vector2.UnitX * (verticalRaySpacing * i + velocity.X);
  142.  
  143.                 if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor)
  144.                     VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, 0, directionY * rayLength);
  145.  
  146.                 RayCastCallback raycastCallback = data =>
  147.                 {
  148.                     if ((data.Body.CollisionCategory & CollidesWith) != 0)
  149.                         return 1.0f;
  150.                     else
  151.                         return -1.0f;
  152.                 };
  153.                 RayCastData rayCastData;
  154.  
  155.                 if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitY * directionY * rayLength, raycastCallback,
  156.                     out rayCastData))
  157.                 {
  158.                     var distance = (rayOrigin - rayCastData.Pos).Length;
  159.                     velocity.Y = (distance - SkinWidth) * directionY;
  160.                     rayLength = distance;
  161.  
  162.                     collisions.below = directionY == 1;
  163.                     collisions.above = directionY == -1;
  164.                 }
  165.             }
  166.         }
  167.  
  168.         private void CalculateBounds()
  169.         {
  170.             var spriteRenderer = GameObj.GetComponent<SpriteRenderer>();
  171.             var animSpriteRenderer = GameObj.GetComponent<AnimSpriteRenderer>();
  172.             if (spriteRenderer != null)
  173.             {
  174.                 bounds = new Rect(
  175.                     GameObj.Transform.Pos.X + spriteRenderer.Rect.X + SpriteBoundsPositionOffset.X,
  176.                     GameObj.Transform.Pos.Y + spriteRenderer.Rect.Y + SpriteBoundsPositionOffset.Y,
  177.                     spriteRenderer.Rect.W - SpriteBoundsOffset.X,
  178.                     spriteRenderer.Rect.H - SpriteBoundsOffset.Y);
  179.             }
  180.             else if (animSpriteRenderer != null)
  181.             {
  182.                 bounds = new Rect(
  183.                     GameObj.Transform.Pos.X + animSpriteRenderer.Rect.X,
  184.                     GameObj.Transform.Pos.Y + animSpriteRenderer.Rect.Y,
  185.                     animSpriteRenderer.Rect.W,
  186.                     animSpriteRenderer.Rect.H);
  187.             }
  188.             else
  189.             {
  190.                 Log.Game.WriteError("A spriterenderer or animspriterenderer has to be attached!");
  191.                 bounds = new Rect();
  192.             }
  193.         }
  194.  
  195.         private void CalculateRayCastOrigins()
  196.         {
  197.             var shrinkedBounds = new Rect(bounds.X + SkinWidth, bounds.Y + SkinWidth, bounds.W - 2 * SkinWidth,
  198.                 bounds.H - 2 * SkinWidth);
  199.             raycastOrigins.topLeft = shrinkedBounds.TopLeft;
  200.             raycastOrigins.bottomLeft = shrinkedBounds.BottomLeft;
  201.             raycastOrigins.topRight = shrinkedBounds.TopRight;
  202.             raycastOrigins.bottomRight = shrinkedBounds.BottomRight;
  203.         }
  204.  
  205.         private void CalculateRaySpacing()
  206.         {
  207.             var shrinkedBounds = new Rect(bounds.X + SkinWidth, bounds.Y + SkinWidth, bounds.W - 2 * SkinWidth,
  208.                 bounds.H - 2 * SkinWidth);
  209.  
  210.             HorizontalRayCount = MathF.Clamp(HorizontalRayCount, 2, int.MaxValue);
  211.             VerticalRayCount = MathF.Clamp(VerticalRayCount, 2, int.MaxValue);
  212.  
  213.             horizontalRaySpacing = shrinkedBounds.H / (HorizontalRayCount - 1);
  214.             verticalRaySpacing = shrinkedBounds.W / (VerticalRayCount - 1);
  215.         }
  216.  
  217.         private void ClimbSlope(ref Vector2 velocity, float slopeAngle)
  218.         {
  219.             float moveDistance = MathF.Abs(velocity.X);
  220.             playerController.velocity.Y = MathF.Sin(MathF.DegToRad(slopeAngle)) * moveDistance;
  221.             playerController.velocity.X = MathF.Cos(MathF.DegToRad(slopeAngle)) * moveDistance * MathF.Sign(velocity.X);
  222.  
  223.             Log.Game.Write("Velocity is {0}, moveDistance is {1}, slopeAngle is {2}", velocity, moveDistance, slopeAngle);
  224.         }
  225.  
  226.         public struct CollisionInfo
  227.         {
  228.             public bool above, below, left, right;
  229.             public float slopeAngle;
  230.             public float slopeAngleOld;
  231.             public bool climbingSlope;
  232.  
  233.             public void Reset()
  234.             {
  235.                 above = below = left = right = false;
  236.                 slopeAngleOld = slopeAngle;
  237.             }
  238.         }
  239.  
  240.         private struct RayCastOrigins
  241.         {
  242.             public Vector2 topLeft, bottomLeft, topRight, bottomRight;
  243.         }
  244.  
  245.         private void SetCorrectColliderBounds()
  246.         {
  247.             switch (entityType)
  248.             {
  249.                 case EntityType.Player:
  250.                     SpriteBoundsOffset = new Vector2(14.4f, 10.12f);
  251.                     SpriteBoundsPositionOffset = new Vector2(7.4f, 10);
  252.                     break;
  253.                 case EntityType.GreenAppowl:
  254.                     SpriteBoundsOffset = new Vector2(14.4f, 17);
  255.                     SpriteBoundsPositionOffset = new Vector2(7.4f, 10);
  256.                     break;
  257.             }
  258.         }
  259.  
  260.         /// <summary>
  261.         /// Adjust collider position based on FacingDirection.
  262.         /// </summary>
  263.         private void AdjustColliderPosition()
  264.         {
  265.             switch (entityType)
  266.             {
  267.                 case EntityType.GreenAppowl:
  268.                     CircleShapeInfo _circleShapeInfo = (CircleShapeInfo)GameObj.GetComponent<RigidBody>().Shapes.First();
  269.                     if (facingDirection == Enemy.FacingDirection.Left)
  270.                     {
  271.                         if (_circleShapeInfo.Position.X < 0) //X is not negative
  272.                             _circleShapeInfo.Position = new Vector2(_circleShapeInfo.Position.X * -1, _circleShapeInfo.Position.Y);
  273.                     }
  274.                     else if (facingDirection == Enemy.FacingDirection.Right)
  275.                     {
  276.                         if (_circleShapeInfo.Position.X > 0)
  277.                             _circleShapeInfo.Position = new Vector2(_circleShapeInfo.Position.X * -1, _circleShapeInfo.Position.Y);
  278.                     }
  279.  
  280.                     break;
  281.  
  282.             }
  283.         }
  284.     }
  285. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement