Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16,026 changes: 16,026 additions & 0 deletions Assets/Scenes/Location.unity

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Assets/Scenes/Location.unity.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added Assets/Scripts/.DS_Store
Binary file not shown.
8 changes: 8 additions & 0 deletions Assets/Scripts/Environment.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Assets/Scripts/Ghost.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Assets/Scripts/Interactions.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added Assets/Scripts/Interactions/.DS_Store
Binary file not shown.
96 changes: 96 additions & 0 deletions Assets/Scripts/Interactions/DoorInteractable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using UnityEngine;

namespace Game.Interaction
{
/// <summary>
/// Простая дверь: открывается/закрывается при взаимодействии.
///
/// Важно: дверь "анимируется" через поворот pivot вокруг локальной оси Y.
/// pivot обычно ставят в месте петель двери, чтобы она открывалась реалистично.
/// Если pivot не задан — используем сам объект двери.
/// </summary>
public class DoorInteractable : MonoBehaviour, IInteractable
{
/// <summary>
/// Pivot = объект, который мы вращаем.
/// Часто это "родитель" двери, стоящий в месте петель.
/// </summary>
[SerializeField] private Transform pivot;

/// <summary>
/// На сколько градусов повернуть дверь при открытии.
/// 90 = классика.
/// </summary>
[SerializeField] private float openAngle = 90f;

/// <summary>
/// Скорость плавного поворота (чем больше — тем быстрее).
/// </summary>
[SerializeField] private float speed = 6f;

/// <summary>
/// Текущее состояние двери.
/// false = закрыта
/// true = открыта
/// </summary>
private bool _open;

/// <summary>
/// Запоминаем, как дверь выглядит в закрытом состоянии (поворот).
/// </summary>
private Quaternion _closedRot;

/// <summary>
/// Запоминаем поворот, когда дверь открыта.
/// </summary>
private Quaternion _openRot;

private void Awake()
{
// Если pivot не задан — вращаем сам объект (не идеально, но работает)
if (!pivot) pivot = transform;

// Запоминаем исходный поворот как "закрыто"
_closedRot = pivot.localRotation;

// Рассчитываем "открыто": это "закрыто" + поворот по Y на openAngle
_openRot = _closedRot * Quaternion.Euler(0f, openAngle, 0f);
}

private void Update()
{
// В Update мы НЕ переключаем состояние.
// Мы только плавно двигаем текущий поворот к нужному.
// Это дает "анимацию" открывания/закрывания.

// Куда хотим прийти сейчас:
var target = _open ? _openRot : _closedRot;

// Плавно интерполируем (Slerp) текущий поворот к target
pivot.localRotation = Quaternion.Slerp(
pivot.localRotation,
target,
Time.deltaTime * speed
);
}

/// <summary>
/// Текст подсказки.
/// </summary>
public string GetPrompt() => _open ? "Close" : "Open";

/// <summary>
/// Дверь без замка — всегда можно.
/// </summary>
public bool CanInteract(GameObject interactor) => true;

/// <summary>
/// Нажали E -> меняем состояние.
/// Дальше Update сам плавно повернет pivot.
/// </summary>
public void Interact(GameObject interactor)
{
_open = !_open; // переключаем
}
}
}
2 changes: 2 additions & 0 deletions Assets/Scripts/Interactions/DoorInteractable.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

140 changes: 140 additions & 0 deletions Assets/Scripts/Interactions/HidingSpotInteractable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using System.Collections.Generic;
using UnityEngine;

