using System; using UnityEngine; using UnityEngine.Tilemaps; public abstract class Character : MonoBehaviour { [SerializeField] protected Animator _animator; [SerializeField] private float MovementSpeed = 1.5f; [SerializeField] protected GameObject _bonesSide; [SerializeField] protected GameObject _bonesBack; [SerializeField] protected GameObject _spawnPoint; [SerializeField] protected Tilemap _tileMap; [SerializeField] private LayerMask _mapLayer; private Rigidbody2D _body; private CapsuleCollider2D _capsuleCollider; protected bool _isOnBridge; protected bool _isOnLadder = false; protected bool _isFalling; protected bool _facingRight = true; protected bool isAllowVertical = true; protected bool isAllowRight = true; protected bool isAllowLeft = true; private Vector2 _cellSize; private void Start() { _body = GetComponent(); _capsuleCollider = GetComponent(); _cellSize = new Vector2(_tileMap.cellSize.x, _tileMap.cellSize.y); } protected void Spawn() { transform.position = _spawnPoint.transform.position; } protected void MoveTo(float inputHorizontal, float inputVertical) { var downBlock = GetMapElement(Vector2.down); if (downBlock == MapElementType.Water) { Death(); } _isOnBridge = downBlock == MapElementType.Bridge && !_isFalling; GetMapElement(Vector2.up); if (downBlock == MapElementType.Wall || _isOnLadder || _isOnBridge || downBlock == MapElementType.BreakableWall) { var leftCheck = GetMapElement(Vector2.left); var rightCheck = GetMapElement(Vector2.right); //print($"LeftCheck:{leftCheck} right:{rightCheck}"); isAllowLeft = !(leftCheck == MapElementType.Wall || leftCheck == MapElementType.BreakableWall); isAllowRight = !(rightCheck == MapElementType.Wall || rightCheck == MapElementType.BreakableWall); isAllowVertical = false; _isFalling = false; float h_movement = inputHorizontal; if (h_movement > 0 && !_facingRight || h_movement < 0 && _facingRight) { FlipCharacter(); } SetWalkingAnimation(h_movement != 0); ; _isOnLadder = GetMapElement(Vector2.zero) == MapElementType.Ladder || downBlock == MapElementType.Ladder; if (_isOnLadder) { float v_movement = inputVertical; isAllowVertical = true; SetClimbingAnimation(v_movement != 0); _body.velocity = new Vector2(h_movement * MovementSpeed, v_movement * MovementSpeed); } else { _body.velocity = new Vector2(h_movement * MovementSpeed, _body.velocity.y); } } else { _isFalling = true; } if (_isOnLadder || _isOnBridge) { _body.gravityScale = 0; } else { _body.gravityScale = 1; } if (_isFalling) { _body.velocity = new Vector2(0, _body.velocity.y); SetWalkingAnimation(false); if (downBlock == MapElementType.Ladder) { _body.velocity = Vector2.zero; _isOnLadder = true; } } } private void Death() { OnDeath(); } private MapElementType GetMapElement(Vector3 direction) { var bounds = _capsuleCollider.bounds.min; //var cell = _tileMap.WorldToCell(bounds + direction); //Vector2 cell2d = new Vector2(cell.x + 0.5f, cell.y + 0.3f); Vector2 cellSize = _cellSize; var playerBounds = _capsuleCollider.bounds.center; //DrawBounds(playerBounds, cellSize, Color.cyan); playerBounds = playerBounds + direction; var raycastHit = BoxCast(playerBounds, cellSize, 0f, Vector3.forward, .01f, _mapLayer); MapElementType returnValue; Color color = Color.red; if (raycastHit) { var mapElement = raycastHit.transform.GetComponent(); if (!mapElement.IsEnabled) { color = Color.white; returnValue = MapElementType.Empty; } else { returnValue = mapElement.ElementSO.ElementType; switch (returnValue) { case MapElementType.Wall: color = Color.green; break; case MapElementType.Ladder: color = Color.yellow; break; case MapElementType.BreakableWall: color = Color.magenta; break; } } } else { returnValue = MapElementType.Empty; } // DrawBounds(playerBounds, cellSize, color); return returnValue; } //private static void DrawBounds(Vector2 cell2d, Vector2 cellSize, Color color) //{ // Debug.DrawLine(cell2d, cell2d + new Vector2(cellSize.x, 0), color); // Debug.DrawLine(cell2d + new Vector2(cellSize.x, 0), cell2d + new Vector2(cellSize.x, cellSize.y), color); // Debug.DrawLine(cell2d, cell2d + new Vector2(0, cellSize.y), color); // Debug.DrawLine(cell2d + new Vector2(0, cellSize.y), cell2d + new Vector2(cellSize.x, cellSize.y), color); //} protected abstract void OnDeath(); protected abstract void SetWalkingAnimation(bool isWalking); protected abstract void SetClimbingAnimation(bool isClimbing); private void FlipCharacter() { Vector3 currentScale = gameObject.transform.localScale; currentScale.x *= -1; gameObject.transform.localScale = currentScale; _facingRight = !_facingRight; } static public RaycastHit2D BoxCast(Vector2 origen, Vector2 size, float angle, Vector2 direction, float distance, int mask) { RaycastHit2D hit = Physics2D.BoxCast(origen, size, angle, direction, distance, mask); //Setting up the points to draw the cast Vector2 p1, p2, p3, p4, p5, p6, p7, p8; float w = size.x * 0.5f; float h = size.y * 0.5f; p1 = new Vector2(-w, h); p2 = new Vector2(w, h); p3 = new Vector2(w, -h); p4 = new Vector2(-w, -h); Quaternion q = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1)); p1 = q * p1; p2 = q * p2; p3 = q * p3; p4 = q * p4; p1 += origen; p2 += origen; p3 += origen; p4 += origen; Vector2 realDistance = direction.normalized * distance; p5 = p1 + realDistance; p6 = p2 + realDistance; p7 = p3 + realDistance; p8 = p4 + realDistance; //Drawing the cast Color castColor = hit ? Color.red : Color.green; Debug.DrawLine(p1, p2, castColor); Debug.DrawLine(p2, p3, castColor); Debug.DrawLine(p3, p4, castColor); Debug.DrawLine(p4, p1, castColor); Debug.DrawLine(p5, p6, castColor); Debug.DrawLine(p6, p7, castColor); Debug.DrawLine(p7, p8, castColor); Debug.DrawLine(p8, p5, castColor); Debug.DrawLine(p1, p5, Color.grey); Debug.DrawLine(p2, p6, Color.grey); Debug.DrawLine(p3, p7, Color.grey); Debug.DrawLine(p4, p8, Color.grey); if (hit) { Debug.DrawLine(hit.point, hit.point + hit.normal.normalized * 0.2f, Color.yellow); } return hit; } }