SHARE
TWEET

Untitled

a guest Mar 9th, 2017 21 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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.             collisions.climbingSlope = false;
  95.  
  96.             for (var i = 0; i < HorizontalRayCount; i++)
  97.             {
  98.                 var rayOrigin = directionX == -1 ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
  99.                 rayOrigin -= Vector2.UnitY * (horizontalRaySpacing * i);
  100.  
  101.                 if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor)
  102.                     VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, directionX * rayLength, 0);
  103.  
  104.                 RayCastCallback raycastCallback = data =>
  105.                 {
  106.                     if ((data.Body.CollisionCategory & CollidesWith) != 0)
  107.                         return 1.0f;
  108.                     else
  109.                         return -1.0f;
  110.                 };
  111.                 RayCastData rayCastData; //If statement's data is outputted to here.
  112.  
  113.                 if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitX * directionX * rayLength, raycastCallback,
  114.                     out rayCastData))
  115.                 {
  116.                     float _slopeAngleRad = Vector2.AngleBetween(rayCastData.Normal, new Vector2(0, 1));
  117.                     float _slopeAngleDeg = MathF.Abs(MathF.RadToDeg(_slopeAngleRad) - 180); //Convert to degrees, account for flat angle, get positive value.
  118.  
  119.                     if (i == 0 && _slopeAngleDeg <= maxClimbAngle)
  120.                     {
  121.                         ClimbSlope(ref velocity, _slopeAngleDeg);
  122.                     }
  123.                     else
  124.                     {
  125.                         var distance = (rayOrigin - rayCastData.Pos).Length;
  126.                         velocity.X = (distance - SkinWidth) * directionX;
  127.                         rayLength = distance;
  128.                     }
  129.  
  130.                     collisions.right = directionX == 1;
  131.                     collisions.left = directionX == -1;
  132.                 }
  133.             }
  134.         }
  135.  
  136.         private void VerticalCollisions(ref Vector2 velocity)
  137.         {
  138.             var directionY = MathF.Sign(velocity.Y);
  139.             var rayLength = MathF.Abs(velocity.Y) + SkinWidth;
  140.  
  141.             for (var i = 0; i < VerticalRayCount; i++)
  142.             {
  143.                 var rayOrigin = directionY == -1 ? raycastOrigins.topLeft : raycastOrigins.bottomLeft;
  144.                 rayOrigin += Vector2.UnitX * (verticalRaySpacing * i + velocity.X);
  145.  
  146.                 if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor)
  147.                     VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, 0, directionY * rayLength);
  148.  
  149.                 RayCastCallback raycastCallback = data =>
  150.                 {
  151.                     if ((data.Body.CollisionCategory & CollidesWith) != 0)
  152.                         return 1.0f;
  153.                     else
  154.                         return -1.0f;
  155.                 };
  156.                 RayCastData rayCastData;
  157.  
  158.                 if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitY * directionY * rayLength, raycastCallback,
  159.                     out rayCastData))
  160.                 {
  161.                     var distance = (rayOrigin - rayCastData.Pos).Length;
  162.                     velocity.Y = (distance - SkinWidth) * directionY;
  163.                     rayLength = distance;
  164.  
  165.                     collisions.below = directionY == 1;
  166.                     collisions.above = directionY == -1;
  167.                 }
  168.             }
  169.         }
  170.  
  171.         private void CalculateBounds()
  172.         {
  173.             var spriteRenderer = GameObj.GetComponent<SpriteRenderer>();
  174.             var animSpriteRenderer = GameObj.GetComponent<AnimSpriteRenderer>();
  175.             if (spriteRenderer != null)
  176.             {
  177.                 bounds = new Rect(
  178.                     GameObj.Transform.Pos.X + spriteRenderer.Rect.X + SpriteBoundsPositionOffset.X,
  179.                     GameObj.Transform.Pos.Y + spriteRenderer.Rect.Y + SpriteBoundsPositionOffset.Y,
  180.                     spriteRenderer.Rect.W - SpriteBoundsOffset.X,
  181.                     spriteRenderer.Rect.H - SpriteBoundsOffset.Y);
  182.             }
  183.             else if (animSpriteRenderer != null)
  184.             {
  185.                 bounds = new Rect(
  186.                     GameObj.Transform.Pos.X + animSpriteRenderer.Rect.X,
  187.                     GameObj.Transform.Pos.Y + animSpriteRenderer.Rect.Y,
  188.                     animSpriteRenderer.Rect.W,
  189.                     animSpriteRenderer.Rect.H);
  190.             }
  191.             else
  192.             {
  193.                 Log.Game.WriteError("A spriterenderer or animspriterenderer has to be attached!");
  194.                 bounds = new Rect();
  195.             }
  196.         }
  197.  
  198.         private void CalculateRayCastOrigins()
  199.         {
  200.             var shrinkedBounds = new Rect(bounds.X + SkinWidth, bounds.Y + SkinWidth, bounds.W - 2 * SkinWidth,
  201.                 bounds.H - 2 * SkinWidth);
  202.             raycastOrigins.topLeft = shrinkedBounds.TopLeft;
  203.             raycastOrigins.bottomLeft = shrinkedBounds.BottomLeft;
  204.             raycastOrigins.topRight = shrinkedBounds.TopRight;
  205.             raycastOrigins.bottomRight = shrinkedBounds.BottomRight;
  206.         }
  207.  
  208.         private void CalculateRaySpacing()
  209.         {
  210.             var shrinkedBounds = new Rect(bounds.X + SkinWidth, bounds.Y + SkinWidth, bounds.W - 2 * SkinWidth,
  211.                 bounds.H - 2 * SkinWidth);
  212.  
  213.             HorizontalRayCount = MathF.Clamp(HorizontalRayCount, 2, int.MaxValue);
  214.             VerticalRayCount = MathF.Clamp(VerticalRayCount, 2, int.MaxValue);
  215.  
  216.             horizontalRaySpacing = shrinkedBounds.H / (HorizontalRayCount - 1);
  217.             verticalRaySpacing = shrinkedBounds.W / (VerticalRayCount - 1);
  218.         }
  219.  
  220.         private void ClimbSlope(ref Vector2 velocity, float slopeAngle)
  221.         {
  222.             float moveDistance = MathF.Abs(velocity.X);
  223.             velocity.Y = -MathF.Sin(MathF.DegToRad(slopeAngle)) * moveDistance;
  224.             velocity.X = MathF.Cos(MathF.DegToRad(slopeAngle)) * moveDistance * MathF.Sign(velocity.X);
  225.  
  226.             collisions.below = true;
  227.             collisions.climbingSlope = true;
  228.             collisions.slopeAngle = slopeAngle;
  229.             //Log.Game.Write("Velocity is {0}, moveDistance is {1}, slopeAngle is {2}", velocity, moveDistance, slopeAngle);
  230.         }
  231.  
  232.         public struct CollisionInfo
  233.         {
  234.             public bool above, below, left, right;
  235.             public float slopeAngle;
  236.             public float slopeAngleOld;
  237.             public bool climbingSlope;
  238.  
  239.             public void Reset()
  240.             {
  241.                 above = below = left = right = false;
  242.                 slopeAngleOld = slopeAngle;
  243.             }
  244.         }
  245.  
  246.         private struct RayCastOrigins
  247.         {
  248.             public Vector2 topLeft, bottomLeft, topRight, bottomRight;
  249.         }
  250.  
  251.         private void SetCorrectColliderBounds()
  252.         {
  253.             switch (entityType)
  254.             {
  255.                 case EntityType.Player:
  256.                     SpriteBoundsOffset = new Vector2(14.4f, 10.12f);
  257.                     SpriteBoundsPositionOffset = new Vector2(7.4f, 10);
  258.                     break;
  259.                 case EntityType.GreenAppowl:
  260.                     SpriteBoundsOffset = new Vector2(14.4f, 17);
  261.                     SpriteBoundsPositionOffset = new Vector2(7.4f, 10);
  262.                     break;
  263.             }
  264.         }
  265.  
  266.         /// <summary>
  267.         /// Adjust collider position based on FacingDirection.
  268.         /// </summary>
  269.         private void AdjustColliderPosition()
  270.         {
  271.             switch (entityType)
  272.             {
  273.                 case EntityType.GreenAppowl:
  274.                     CircleShapeInfo _circleShapeInfo = (CircleShapeInfo)GameObj.GetComponent<RigidBody>().Shapes.First();
  275.                     if (facingDirection == Enemy.FacingDirection.Left)
  276.                     {
  277.                         if (_circleShapeInfo.Position.X < 0) //X is not negative
  278.                             _circleShapeInfo.Position = new Vector2(_circleShapeInfo.Position.X * -1, _circleShapeInfo.Position.Y);
  279.                     }
  280.                     else if (facingDirection == Enemy.FacingDirection.Right)
  281.                     {
  282.                         if (_circleShapeInfo.Position.X > 0)
  283.                             _circleShapeInfo.Position = new Vector2(_circleShapeInfo.Position.X * -1, _circleShapeInfo.Position.Y);
  284.                     }
  285.  
  286.                     break;
  287.  
  288.             }
  289.         }
  290.     }
  291. }
RAW Paste Data
Top