This commit is contained in:
MrTorex committed 2026-02-18 20:13:09 +03:00
1 parent 0d5e6b6dec
commit c12d653cbc
647 files changed
+194585 -117

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c5ff52f5fb054d67bf29e3f537dcbb22
timeCreated: 1771430840
+18
View File
@@ -0,0 +1,18 @@
using Code.Input;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Code.DI
{
public class Bootstrapper : MonoBehaviour
{
[SerializeField] private InputActionAsset inputActionAsset;
private void Awake()
{
var container = new GameObject("DIContainer").AddComponent<DIContainer>();
container.Register<IInputService>(new InputService(inputActionAsset));
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 65859af4acde4a76adb00a20e8f85134
timeCreated: 1771430870
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Code.DI
{
public class DIContainer : MonoBehaviour
{
private readonly Dictionary<Type, object> _services = new();
private void Awake()
{
DontDestroyOnLoad(gameObject);
}
public void Register<T>(T service)
{
var type = typeof(T);
if (!_services.TryAdd(type, service))
{
Debug.LogWarning($"Service {type} is already registered.");
}
}
public T Resolve<T>()
{
var type = typeof(T);
if (_services.TryGetValue(type, out var service))
{
return (T)service;
}
throw new Exception($"Service {type} not found.");
}
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9af57c4618e949c0a0242ed71006116f
timeCreated: 1771430880
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: aff95e5ac5b74cc080a61d3f540cb997
timeCreated: 1771430846
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 84e1789d1c504243adf3e4622f43155d
timeCreated: 1771432728
@@ -0,0 +1,127 @@
using Code.DI;
using Code.Input;
using UnityEngine;
namespace Code.Gameplay.Camera
{
public class CameraController : MonoBehaviour
{
[Header("Settings")]
[SerializeField] private float rotationSpeed = 300f;
[SerializeField] private float rotationSharpness = 10f;
[SerializeField] private float followSharpness = 10f;
[SerializeField] private float minVerticalAngle = -90f;
[SerializeField] private float maxVerticalAngle = 90f;
[SerializeField] private float defaultVerticalAngle = 0f;
[Header("Target")]
[SerializeField] private Transform followTransform;
private UnityEngine.Camera _camera;
private Vector3 _currentFollowPosition;
private Vector3 _planarDirection;
private float _targetVerticalAngle;
private IInputService _inputService;
private void Awake()
{
_camera = GetComponent<UnityEngine.Camera>();
if (_camera == null)
{
Debug.LogError("CameraController requires a Camera component!");
enabled = false;
return;
}
Initialize();
}
private void Start()
{
_inputService = FindFirstObjectByType<DIContainer>().Resolve<IInputService>();
}
private void Initialize()
{
_targetVerticalAngle = Mathf.Clamp(defaultVerticalAngle, minVerticalAngle, maxVerticalAngle);
_planarDirection = followTransform != null ? followTransform.forward : Vector3.forward;
_currentFollowPosition = followTransform != null ? followTransform.position : Vector3.zero;
}
private void LateUpdate()
{
if (followTransform != null)
{
UpdateCamera(Time.deltaTime, GetLookInput());
}
}
private void UpdateCamera(float deltaTime, Vector3 lookInput)
{
// Handle rotation
Quaternion targetRotation = HandleRotation(deltaTime, lookInput);
// Handle position
HandlePosition(deltaTime, targetRotation);
}
private Quaternion HandleRotation(float deltaTime, Vector3 lookInput)
{
// Horizontal rotation
Quaternion horizontalRotation = Quaternion.Euler(Vector3.up * (lookInput.x * rotationSpeed));
_planarDirection = horizontalRotation * _planarDirection;
Quaternion planarRotation = Quaternion.LookRotation(_planarDirection, followTransform.up);
// Vertical rotation
_targetVerticalAngle -= lookInput.y * rotationSpeed;
_targetVerticalAngle = Mathf.Clamp(_targetVerticalAngle, minVerticalAngle, maxVerticalAngle);
Quaternion verticalRotation = Quaternion.Euler(_targetVerticalAngle, 0, 0);
// Combine and apply
Quaternion targetRotation = planarRotation * verticalRotation;
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, deltaTime * rotationSharpness);
return targetRotation;
}
private void HandlePosition(float deltaTime, Quaternion targetRotation)
{
_currentFollowPosition = Vector3.Lerp(
_currentFollowPosition,
followTransform.position,
1f - Mathf.Exp(-followSharpness * deltaTime)
);
transform.position = _currentFollowPosition;
}
private Vector3 GetLookInput()
{
// Получите здесь ваш инпут (например, из Input System)
// Это пример для стандартного инпута:
return _inputService.MoveInput;
}
// Публичные методы для получения данных
public Quaternion GetCameraRotation()
{
return transform.rotation;
}
public Vector3 GetPlanarDirection()
{
return _planarDirection;
}
// Метод для установки цели следования
public void SetFollowTransform(Transform target)
{
followTransform = target;
if (target != null)
{
_currentFollowPosition = target.position;
_planarDirection = target.forward;
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8f40748c010b4efda14731086ef26f0e
timeCreated: 1771432941
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c1d04e06f32d4a15a8b3ec6da754bc0b
timeCreated: 1771431576
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0e4799047a8c484abd6ff0e92a5ff093
timeCreated: 1771431588
@@ -0,0 +1,19 @@
using UnityEngine;
namespace Code.Gameplay.Character.Controller
{
public class AirMovementSystem
{
private readonly Vector3 _gravity;
public AirMovementSystem(Vector3 gravity)
{
_gravity = gravity;
}
public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{
currentVelocity += _gravity * deltaTime;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 60d5b036992c463590cada0327f0e4d4
timeCreated: 1771431829
@@ -0,0 +1,46 @@
using UnityEngine;
using KinematicCharacterController;
namespace Code.Gameplay.Character.Controller
{
public class GroundMovementSystem
{
private readonly float _maxStableMoveSpeed;
private readonly float _sprintMoveSpeed;
private readonly float _stableMovementSharpness;
public GroundMovementSystem(float maxStableMoveSpeed, float sprintMoveSpeed, float stableMovementSharpness)
{
_maxStableMoveSpeed = maxStableMoveSpeed;
_sprintMoveSpeed = sprintMoveSpeed;
_stableMovementSharpness = stableMovementSharpness;
}
public void UpdateVelocity(
ref Vector3 currentVelocity,
CharacterInputHandler inputHandler,
KinematicCharacterMotor motor,
float deltaTime)
{
var currentVelocityMagnitude = currentVelocity.magnitude;
var effectiveGroundNormal = motor.GroundingStatus.GroundNormal;
currentVelocity = motor.GetDirectionTangentToSurface(currentVelocity, effectiveGroundNormal) *
currentVelocityMagnitude;
var inputRight = Vector3.Cross(inputHandler.MoveInputVector, motor.CharacterUp);
var reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized *
inputHandler.MoveInputVector.magnitude;
var targetSpeed = inputHandler.IsSprinting ? _sprintMoveSpeed : _maxStableMoveSpeed;
var targetMovementVelocity = reorientedInput * targetSpeed;
currentVelocity = Vector3.Lerp(
currentVelocity,
targetMovementVelocity,
1f - Mathf.Exp(-_stableMovementSharpness * deltaTime)
);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 65cbfbe68735468997f05a5e80b6910e
timeCreated: 1771431851
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0dce37a9def247adb97d183cf312fcde
timeCreated: 1771431596
@@ -0,0 +1,63 @@
using UnityEngine;
using Code.Gameplay.Character.Core;
using KinematicCharacterController;
namespace Code.Gameplay.Character.Controller
{
public class CharacterInputHandler
{
private readonly float _sprintAngleThresholdCos;
public Vector3 MoveInputVector { get; set; }
public Vector3 LookInputVector { get; set; }
public bool IsSprinting { get; set; }
public Quaternion FirstPersonCameraRotation { get; set; }
public bool ShouldApplyCameraRotation { get; private set; }
public CharacterInputHandler(float sprintAngleThreshold)
{
_sprintAngleThresholdCos = Mathf.Cos(Mathf.Deg2Rad * sprintAngleThreshold);
}
public void ProcessInputs(ref CharacterInputs inputs, KinematicCharacterMotor motor)
{
IsSprinting = inputs.SprintPressed && inputs.MoveAxisForward > _sprintAngleThresholdCos; // Спринт только при движении на заданный в конфиге угол
var moveInputVector =
Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0, inputs.MoveAxisForward), 1f);
HandleFirstPersonInputs(ref inputs, moveInputVector, motor);
}
private void HandleFirstPersonInputs(ref CharacterInputs inputs, Vector3 moveInputVector, KinematicCharacterMotor motor)
{
FirstPersonCameraRotation = ExtractHorizontalRotation(inputs.CameraRotation, motor);
ShouldApplyCameraRotation = true;
var cameraPlanarDirection = inputs.CameraPlanarDirection;
var cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, motor.CharacterUp);
MoveInputVector = cameraPlanarRotation * moveInputVector;
LookInputVector = cameraPlanarDirection;
}
private static Quaternion ExtractHorizontalRotation(Quaternion cameraRotation, KinematicCharacterMotor motor)
{
var cameraForward = cameraRotation * Vector3.forward;
var horizontalForward = Vector3.ProjectOnPlane(cameraForward, Vector3.up).normalized;
if (horizontalForward.sqrMagnitude < 0.01f)
{
horizontalForward = motor.CharacterForward;
}
return Quaternion.LookRotation(horizontalForward, motor.CharacterUp);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7cbc2ef1c7c14e1788d9633d4b9267c5
timeCreated: 1771431877
@@ -0,0 +1,15 @@
using UnityEngine;
namespace Code.Gameplay.Character.Core
{
public struct CharacterInputs
{
public float MoveAxisForward;
public float MoveAxisRight;
public Quaternion CameraRotation;
public Vector3 CameraPlanarDirection;
public bool JumpPressed;
public bool SprintPressed;
public bool SlidePressed;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f0b3699e82824e42832f381246741e90
timeCreated: 1771431755
@@ -0,0 +1,42 @@
using Code.Gameplay.Camera;
using Code.Gameplay.Character.Controller;
using Code.Input;
using UnityEngine;
namespace Code.Gameplay.Character.Core
{
public class CharacterProvider : MonoBehaviour
{
[SerializeField] private CustomCharacterController customCharacterController;
public CustomCharacterController CustomCharacterController => customCharacterController;
[SerializeField] private Transform cameraFollowPoint;
public Transform GetFollowTransform() => cameraFollowPoint;
private IInputService _inputService;
public void Teleport(Vector3 position, Quaternion rotation)
{
customCharacterController.SetPosition(position);
customCharacterController.SetRotation(rotation);
}
private void HandleCharacterInput()
{
var inputs = new CharacterInputs();
var moveInput = _inputService.MoveInput;
inputs.MoveAxisForward = moveInput.y;
inputs.MoveAxisRight = moveInput.x;
inputs.SprintPressed = _inputService.SprintHeld;
inputs.CameraRotation = FindFirstObjectByType<CameraController>().GetCameraRotation();
inputs.CameraPlanarDirection = FindFirstObjectByType<CameraController>().GetPlanarDirection();
customCharacterController.SetInputs(ref inputs);
}
private void Update()
{
HandleCharacterInput();
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0073ba8d33504841b4ec7ef63b747249
timeCreated: 1771431716
@@ -0,0 +1,78 @@
using Code.Gameplay.Character.Core;
using KinematicCharacterController;
using UnityEngine;
namespace Code.Gameplay.Character.Controller
{
public class CustomCharacterController : MonoBehaviour, ICharacterController
{
[SerializeField] private KinematicCharacterMotor motor;
[SerializeField] private Transform characterTransform;
private CharacterInputHandler _inputHandler;
private GroundMovementSystem _groundMovement;
private AirMovementSystem _airMovement;
[SerializeField] private float sprintAngleThreshold;
[SerializeField] private float maxStableMoveSpeed;
[SerializeField] private float sprintMoveSpeed;
[SerializeField] private float stableMovementSharpness;
[SerializeField] private Vector3 gravity;
public void SetPosition(Vector3 position) => motor.SetPosition(position);
public void SetRotation(Quaternion rotation) => motor.SetRotation(rotation);
private void Construct()
{
_inputHandler = new CharacterInputHandler(
sprintAngleThreshold
);
_groundMovement = new GroundMovementSystem(
maxStableMoveSpeed,
sprintMoveSpeed,
stableMovementSharpness
);
_airMovement = new AirMovementSystem(
gravity
);
motor.CharacterController = this;
_inputHandler.FirstPersonCameraRotation = motor.Transform.rotation;
}
public void SetInputs(ref CharacterInputs inputs)
{
_inputHandler.ProcessInputs(ref inputs, motor);
}
public void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
{
currentRotation = _inputHandler.FirstPersonCameraRotation;
}
public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{
var wasGrounded = motor.GroundingStatus.IsStableOnGround;
if (wasGrounded)
{
_groundMovement?.UpdateVelocity(ref currentVelocity, _inputHandler, motor, deltaTime);
}
else
{
_airMovement?.UpdateVelocity(ref currentVelocity, deltaTime);
}
}
public void BeforeCharacterUpdate(float deltaTime) { }
public void PostGroundingUpdate(float deltaTime) { }
public void AfterCharacterUpdate(float deltaTime) { }
public bool IsColliderValidForCollisions(Collider coll) => true;
public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { }
public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport) { }
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) { }
public void OnDiscreteCollisionDetected(Collider hitCollider) { }
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3ab3cb1f5b954513a34e58dd8a96d027
timeCreated: 1771431901
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6e7634bb316042e8a70ab984454b8d23
timeCreated: 1771430852
+9
View File
@@ -0,0 +1,9 @@
namespace Code.Input
{
public enum ActionMapping
{
MainMenu,
Gameplay,
UI
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 79cf117afe77443992636e32b29782ec
timeCreated: 1771430942
+23
View File
@@ -0,0 +1,23 @@
using System;
using UnityEngine;
using UnityEngine.InputSystem;
namespace Code.Input
{
public interface IInputService
{
void EnableMap(ActionMapping actionMap);
void DisableMap(ActionMapping actionMap);
Vector2 MainMenuParalax { get; }
Vector2 LookInput { get; }
Vector2 MoveInput { get; }
bool JumpPressed { get; }
bool SprintHeld { get; }
void DebugBindAction(int mapId, int actionId, Action<InputAction.CallbackContext> action);
void DebugUnbindAction(int mapId, int actionId, Action<InputAction.CallbackContext> action);
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c8acf7d28cc74a7fb5fca2a6ffb2dee3
timeCreated: 1771430932
+95
View File
@@ -0,0 +1,95 @@
using UnityEngine;
using UnityEngine.InputSystem;
namespace Code.Input
{
public class InputService : IInputService
{
private readonly InputActionAsset _inputActionAsset;
private InputAction _lmbInteractAction;
public Vector2 MainMenuParalax { get; private set; }
public Vector2 LookInput { get; private set; }
public Vector2 MoveInput { get; private set; }
public bool JumpPressed { get; private set; }
public bool SprintHeld { get; private set; }
public bool AttackPressed { get; private set; }
public InputService(InputActionAsset inputActionAsset)
{
_inputActionAsset = inputActionAsset;
SetupInputCallbacks();
}
private void SetupInputCallbacks()
{
SetupMainMenuInputCallbacks();
SetupGameplayInputCallbacks();
}
private void SetupGameplayInputCallbacks()
{
var map = _inputActionAsset.actionMaps[(int)ActionMapping.Gameplay];
BindVector2(map, "Move", v => MoveInput = v);
BindButton(map, "Jump", v => JumpPressed = v);
BindButton(map, "Sprint", v => SprintHeld = v);
BindButton(map, "Attack", v => AttackPressed = v);
}
private void SetupMainMenuInputCallbacks()
{
var map = _inputActionAsset.actionMaps[(int)ActionMapping.MainMenu];
BindVector2(map, "Parallax", v => MainMenuParalax = v);
}
private void BindButton(InputActionMap map, string actionName, System.Action<bool> setter)
{
var action = map.FindAction(actionName);
if (action == null)
return;
action.performed += _ => setter(true);
action.canceled += _ => setter(false);
}
private void BindVector2(InputActionMap map, string actionName, System.Action<Vector2> setter)
{
var action = map.FindAction(actionName);
if (action == null)
return;
action.performed += ctx => setter(ctx.ReadValue<Vector2>());
action.canceled += _ => setter(Vector2.zero);
}
private void BindAxis(InputActionMap map, string actionName, System.Action<float> setter)
{
var action = map.FindAction(actionName);
if (action == null)
return;
action.performed += ctx => setter(ctx.ReadValue<float>());
action.canceled += _ => setter(0f);
}
public void EnableMap(ActionMapping actionMap)
{
_inputActionAsset.actionMaps[(int)actionMap].Enable();
}
public void DisableMap(ActionMapping actionMap)
{
_inputActionAsset.actionMaps[(int)actionMap].Disable();
}
public void DebugBindAction(int mapId, int actionId, System.Action<InputAction.CallbackContext> action) =>
_inputActionAsset.actionMaps[mapId].actions[actionId].performed += action;
public void DebugUnbindAction(int mapId, int actionId, System.Action<InputAction.CallbackContext> action) =>
_inputActionAsset.actionMaps[mapId].actions[actionId].performed -= action;
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7a985f6fee1a476280bc4e54af892714
timeCreated: 1771430923
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6c532ef1913b4c80be438be2b66525e3
timeCreated: 1771430858