first commit

This commit is contained in:
2026-06-04 19:34:38 +03:00
commit 6318b20158
110 changed files with 9536 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
using UnityEngine;
public class BillboardNameplate : MonoBehaviour
{
public Camera targetCamera;
private void LateUpdate()
{
Camera cam = targetCamera != null ? targetCamera : Camera.main;
if (cam == null)
return;
transform.rotation = Quaternion.LookRotation(transform.position - cam.transform.position);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a56680789bcc19bc2af5ed5e1245b7e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+111
View File
@@ -0,0 +1,111 @@
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class DialogueHUD : MonoBehaviour
{
public static DialogueHUD Instance { get; private set; }
[Header("UI")]
public Text hintText;
public Text statusText;
public Text inventoryText;
[Header("Data")]
public Inventory inventory;
public float messageDuration = 2.5f;
private Coroutine messageRoutine;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
private void OnEnable()
{
if (inventory != null)
inventory.OnInventoryChanged += UpdateInventoryText;
HideHint();
UpdateInventoryText();
}
private void OnDisable()
{
if (inventory != null)
inventory.OnInventoryChanged -= UpdateInventoryText;
}
public void ShowHint(string message)
{
if (hintText == null)
return;
hintText.text = message;
SetTextRootActive(hintText, !string.IsNullOrEmpty(message));
}
public void HideHint()
{
if (hintText == null)
return;
hintText.text = string.Empty;
SetTextRootActive(hintText, false);
}
public void SetStatus(string message)
{
if (statusText == null)
return;
statusText.text = message;
SetTextRootActive(statusText, !string.IsNullOrEmpty(message));
if (messageRoutine != null)
StopCoroutine(messageRoutine);
if (!string.IsNullOrEmpty(message) && gameObject.activeInHierarchy)
messageRoutine = StartCoroutine(ClearStatusAfterDelay());
}
public void UpdateInventoryText()
{
if (inventoryText == null)
return;
inventoryText.text = inventory != null ? inventory.GetDebugText() : "Инвентарь: недоступен";
}
private IEnumerator ClearStatusAfterDelay()
{
yield return new WaitForSeconds(messageDuration);
if (statusText != null)
{
statusText.text = string.Empty;
SetTextRootActive(statusText, false);
}
messageRoutine = null;
}
private static void SetTextRootActive(Text text, bool active)
{
if (text == null)
return;
Transform parent = text.transform.parent;
if (parent != null && parent.GetComponent<Image>() != null)
parent.gameObject.SetActive(active);
else
text.gameObject.SetActive(active);
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 209c58a4fe0343f04ad50081998de8c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+404
View File
@@ -0,0 +1,404 @@
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class DialogueManager : MonoBehaviour
{
public static DialogueManager Instance { get; private set; }
[Header("UI")]
public GameObject dialoguePanel;
public Text speakerText;
public Text npcText;
public Transform responseContainer;
public ScrollRect responseScrollRect;
public GameObject responseButtonPrefab;
public Text hintText;
public Text statusText;
[Header("Scene References")]
public Inventory playerInventory;
public SimplePlayerController playerController;
[Header("Typewriter")]
public float characterDelay = 0.025f;
public bool IsDialogueActive { get; private set; }
private DialogueNode currentNode;
private string currentNpcLine;
private Coroutine typewriterRoutine;
private bool isTyping;
private string overrideSpeakerName;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
if (dialoguePanel != null)
dialoguePanel.SetActive(false);
}
private void Update()
{
if (!IsDialogueActive)
return;
if (isTyping && (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)))
SkipTypewriter();
if (Input.GetKeyDown(KeyCode.Escape))
EndDialogue();
}
public void StartDialogue(DialogueNode startNode, string npcDisplayName = null)
{
if (IsDialogueActive || startNode == null)
return;
IsDialogueActive = true;
overrideSpeakerName = npcDisplayName;
if (dialoguePanel != null)
dialoguePanel.SetActive(true);
SetHint(string.Empty);
SetStatus(string.Empty);
if (playerController != null)
playerController.SetInputEnabled(false);
else
{
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
ShowNode(startNode);
}
public void ShowNode(DialogueNode node)
{
if (node == null)
{
EndDialogue();
return;
}
currentNode = node;
currentNpcLine = string.IsNullOrEmpty(node.npcLine) ? string.Empty : node.npcLine;
if (speakerText != null)
{
string speaker = !string.IsNullOrEmpty(node.speakerName) ? node.speakerName : overrideSpeakerName;
speakerText.text = string.IsNullOrEmpty(speaker) ? "NPC" : speaker;
}
ClearResponses();
if (typewriterRoutine != null)
StopCoroutine(typewriterRoutine);
typewriterRoutine = StartCoroutine(TypeLine(currentNpcLine));
}
public void EndDialogue()
{
if (!IsDialogueActive)
return;
if (typewriterRoutine != null)
{
StopCoroutine(typewriterRoutine);
typewriterRoutine = null;
}
isTyping = false;
currentNode = null;
ClearResponses();
if (dialoguePanel != null)
dialoguePanel.SetActive(false);
if (playerController != null)
playerController.SetInputEnabled(true);
else
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
IsDialogueActive = false;
SetStatus("Диалог завершён");
}
public void OnResponseSelected(DialogueResponse response)
{
if (response == null)
{
EndDialogue();
return;
}
if (isTyping)
{
SkipTypewriter();
return;
}
if (!CheckRequirements(response))
{
string requiredName = response.requiredItem != null ? response.requiredItem.itemName : "предмет";
SetStatus(!string.IsNullOrEmpty(response.unavailableText) ? response.unavailableText : "Нужен предмет: " + requiredName);
return;
}
ApplyResponseEffects(response);
if (response.endsDialogue || response.nextNode == null)
EndDialogue();
else
ShowNode(response.nextNode);
}
public void CreateResponseButton(DialogueResponse response, bool interactable, string buttonText)
{
if (responseContainer == null)
return;
GameObject buttonObject = responseButtonPrefab != null
? Instantiate(responseButtonPrefab, responseContainer)
: CreateFallbackButton(responseContainer);
buttonObject.name = interactable ? "ResponseButton" : "ResponseButton_Disabled";
buttonObject.SetActive(true);
Text label = buttonObject.GetComponentInChildren<Text>(true);
if (label != null)
{
label.text = buttonText;
label.color = interactable ? Color.white : new Color(0.68f, 0.7f, 0.73f, 1f);
}
Button button = buttonObject.GetComponent<Button>();
if (button == null)
button = buttonObject.AddComponent<Button>();
button.interactable = interactable;
button.onClick.RemoveAllListeners();
if (interactable)
button.onClick.AddListener(() => OnResponseSelected(response));
Image image = buttonObject.GetComponent<Image>();
if (image != null && !interactable)
image.color = new Color(0.12f, 0.13f, 0.15f, 0.88f);
if (responseScrollRect != null)
responseScrollRect.verticalNormalizedPosition = 1f;
}
public bool CheckRequirements(DialogueResponse response)
{
if (response == null || response.requiredItem == null)
return true;
if (playerInventory == null)
return false;
return playerInventory.HasItem(response.requiredItem, Mathf.Max(1, response.requiredItemAmount));
}
public void ApplyResponseEffects(DialogueResponse response)
{
if (response == null || playerInventory == null)
return;
if (response.consumeRequiredItem && response.requiredItem != null)
{
int amount = Mathf.Max(1, response.requiredItemAmount);
if (playerInventory.RemoveItem(response.requiredItem, amount))
SetStatus("Списан предмет: " + response.requiredItem.itemName);
}
if (response.rewardItem != null && response.rewardAmount > 0)
{
if (playerInventory.AddItem(response.rewardItem, response.rewardAmount))
SetStatus("Получен предмет: " + response.rewardItem.itemName);
}
if (!string.IsNullOrEmpty(response.eventId))
Debug.Log("Dialogue event fired: " + response.eventId);
}
public void SkipTypewriter()
{
if (!isTyping)
return;
if (typewriterRoutine != null)
{
StopCoroutine(typewriterRoutine);
typewriterRoutine = null;
}
if (npcText != null)
npcText.text = currentNpcLine;
isTyping = false;
BuildResponseButtons();
}
public void ClearResponses()
{
if (responseContainer == null)
return;
for (int i = responseContainer.childCount - 1; i >= 0; i--)
Destroy(responseContainer.GetChild(i).gameObject);
}
public void SetStatus(string message)
{
if (statusText != null)
{
statusText.text = message;
SetTextRootActive(statusText, !string.IsNullOrEmpty(message));
}
if (DialogueHUD.Instance != null && !string.IsNullOrEmpty(message))
DialogueHUD.Instance.SetStatus(message);
}
private IEnumerator TypeLine(string line)
{
isTyping = true;
if (npcText != null)
npcText.text = string.Empty;
for (int i = 0; i < line.Length; i++)
{
if (npcText != null)
npcText.text = line.Substring(0, i + 1);
yield return new WaitForSeconds(characterDelay);
}
isTyping = false;
typewriterRoutine = null;
BuildResponseButtons();
}
private void BuildResponseButtons()
{
ClearResponses();
if (currentNode == null)
return;
int visibleCount = 0;
int interactableCount = 0;
DialogueResponse[] responses = currentNode.responses;
if (responses != null)
{
foreach (DialogueResponse response in responses)
{
if (response == null)
continue;
bool requirementsMet = CheckRequirements(response);
if (!requirementsMet && response.hideIfRequirementsNotMet)
continue;
string text = response.responseText;
if (!requirementsMet)
text = !string.IsNullOrEmpty(response.unavailableText) ? response.unavailableText : BuildUnavailableText(response);
CreateResponseButton(response, requirementsMet, text);
visibleCount++;
if (requirementsMet)
interactableCount++;
}
}
if (visibleCount == 0 || interactableCount == 0 || currentNode.isEndNode)
{
DialogueResponse closeResponse = new DialogueResponse
{
responseText = "До свидания.",
endsDialogue = true
};
CreateResponseButton(closeResponse, true, "До свидания");
}
}
private string BuildUnavailableText(DialogueResponse response)
{
if (response.requiredItem == null)
return "Недоступно";
int amount = Mathf.Max(1, response.requiredItemAmount);
return amount > 1
? "Недоступно: нужен предмет " + response.requiredItem.itemName + " x" + amount
: "Недоступно: нужен предмет " + response.requiredItem.itemName;
}
private void SetHint(string message)
{
if (hintText != null)
{
hintText.text = message;
SetTextRootActive(hintText, !string.IsNullOrEmpty(message));
}
if (DialogueHUD.Instance != null)
{
if (string.IsNullOrEmpty(message))
DialogueHUD.Instance.HideHint();
else
DialogueHUD.Instance.ShowHint(message);
}
}
private GameObject CreateFallbackButton(Transform parent)
{
GameObject buttonObject = new GameObject("ResponseButton", typeof(RectTransform), typeof(Image), typeof(Button));
buttonObject.transform.SetParent(parent, false);
GameObject labelObject = new GameObject("Text", typeof(RectTransform), typeof(Text));
labelObject.transform.SetParent(buttonObject.transform, false);
RectTransform labelRect = labelObject.GetComponent<RectTransform>();
labelRect.anchorMin = Vector2.zero;
labelRect.anchorMax = Vector2.one;
labelRect.offsetMin = new Vector2(16f, 6f);
labelRect.offsetMax = new Vector2(-16f, -6f);
Text label = labelObject.GetComponent<Text>();
label.color = Color.white;
label.alignment = TextAnchor.MiddleLeft;
label.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
return buttonObject;
}
private static void SetTextRootActive(Text text, bool active)
{
if (text == null)
return;
Transform parent = text.transform.parent;
if (parent != null && parent.GetComponent<Image>() != null)
parent.gameObject.SetActive(active);
else
text.gameObject.SetActive(active);
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3d5c728207b3a368ea9bfcc9e30ffb6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+33
View File
@@ -0,0 +1,33 @@
using System;
using UnityEngine;
[CreateAssetMenu(fileName = "DialogueNode", menuName = "Dialogue/DialogueNode")]
public class DialogueNode : ScriptableObject
{
public string nodeId;
public string speakerName;
[TextArea(3, 8)]
public string npcLine;
public DialogueResponse[] responses;
public bool isEndNode;
public string editorNote;
}
[Serializable]
public class DialogueResponse
{
public string responseText;
public DialogueNode nextNode;
public bool endsDialogue;
public ItemData requiredItem;
public int requiredItemAmount = 1;
public string unavailableText;
public bool hideIfRequirementsNotMet;
public bool consumeRequiredItem;
public ItemData rewardItem;
public int rewardAmount;
public string eventId;
public string editorNote;
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 760b0a0b8bcf617edbf21f60d51169f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+119
View File
@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
[Serializable]
public class InventorySlot
{
public ItemData item;
public int amount;
public InventorySlot(ItemData item, int amount)
{
this.item = item;
this.amount = Mathf.Max(0, amount);
}
}
public class Inventory : MonoBehaviour
{
[SerializeField] private List<InventorySlot> slots = new List<InventorySlot>();
public event Action OnInventoryChanged;
public IReadOnlyList<InventorySlot> Slots => slots;
public bool HasItem(ItemData item, int amount)
{
if (item == null)
return true;
return GetAmount(item) >= Mathf.Max(1, amount);
}
public int GetAmount(ItemData item)
{
if (item == null)
return 0;
InventorySlot slot = FindSlot(item);
return slot != null ? Mathf.Max(0, slot.amount) : 0;
}
public bool AddItem(ItemData item, int amount)
{
if (item == null || amount <= 0)
return false;
InventorySlot slot = FindSlot(item);
int maxStack = Mathf.Max(1, item.maxStack);
if (slot == null)
{
slots.Add(new InventorySlot(item, Mathf.Min(amount, maxStack)));
RaiseChanged();
return true;
}
int newAmount = Mathf.Clamp(slot.amount + amount, 0, maxStack);
if (newAmount == slot.amount)
return false;
slot.amount = newAmount;
RaiseChanged();
return true;
}
public bool RemoveItem(ItemData item, int amount)
{
if (item == null || amount <= 0)
return false;
InventorySlot slot = FindSlot(item);
if (slot == null || slot.amount < amount)
return false;
slot.amount -= amount;
if (slot.amount <= 0)
slots.Remove(slot);
RaiseChanged();
return true;
}
public string GetDebugText()
{
if (slots.Count == 0)
return "Инвентарь: пусто";
StringBuilder builder = new StringBuilder("Инвентарь: ");
bool first = true;
foreach (InventorySlot slot in slots)
{
if (slot == null || slot.item == null || slot.amount <= 0)
continue;
if (!first)
builder.Append(", ");
builder.Append(slot.item.itemName);
builder.Append(" x");
builder.Append(slot.amount);
first = false;
}
return first ? "Инвентарь: пусто" : builder.ToString();
}
private InventorySlot FindSlot(ItemData item)
{
return slots.Find(slot => slot != null && slot.item == item);
}
private void RaiseChanged()
{
OnInventoryChanged?.Invoke();
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 041b00ae48363aabaaf30a53abcd35ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+14
View File
@@ -0,0 +1,14 @@
using UnityEngine;
[CreateAssetMenu(fileName = "ItemData", menuName = "Dialogue/ItemData")]
public class ItemData : ScriptableObject
{
public string itemId;
public string itemName;
[TextArea(2, 5)]
public string description;
public Color itemColor = Color.white;
public int maxStack = 99;
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10cf6353066082490a62140ae9883b4e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+114
View File
@@ -0,0 +1,114 @@
using UnityEngine;
[RequireComponent(typeof(SphereCollider))]
public class NPCInteract : MonoBehaviour
{
public DialogueNode startNode;
public string npcDisplayName = "Смотритель ворот";
public float interactionRadius = 3f;
public KeyCode interactKey = KeyCode.E;
public DialogueManager dialogueManager;
public Renderer highlightRenderer;
public Color highlightColor = new Color(1f, 0.78f, 0.22f, 1f);
private Transform player;
private bool playerInRange;
private Color baseColor;
private Material runtimeMaterial;
private void Awake()
{
SphereCollider trigger = GetComponent<SphereCollider>();
trigger.isTrigger = true;
trigger.radius = interactionRadius;
if (highlightRenderer == null)
highlightRenderer = GetComponentInChildren<Renderer>();
if (highlightRenderer != null)
{
runtimeMaterial = highlightRenderer.material;
baseColor = runtimeMaterial.color;
}
}
private void Start()
{
if (dialogueManager == null)
dialogueManager = DialogueManager.Instance;
SimplePlayerController controller = FindObjectOfType<SimplePlayerController>();
if (controller != null)
player = controller.transform;
}
private void Update()
{
if (player != null)
SetPlayerInRange(Vector3.Distance(transform.position, player.position) <= interactionRadius);
bool dialogueActive = dialogueManager != null && dialogueManager.IsDialogueActive;
if (!playerInRange || dialogueActive)
return;
ShowHint();
if (Input.GetKeyDown(interactKey) && startNode != null && dialogueManager != null)
dialogueManager.StartDialogue(startNode, npcDisplayName);
}
private void OnTriggerEnter(Collider other)
{
if (other.GetComponentInParent<SimplePlayerController>() != null)
{
player = other.transform;
SetPlayerInRange(true);
}
}
private void OnTriggerExit(Collider other)
{
if (other.GetComponentInParent<SimplePlayerController>() != null)
SetPlayerInRange(false);
}
private void OnDrawGizmosSelected()
{
Gizmos.color = new Color(1f, 0.75f, 0.2f, 0.25f);
Gizmos.DrawSphere(transform.position, interactionRadius);
Gizmos.color = new Color(1f, 0.75f, 0.2f, 1f);
Gizmos.DrawWireSphere(transform.position, interactionRadius);
}
private void SetPlayerInRange(bool inRange)
{
if (playerInRange == inRange)
return;
playerInRange = inRange;
SetHighlight(inRange);
if (!inRange && DialogueHUD.Instance != null)
DialogueHUD.Instance.HideHint();
}
private void SetHighlight(bool enabled)
{
if (runtimeMaterial == null)
return;
runtimeMaterial.color = enabled ? highlightColor : baseColor;
}
private void ShowHint()
{
if (DialogueHUD.Instance != null)
DialogueHUD.Instance.ShowHint("Нажмите E для разговора");
else if (dialogueManager != null && dialogueManager.hintText != null)
{
dialogueManager.hintText.text = "Нажмите E для разговора";
dialogueManager.hintText.gameObject.SetActive(true);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df6b7e66747a822b487e1fb1c9b6e736
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+96
View File
@@ -0,0 +1,96 @@
using UnityEngine;
[RequireComponent(typeof(SphereCollider))]
public class PickupItem : MonoBehaviour
{
public ItemData item;
public int amount = 1;
public KeyCode interactKey = KeyCode.E;
public float interactionRadius = 2.25f;
public Inventory targetInventory;
private Transform player;
private bool playerInRange;
private void Awake()
{
SphereCollider trigger = GetComponent<SphereCollider>();
trigger.isTrigger = true;
trigger.radius = interactionRadius;
}
private void Start()
{
if (targetInventory == null)
targetInventory = FindObjectOfType<Inventory>();
SimplePlayerController controller = FindObjectOfType<SimplePlayerController>();
if (controller != null)
player = controller.transform;
}
private void Update()
{
if (player != null)
SetPlayerInRange(Vector3.Distance(transform.position, player.position) <= interactionRadius);
if (!playerInRange || item == null || targetInventory == null)
return;
if (DialogueManager.Instance != null && DialogueManager.Instance.IsDialogueActive)
return;
ShowHint();
if (Input.GetKeyDown(interactKey) && targetInventory.AddItem(item, amount))
{
if (DialogueHUD.Instance != null)
{
DialogueHUD.Instance.SetStatus("Получен предмет: " + item.itemName);
DialogueHUD.Instance.HideHint();
}
gameObject.SetActive(false);
}
}
private void OnTriggerEnter(Collider other)
{
if (other.GetComponentInParent<SimplePlayerController>() != null)
{
player = other.transform;
SetPlayerInRange(true);
}
}
private void OnTriggerExit(Collider other)
{
if (other.GetComponentInParent<SimplePlayerController>() != null)
SetPlayerInRange(false);
}
private void OnDrawGizmosSelected()
{
Gizmos.color = new Color(0.2f, 0.8f, 1f, 0.25f);
Gizmos.DrawSphere(transform.position, interactionRadius);
Gizmos.color = new Color(0.2f, 0.8f, 1f, 1f);
Gizmos.DrawWireSphere(transform.position, interactionRadius);
}
private void SetPlayerInRange(bool inRange)
{
if (playerInRange == inRange)
return;
playerInRange = inRange;
if (!inRange && DialogueHUD.Instance != null)
DialogueHUD.Instance.HideHint();
}
private void ShowHint()
{
if (DialogueHUD.Instance != null)
DialogueHUD.Instance.ShowHint("Нажмите E, чтобы подобрать: " + item.itemName);
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 05965783683e09fc7b4fdcb59d65f7bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+88
View File
@@ -0,0 +1,88 @@
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class SimplePlayerController : MonoBehaviour
{
[Header("Movement")]
public float moveSpeed = 4.5f;
public float jumpForce = 1.2f;
public float gravity = -18f;
[Header("Look")]
public Camera playerCamera;
public float mouseSensitivity = 2.2f;
public float minPitch = -75f;
public float maxPitch = 75f;
private CharacterController characterController;
private Vector3 verticalVelocity;
private float pitch;
private bool inputEnabled = true;
private void Awake()
{
characterController = GetComponent<CharacterController>();
if (playerCamera == null)
playerCamera = GetComponentInChildren<Camera>();
}
private void Start()
{
SetInputEnabled(true);
}
private void Update()
{
if (!inputEnabled)
return;
Look();
Move();
}
public void SetInputEnabled(bool enabled)
{
inputEnabled = enabled;
if (!enabled)
verticalVelocity = Vector3.zero;
Cursor.visible = !enabled;
Cursor.lockState = enabled ? CursorLockMode.Locked : CursorLockMode.None;
}
private void Look()
{
float yaw = Input.GetAxis("Mouse X") * mouseSensitivity;
float pitchDelta = Input.GetAxis("Mouse Y") * mouseSensitivity;
transform.Rotate(Vector3.up * yaw);
pitch = Mathf.Clamp(pitch - pitchDelta, minPitch, maxPitch);
if (playerCamera != null)
playerCamera.transform.localEulerAngles = new Vector3(pitch, 0f, 0f);
}
private void Move()
{
bool grounded = characterController.isGrounded;
if (grounded && verticalVelocity.y < 0f)
verticalVelocity.y = -2f;
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector3 move = transform.right * horizontal + transform.forward * vertical;
if (move.sqrMagnitude > 1f)
move.Normalize();
characterController.Move(move * (moveSpeed * Time.deltaTime));
if (grounded && Input.GetKeyDown(KeyCode.Space))
verticalVelocity.y = Mathf.Sqrt(jumpForce * -2f * gravity);
verticalVelocity.y += gravity * Time.deltaTime;
characterController.Move(verticalVelocity * Time.deltaTime);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f0993d8504dc71019bbeb442778b3b51
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: