chunk 1: core gameplay scripts scenes runtime assets

This commit is contained in:
2026-04-06 11:02:34 +03:00
parent fa0388bc79
commit 0d11a097d8
703 changed files with 2292651 additions and 0 deletions

View File

@@ -0,0 +1,182 @@
using UnityEngine;
using Cinemachine;
using System.Collections;
/// <summary>
/// Automatically configures Cinemachine FreeLook camera targets on scene start.
/// Correctly separates Follow (character root) from LookAt (head bone)
/// to prevent orbit collapse and camera looking at the sky.
/// </summary>
public class AutoAddCinemachineCamera : MonoBehaviour
{
[TagField]
public string Tag = string.Empty;
void Start()
{
var vcam = GetComponent<CinemachineFreeLook>();
if (vcam != null && Tag.Length > 0)
{
bool isCashSystemMode = SelectionOptions.Instance != null && SelectionOptions.Instance.isCashSystemSelected;
if (isCashSystemMode)
{
// In Cash System mode, characters spawn after a delay
StartCoroutine(FindPlayerControlledTargetDelayed(vcam, 1.0f));
}
else
{
// Normal mode - find immediately
var targets = GameObject.FindGameObjectsWithTag(Tag);
if (targets.Length > 0)
{
SetCameraTargets(vcam, targets[0]);
}
}
}
}
private IEnumerator FindPlayerControlledTargetDelayed(CinemachineFreeLook vcam, float delay)
{
yield return new WaitForSeconds(delay);
// If CameraManager already set targets, don't override
if (CameraManager.Instance != null && CameraManager.Instance.GetCurrentTarget() != null)
{
Debug.Log("[AutoAddCinemachineCamera] CameraManager already handling camera — skipping.");
yield break;
}
var targets = GameObject.FindGameObjectsWithTag(Tag);
// Find the character with IsPlayerControlled = true
foreach (var target in targets)
{
TeamMember teamMember = target.GetComponent<TeamMember>();
if (teamMember != null && teamMember.IsPlayerControlled)
{
// Route through CameraManager if available
if (CameraManager.Instance != null)
{
CameraManager.Instance.SetTarget(teamMember);
Debug.Log($"[AutoAddCinemachineCamera] Routed to CameraManager for {target.name}");
}
else
{
SetCameraTargets(vcam, target);
Debug.Log($"[AutoAddCinemachineCamera] Set targets directly for {target.name}");
}
yield break;
}
}
// Fallback if no TeamMember found
if (targets.Length > 0)
{
Debug.LogWarning("[AutoAddCinemachineCamera] No player-controlled character found, using first target");
SetCameraTargets(vcam, targets[0]);
}
}
/// <summary>
/// Set Follow to character ROOT (orbit center) and LookAt to HEAD (aim point).
/// This is the correct configuration for CinemachineFreeLook.
/// </summary>
private void SetCameraTargets(CinemachineFreeLook vcam, GameObject character)
{
// Follow = character root (stable orbit center at ground level)
Transform followTarget = character.transform;
// LookAt = head bone (camera aims at upper body)
Transform lookAtTarget = FindHeadTransform(character) ?? character.transform;
vcam.Follow = followTarget;
vcam.LookAt = lookAtTarget;
// CRITICAL: Start at middle rig (0.5), not bottom (0)
// Without this, camera defaults to looking UP at the character from below
vcam.m_YAxis.Value = 0.5f;
// Force Cinemachine to recalculate from scratch (forget cached underground position)
vcam.PreviousStateIsValid = false;
// Clear input axis names — CinemachineCameraInput handles all input
vcam.m_XAxis.m_InputAxisName = "";
vcam.m_YAxis.m_InputAxisName = "";
// Set professional orbit heights (consistent with CameraManager)
vcam.m_Orbits = new CinemachineFreeLook.Orbit[] {
new CinemachineFreeLook.Orbit(4.5f, 5f), // TopRig
new CinemachineFreeLook.Orbit(2.5f, 6f), // MiddleRig
new CinemachineFreeLook.Orbit(0.5f, 5f), // BottomRig
};
// Configure Composer aim on each rig
for (int i = 0; i < 3; i++)
{
var rig = vcam.GetRig(i);
if (rig == null) continue;
var composer = rig.GetCinemachineComponent<CinemachineComposer>();
if (composer != null)
{
composer.m_ScreenX = 0.5f;
composer.m_ScreenY = 0.4f;
composer.m_DeadZoneWidth = 0.1f;
composer.m_DeadZoneHeight = 0.1f;
composer.m_SoftZoneWidth = 0.8f;
composer.m_SoftZoneHeight = 0.8f;
}
}
// Add CinemachineCollider to prevent camera clipping below terrain
EnsureCinemachineCollider(vcam);
Debug.Log($"[AutoAddCinemachineCamera] Follow={followTarget.name}, LookAt={lookAtTarget.name}, YAxis=0.5");
}
/// <summary>
/// Adds a CinemachineCollider extension so the camera stays above terrain
/// and doesn't clip through the environment after changing levels.
/// </summary>
private void EnsureCinemachineCollider(CinemachineFreeLook vcam)
{
var colliderExt = vcam.GetComponent<CinemachineCollider>();
if (colliderExt == null)
{
colliderExt = vcam.gameObject.AddComponent<CinemachineCollider>();
}
colliderExt.m_Strategy = CinemachineCollider.ResolutionStrategy.PullCameraForward;
colliderExt.m_CollideAgainst = LayerMask.GetMask("Default", "Ground");
colliderExt.m_IgnoreTag = "Player";
colliderExt.m_CameraRadius = 0.2f;
colliderExt.m_Damping = 0f;
colliderExt.m_MinimumDistanceFromTarget = 1f;
Debug.Log("[AutoAddCinemachineCamera] CinemachineCollider extension configured for terrain avoidance");
}
private Transform FindHeadTransform(GameObject character)
{
string[] headNames = { "Head", "head", "Bip001 Head", "mixamorig:Head", "Bip01 Head" };
foreach (string headName in headNames)
{
Transform head = FindChildRecursive(character.transform, headName);
if (head != null) return head;
}
return null;
}
private Transform FindChildRecursive(Transform parent, string name)
{
foreach (Transform child in parent)
{
if (child.name == name) return child;
Transform found = FindChildRecursive(child, name);
if (found != null) return found;
}
return null;
}
}