namespace Game.Interaction
{
public class HidingSpotInteractable : MonoBehaviour, IInteractable
{
private static readonly List<HidingSpotInteractable> Spots = new List<HidingSpotInteractable>();

[Header("Points")]
[SerializeField] private Transform hidePoint;
[SerializeField] private Transform exitPoint;

[Header("Rules")]
[SerializeField] private float activationDistance = 0.7f;
[SerializeField] private bool requiresCrouch;
[SerializeField, Range(0f, 1f)] private float inspectionChance = 1f;

private PlayerHiding occupant;

public static IReadOnlyList<HidingSpotInteractable> AllSpots => Spots;
public bool IsOccupied => occupant != null;
public float ActivationDistance => activationDistance;

private void OnEnable()
{
if (!Spots.Contains(this))
Spots.Add(this);
}

private void OnDisable()
{
Spots.Remove(this);

if (occupant != null)
{
PlayerHiding oldOccupant = occupant;
occupant = null;
oldOccupant.ForceExitFromHiding();
}
}

public string GetPrompt()
{
if (occupant != null)
return "Exit hiding";

return "Hide";
}

public bool CanInteract(GameObject interactor)
{
PlayerHiding playerHiding = interactor.GetComponent<PlayerHiding>();

if (playerHiding == null)
playerHiding = interactor.GetComponentInParent<PlayerHiding>();

if (playerHiding == null)
return false;

if (playerHiding.IsHidden)
return playerHiding.CurrentSpot == this;

return CanPlayerEnter(playerHiding);
}

public void Interact(GameObject interactor)
{
PlayerHiding playerHiding = interactor.GetComponent<PlayerHiding>();

if (playerHiding == null)
playerHiding = interactor.GetComponentInParent<PlayerHiding>();

if (playerHiding == null)
return;

playerHiding.ToggleHide(this);
}

public bool CanPlayerEnter(PlayerHiding playerHiding)
{
if (playerHiding == null)
return false;

if (IsOccupied)
return false;

float distance = Vector3.Distance(playerHiding.transform.position, transform.position);
if (distance > activationDistance)
return false;

if (requiresCrouch && !playerHiding.IsCrouching())
return false;

return true;
}

public void SetOccupant(PlayerHiding playerHiding)
{
occupant = playerHiding;
}

public void ClearOccupant(PlayerHiding playerHiding)
{
if (occupant == playerHiding)
occupant = null;
}

public bool ShouldBeInspected()
{
return Random.value <= inspectionChance;
}

public Vector3 GetHidePosition()
{
return hidePoint != null ? hidePoint.position : transform.position;
}

public Quaternion GetHideRotation()
{
return hidePoint != null ? hidePoint.rotation : transform.rotation;
}

public Vector3 GetExitPosition()
{
if (exitPoint != null)
return exitPoint.position;

return transform.position + transform.forward;
}

public Quaternion GetExitRotation()
{
if (exitPoint != null)
return exitPoint.rotation;

return transform.rotation;
}
}
}
2 changes: 2 additions & 0 deletions Assets/Scripts/Interactions/HidingSpotInteractable.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions Assets/Scripts/Interactions/IInteractable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using UnityEngine;

namespace Game.Interaction
{
public interface IInteractable
{
string GetPrompt();
bool CanInteract(GameObject interactor);
void Interact(GameObject interactor);
}
}
2 changes: 2 additions & 0 deletions Assets/Scripts/Interactions/IInteractable.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions Assets/Scripts/Interactions/InventoryDebugUI.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.Text;
using UnityEngine;
using UnityEngine.UI;

namespace Game.Interaction
{
/// Простой debug UI для отображения содержимого инвентаря на экране.
public class InventoryDebugUI : MonoBehaviour
{
[SerializeField] private SimpleInventory inventory;
[SerializeField] private Text inventoryText;

private readonly StringBuilder _builder = new();

private void Reset()
{
if (!inventory)
inventory = FindFirstObjectByType<SimpleInventory>();
}

private void Update()
{
if (inventoryText == null) return;

if (inventory == null)
{
inventoryText.text = "Inventory:\n<missing inventory>";
return;
}

var items = inventory.GetItems();

_builder.Clear();
_builder.AppendLine("Inventory:");

if (items.Count == 0)
{
_builder.AppendLine("- empty");
}
else
{
foreach (var item in items)
{
_builder.Append("- ");
_builder.AppendLine(item);
}
}

inventoryText.text = _builder.ToString();
}
}
}
2 changes: 2 additions & 0 deletions Assets/Scripts/Interactions/InventoryDebugUI.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading