Add player controller, state management, and input handling

- Implemented PlayerController.cs to manage player movement and actions.
- Created PlayerState.cs to track player lives, coins, and key status.
- Added CameraFollow.cs for smooth camera movement following the player.
- Developed Character.cs as an abstract class for character behavior.
- Introduced Enums.cs for defining TreasureType and MapElementType.
- Added IDoor interface for door interactions.
- Created InputActions.cs for handling player input actions.
- Implemented MainMenu.cs for basic menu functionality including play and exit options.
This commit is contained in:
2026-06-17 22:43:59 +03:00
parent dabd056e8b
commit 39e4e51866
70 changed files with 1807 additions and 99 deletions
+252
View File
@@ -0,0 +1,252 @@
using System.Linq;
using System;
using UnityEngine;
public abstract class Character : MonoBehaviour
{
[SerializeField]
protected Animator _animator;
[SerializeField]
private float _movementSpeed = 1.5f;
[SerializeField]
protected GameObject _bonesSide;
[SerializeField]
protected GameObject _bonesBack;
[SerializeField]
private LayerMask _mapLayer;
protected SpriteRenderer _spriteRenderer;
private Rigidbody2D _body;
private CapsuleCollider2D _capsuleCollider;
protected bool _isOnBridge;
private bool _isOnLadder = false;
protected bool _isFalling;
protected bool _facingRight = true;
protected bool isCanGoDown = false;
protected bool isCanClimbUp=false;
protected bool isAllowVertical = true;
protected bool isAllowRight = true;
protected bool isAllowLeft = true;
private Vector2 _cellSize;
public event EventHandler OnCharacterDeath;
private void Start()
{
_body = GetComponent<Rigidbody2D>();
_capsuleCollider = GetComponent<CapsuleCollider2D>();
_spriteRenderer = GetComponentInChildren<SpriteRenderer>();
_cellSize = new Vector2(0.6f, 1f);
}
protected void MoveTo(float inputHorizontal, float inputVertical)
{
var block = GetMapElement();
if (block?.ElementSO.ElementType == MapElementType.Water)
{
Death();
}
_isOnBridge = block?.ElementSO.ElementType == MapElementType.Bridge && !_isFalling;
if (block)
{
isAllowVertical = false;
_isFalling = false;
float h_movement = inputHorizontal;
if (h_movement > 0 && !_facingRight || h_movement < 0 && _facingRight)
{
FlipCharacter();
}
SetWalkingAnimation(h_movement != 0);
_isOnLadder = block.ElementSO.ElementType == MapElementType.Ladder;
if (_isOnLadder)
{
isCanClimbUp=CanClimbUp();
isCanGoDown = CanGoDown();
float ladderXCenterDistance = Mathf.Abs(transform.position.x - block.transform.position.x);
float v_movement = inputVertical;
isAllowVertical = (ladderXCenterDistance < 0.3f);
if(!isCanClimbUp&& v_movement>0)
{
v_movement=0;
}
if (isAllowVertical)
{
SetClimbingAnimation(v_movement != 0);
_body.linearVelocity = new Vector2(h_movement * _movementSpeed, v_movement * _movementSpeed);
}
else{
_body.linearVelocity = new Vector2(h_movement * _movementSpeed, _body.linearVelocity.y);
}
}
else
{
_body.linearVelocity = new Vector2(h_movement * _movementSpeed, _body.linearVelocity.y);
}
}
else
{
_isFalling = true;
_isOnLadder = false;
}
if (_isOnLadder || _isOnBridge)
{
_body.gravityScale = 0;
}
else
{
_body.gravityScale = 1;
}
if (_isFalling)
{
_body.linearVelocity = new Vector2(0, _body.linearVelocity.y);
SetWalkingAnimation(false);
if (block?.ElementSO.ElementType == MapElementType.Ladder)
{
_body.linearVelocity = Vector2.zero;
_isOnLadder = true;
}
}
}
protected void Death()
{
OnCharacterDeath?.Invoke(this,EventArgs.Empty);
}
private bool CanClimbUp()
{
var rayCastHit = Physics2D.Raycast(_capsuleCollider.bounds.center, Vector2.down, _capsuleCollider.size.y / 2,_mapLayer);
if(rayCastHit)
if(rayCastHit.collider.transform.GetComponent<MapElement>().ElementSO.ElementType==MapElementType.Ladder)
{
return true;
}
return false;
}
private bool CanGoDown()
{
var rayCastHit = Physics2D.RaycastAll(_capsuleCollider.bounds.center, Vector2.down, 0.5f, _mapLayer);
var isNoladder = rayCastHit.Any(x => x.collider.transform.GetComponent<MapElement>().ElementSO.ElementType != MapElementType.Ladder);
foreach (var hit in rayCastHit)
{
Debug.DrawLine(hit.point, hit.point + hit.normal.normalized * 0.2f, isNoladder? Color.blue: Color.red);
}
if (isNoladder)
{
return false;
}
return true;
}
private MapElement GetMapElement()
{
var collider = BoxCast(_capsuleCollider.bounds.center, _cellSize, 0f, Vector3.forward, .01f, _mapLayer);
Color color = Color.red;
MapElement mapElement = null;
if (collider.Length > 0)
{
var elements=collider.Select(x=>x.transform.GetComponent<MapElement>());
mapElement = elements.Where(x => x.ElementSO.ElementType == MapElementType.Ladder).FirstOrDefault();
if(mapElement == null)
{
mapElement = elements.First();
}
}
return mapElement;
}
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 Collider2D[] BoxCast(Vector2 origin, Vector2 size, float angle, Vector2 direction, float distance, int mask)
{
//RaycastHit2D hit = Physics2D.BoxCast(origin, size, angle, direction, distance, mask);
var collider = Physics2D.OverlapBoxAll(origin, size, angle, 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 += origin;
p2 += origin;
p3 += origin;
p4 += origin;
Vector2 realDistance = direction.normalized * distance;
p5 = p1 + realDistance;
p6 = p2 + realDistance;
p7 = p3 + realDistance;
p8 = p4 + realDistance;
//Drawing the cast
Color castColor = collider.Length > 0 ? 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);
//collider
//if (hit)
//{
// var color = hit.point.x > origin.x ? Color.yellow : Color.cyan;
// Debug.DrawLine(hit.point, hit.point + hit.normal.normalized * 0.2f, color);
//}
return collider;
}
}