Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Linq;
- using Duality;
- using Duality.Components.Physics;
- using Duality.Components.Renderers;
- using Enemy;
- using Player;
- namespace Behavior
- {
- /// <summary>
- /// Does a majority of the calculations for the platformer movement system.
- /// </summary>
- public class Controller2D : Component, ICmpInitializable, ICmpUpdatable
- {
- public enum EntityType
- {
- Player,
- GreenAppowl,
- RedAppowl,
- Grapeshooter,
- Dragonfruit
- }
- public CollisionInfo Collisions
- {
- get { return collisions; }
- }
- public EntityType entityType { get; set; }
- public Vector2 SpriteBoundsOffset { get; set; } //new Vector2(14.4f, 10.12f); //Bounds calculations get this value subtracted from them.
- public Vector2 SpriteBoundsPositionOffset { get; set; } // new Vector2(7.4f, 10);
- public CollisionCategory CollidesWith { get; set; }
- private Rect bounds;
- private CollisionInfo collisions;
- private float horizontalRaySpacing;
- private RayCastOrigins raycastOrigins;
- private float verticalRaySpacing;
- private float SkinWidth { get; } = 0.015f;
- private int HorizontalRayCount { get; set; } = 3;
- private int VerticalRayCount { get; set; } = 3;
- private Enemy.FacingDirection facingDirection;
- private RigidBody rigidBody;
- private PlayerController playerController; //TODO add monster control support
- private EnemyController enemyController;
- private float maxClimbAngle = 60;
- public void OnInit(InitContext context)
- {
- CalculateBounds();
- CalculateRaySpacing();
- SetCorrectColliderBounds();
- rigidBody = GameObj.GetComponent<RigidBody>();
- if (GameObj.GetComponent<PlayerController>() != null)
- playerController = GameObj.GetComponent<PlayerController>();
- else
- enemyController = GameObj.GetComponent<EnemyController>();
- }
- public void OnShutdown(ShutdownContext context)
- {
- }
- public void OnUpdate()
- {
- if (entityType != EntityType.Player)
- {
- facingDirection = GameObj.GetComponent<EnemyController>().FacingDirection;
- }
- AdjustColliderPosition();
- }
- public void Move(Vector2 velocity)
- {
- CalculateBounds();
- CalculateRayCastOrigins();
- collisions.Reset();
- if (velocity.X != 0.0)
- HorizontalCollisions(ref velocity);
- if (velocity.Y != 0.0)
- VerticalCollisions(ref velocity);
- GameObj.Transform.MoveByAbs(velocity);
- }
- private void HorizontalCollisions(ref Vector2 velocity)
- {
- var directionX = MathF.Sign(velocity.X);
- var rayLength = MathF.Abs(velocity.X) + SkinWidth;
- collisions.climbingSlope = false;
- for (var i = 0; i < HorizontalRayCount; i++)
- {
- var rayOrigin = directionX == -1 ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
- rayOrigin -= Vector2.UnitY * (horizontalRaySpacing * i);
- if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor)
- VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, directionX * rayLength, 0);
- RayCastCallback raycastCallback = data =>
- {
- if ((data.Body.CollisionCategory & CollidesWith) != 0)
- return 1.0f;
- else
- return -1.0f;
- };
- RayCastData rayCastData; //If statement's data is outputted to here.
- if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitX * directionX * rayLength, raycastCallback,
- out rayCastData))
- {
- float _slopeAngleRad = Vector2.AngleBetween(rayCastData.Normal, new Vector2(0, 1));
- float _slopeAngleDeg = MathF.Abs(MathF.RadToDeg(_slopeAngleRad) - 180); //Convert to degrees, account for flat angle, get positive value.
- if (i == 0 && _slopeAngleDeg <= maxClimbAngle)
- {
- ClimbSlope(ref velocity, _slopeAngleDeg);
- }
- else
- {
- var distance = (rayOrigin - rayCastData.Pos).Length;
- velocity.X = (distance - SkinWidth) * directionX;
- rayLength = distance;
- }
- collisions.right = directionX == 1;
- collisions.left = directionX == -1;
- }
- }
- }
- private void VerticalCollisions(ref Vector2 velocity)
- {
- var directionY = MathF.Sign(velocity.Y);
- var rayLength = MathF.Abs(velocity.Y) + SkinWidth;
- for (var i = 0; i < VerticalRayCount; i++)
- {
- var rayOrigin = directionY == -1 ? raycastOrigins.topLeft : raycastOrigins.bottomLeft;
- rayOrigin += Vector2.UnitX * (verticalRaySpacing * i + velocity.X);
- if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor)
- VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, 0, directionY * rayLength);
- RayCastCallback raycastCallback = data =>
- {
- if ((data.Body.CollisionCategory & CollidesWith) != 0)
- return 1.0f;
- else
- return -1.0f;
- };
- RayCastData rayCastData;
- if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitY * directionY * rayLength, raycastCallback,
- out rayCastData))
- {
- var distance = (rayOrigin - rayCastData.Pos).Length;
- velocity.Y = (distance - SkinWidth) * directionY;
- rayLength = distance;
- collisions.below = directionY == 1;
- collisions.above = directionY == -1;
- }
- }
- }
- private void CalculateBounds()
- {
- var spriteRenderer = GameObj.GetComponent<SpriteRenderer>();
- var animSpriteRenderer = GameObj.GetComponent<AnimSpriteRenderer>();
- if (spriteRenderer != null)
- {
- bounds = new Rect(
- GameObj.Transform.Pos.X + spriteRenderer.Rect.X + SpriteBoundsPositionOffset.X,
- GameObj.Transform.Pos.Y + spriteRenderer.Rect.Y + SpriteBoundsPositionOffset.Y,
- spriteRenderer.Rect.W - SpriteBoundsOffset.X,
- spriteRenderer.Rect.H - SpriteBoundsOffset.Y);
- }
- else if (animSpriteRenderer != null)
- {
- bounds = new Rect(
- GameObj.Transform.Pos.X + animSpriteRenderer.Rect.X,
- GameObj.Transform.Pos.Y + animSpriteRenderer.Rect.Y,
- animSpriteRenderer.Rect.W,
- animSpriteRenderer.Rect.H);
- }
- else
- {
- Log.Game.WriteError("A spriterenderer or animspriterenderer has to be attached!");
- bounds = new Rect();
- }
- }
- private void CalculateRayCastOrigins()
- {
- var shrinkedBounds = new Rect(bounds.X + SkinWidth, bounds.Y + SkinWidth, bounds.W - 2 * SkinWidth,
- bounds.H - 2 * SkinWidth);
- raycastOrigins.topLeft = shrinkedBounds.TopLeft;
- raycastOrigins.bottomLeft = shrinkedBounds.BottomLeft;
- raycastOrigins.topRight = shrinkedBounds.TopRight;
- raycastOrigins.bottomRight = shrinkedBounds.BottomRight;
- }
- private void CalculateRaySpacing()
- {
- var shrinkedBounds = new Rect(bounds.X + SkinWidth, bounds.Y + SkinWidth, bounds.W - 2 * SkinWidth,
- bounds.H - 2 * SkinWidth);
- HorizontalRayCount = MathF.Clamp(HorizontalRayCount, 2, int.MaxValue);
- VerticalRayCount = MathF.Clamp(VerticalRayCount, 2, int.MaxValue);
- horizontalRaySpacing = shrinkedBounds.H / (HorizontalRayCount - 1);
- verticalRaySpacing = shrinkedBounds.W / (VerticalRayCount - 1);
- }
- private void ClimbSlope(ref Vector2 velocity, float slopeAngle)
- {
- float moveDistance = MathF.Abs(velocity.X);
- velocity.Y = -MathF.Sin(MathF.DegToRad(slopeAngle)) * moveDistance;
- velocity.X = MathF.Cos(MathF.DegToRad(slopeAngle)) * moveDistance * MathF.Sign(velocity.X);
- collisions.below = true;
- collisions.climbingSlope = true;
- collisions.slopeAngle = slopeAngle;
- //Log.Game.Write("Velocity is {0}, moveDistance is {1}, slopeAngle is {2}", velocity, moveDistance, slopeAngle);
- }
- public struct CollisionInfo
- {
- public bool above, below, left, right;
- public float slopeAngle;
- public float slopeAngleOld;
- public bool climbingSlope;
- public void Reset()
- {
- above = below = left = right = false;
- slopeAngleOld = slopeAngle;
- }
- }
- private struct RayCastOrigins
- {
- public Vector2 topLeft, bottomLeft, topRight, bottomRight;
- }
- private void SetCorrectColliderBounds()
- {
- switch (entityType)
- {
- case EntityType.Player:
- SpriteBoundsOffset = new Vector2(14.4f, 10.12f);
- SpriteBoundsPositionOffset = new Vector2(7.4f, 10);
- break;
- case EntityType.GreenAppowl:
- SpriteBoundsOffset = new Vector2(14.4f, 17);
- SpriteBoundsPositionOffset = new Vector2(7.4f, 10);
- break;
- }
- }
- /// <summary>
- /// Adjust collider position based on FacingDirection.
- /// </summary>
- private void AdjustColliderPosition()
- {
- switch (entityType)
- {
- case EntityType.GreenAppowl:
- CircleShapeInfo _circleShapeInfo = (CircleShapeInfo)GameObj.GetComponent<RigidBody>().Shapes.First();
- if (facingDirection == Enemy.FacingDirection.Left)
- {
- if (_circleShapeInfo.Position.X < 0) //X is not negative
- _circleShapeInfo.Position = new Vector2(_circleShapeInfo.Position.X * -1, _circleShapeInfo.Position.Y);
- }
- else if (facingDirection == Enemy.FacingDirection.Right)
- {
- if (_circleShapeInfo.Position.X > 0)
- _circleShapeInfo.Position = new Vector2(_circleShapeInfo.Position.X * -1, _circleShapeInfo.Position.Y);
- }
- break;
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment