first commit
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTG.Lab06.Characters
|
||||
{
|
||||
public sealed class ManaCrystal : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float restoreAmount = 35f;
|
||||
[SerializeField] private float respawnTime = 7f;
|
||||
[SerializeField] private GameObject visualRoot;
|
||||
|
||||
private Collider triggerCollider;
|
||||
private float cooldown;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
triggerCollider = GetComponent<Collider>();
|
||||
if (visualRoot == null && transform.childCount > 0)
|
||||
{
|
||||
visualRoot = transform.GetChild(0).gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
transform.Rotate(Vector3.up, 45f * Time.deltaTime, Space.World);
|
||||
|
||||
if (cooldown <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cooldown -= Time.deltaTime;
|
||||
if (cooldown <= 0f)
|
||||
{
|
||||
SetAvailable(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
PlayerStats stats = other.GetComponentInParent<PlayerStats>();
|
||||
if (stats == null || cooldown > 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
stats.RestoreMana(restoreAmount);
|
||||
cooldown = respawnTime;
|
||||
SetAvailable(false);
|
||||
}
|
||||
|
||||
private void SetAvailable(bool available)
|
||||
{
|
||||
if (triggerCollider != null)
|
||||
{
|
||||
triggerCollider.enabled = available;
|
||||
}
|
||||
|
||||
if (visualRoot != null)
|
||||
{
|
||||
visualRoot.SetActive(available);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf05fce7fd259f2ef9cfdd279ef00cc0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTG.Lab06.Characters
|
||||
{
|
||||
[RequireComponent(typeof(CharacterController))]
|
||||
public sealed class PlayerController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float moveSpeed = 6f;
|
||||
[SerializeField] private float rotationSpeed = 12f;
|
||||
[SerializeField] private float gravity = -24f;
|
||||
[SerializeField] private Transform cameraTransform;
|
||||
|
||||
private CharacterController characterController;
|
||||
private float verticalVelocity;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
characterController = GetComponent<CharacterController>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (cameraTransform == null && Camera.main != null)
|
||||
{
|
||||
cameraTransform = Camera.main.transform;
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
|
||||
input = Vector2.ClampMagnitude(input, 1f);
|
||||
|
||||
Vector3 forward = cameraTransform == null ? Vector3.forward : cameraTransform.forward;
|
||||
Vector3 right = cameraTransform == null ? Vector3.right : cameraTransform.right;
|
||||
forward.y = 0f;
|
||||
right.y = 0f;
|
||||
forward.Normalize();
|
||||
right.Normalize();
|
||||
|
||||
Vector3 move = forward * input.y + right * input.x;
|
||||
if (move.sqrMagnitude > 0.01f)
|
||||
{
|
||||
Quaternion targetRotation = Quaternion.LookRotation(move, Vector3.up);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
|
||||
}
|
||||
|
||||
if (characterController.isGrounded && verticalVelocity < 0f)
|
||||
{
|
||||
verticalVelocity = -2f;
|
||||
}
|
||||
|
||||
verticalVelocity += gravity * Time.deltaTime;
|
||||
Vector3 velocity = move * moveSpeed + Vector3.up * verticalVelocity;
|
||||
characterController.Move(velocity * Time.deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d36fc8809523bc02b9b0f6db8d4ecd1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using OTG.Lab06.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTG.Lab06.Characters
|
||||
{
|
||||
public sealed class PlayerStats : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float health = 100f;
|
||||
[SerializeField] private float mana = 100f;
|
||||
|
||||
private ResourceStat healthStat;
|
||||
private ResourceStat manaStat;
|
||||
|
||||
public event Action<float, float> HealthChanged;
|
||||
public event Action<float, float> ManaChanged;
|
||||
|
||||
public float Health { get { EnsureInitialized(); return healthStat.Current; } }
|
||||
public float MaxHealth { get { EnsureInitialized(); return healthStat.Max; } }
|
||||
public float Mana { get { EnsureInitialized(); return manaStat.Current; } }
|
||||
public float MaxMana { get { EnsureInitialized(); return manaStat.Max; } }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
EnsureInitialized();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
HealthChanged?.Invoke(Health, MaxHealth);
|
||||
ManaChanged?.Invoke(Mana, MaxMana);
|
||||
}
|
||||
|
||||
public void TakeDamage(float amount)
|
||||
{
|
||||
EnsureInitialized();
|
||||
healthStat.Subtract(amount);
|
||||
}
|
||||
|
||||
public void Heal(float amount)
|
||||
{
|
||||
EnsureInitialized();
|
||||
healthStat.Add(amount);
|
||||
}
|
||||
|
||||
public bool SpendMana(float amount)
|
||||
{
|
||||
EnsureInitialized();
|
||||
return manaStat.TrySpend(amount);
|
||||
}
|
||||
|
||||
public void RestoreMana(float amount)
|
||||
{
|
||||
EnsureInitialized();
|
||||
manaStat.Add(amount);
|
||||
}
|
||||
|
||||
private void EnsureInitialized()
|
||||
{
|
||||
if (healthStat != null && manaStat != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
healthStat = new ResourceStat(health);
|
||||
manaStat = new ResourceStat(mana);
|
||||
healthStat.Changed += (current, max) => HealthChanged?.Invoke(current, max);
|
||||
manaStat.Changed += (current, max) => ManaChanged?.Invoke(current, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c1de8ed2b96ea7af8f9a5268fd46f43
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,71 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace OTG.Lab06.Characters
|
||||
{
|
||||
public sealed class ThirdPersonCamera : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Transform target;
|
||||
[SerializeField] private float mouseSensitivity = 2.5f;
|
||||
[SerializeField] private float smoothTime = 0.12f;
|
||||
[SerializeField] private float minPitch = 45f;
|
||||
[SerializeField] private float maxPitch = 60f;
|
||||
[SerializeField] private float initialPitch = 52f;
|
||||
[SerializeField] private float distance = 14f;
|
||||
[SerializeField] private float lookAhead = 3.5f;
|
||||
[SerializeField] private float targetHeight = 1.25f;
|
||||
|
||||
private Vector3 velocity;
|
||||
private float yaw;
|
||||
private float pitch;
|
||||
|
||||
public void SetTarget(Transform newTarget)
|
||||
{
|
||||
target = newTarget;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
yaw = transform.eulerAngles.y;
|
||||
pitch = Mathf.Clamp(initialPitch, minPitch, maxPitch);
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
Cursor.visible = true;
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Input.GetMouseButtonDown(1))
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
Cursor.visible = false;
|
||||
}
|
||||
else if (Input.GetMouseButtonUp(1))
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.None;
|
||||
Cursor.visible = true;
|
||||
}
|
||||
|
||||
if (Input.GetMouseButton(1))
|
||||
{
|
||||
yaw += Input.GetAxis("Mouse X") * mouseSensitivity;
|
||||
pitch -= Input.GetAxis("Mouse Y") * mouseSensitivity;
|
||||
pitch = Mathf.Clamp(pitch, minPitch, maxPitch);
|
||||
}
|
||||
|
||||
Vector3 forward = Quaternion.Euler(0f, yaw, 0f) * Vector3.forward;
|
||||
float pitchRadians = pitch * Mathf.Deg2Rad;
|
||||
float horizontalDistance = Mathf.Cos(pitchRadians) * distance;
|
||||
float height = Mathf.Sin(pitchRadians) * distance;
|
||||
|
||||
Vector3 desiredPosition = target.position - forward * horizontalDistance + Vector3.up * height;
|
||||
Vector3 lookTarget = target.position + forward * lookAhead + Vector3.up * targetHeight;
|
||||
|
||||
transform.position = Vector3.SmoothDamp(transform.position, desiredPosition, ref velocity, smoothTime);
|
||||
transform.rotation = Quaternion.LookRotation(lookTarget - transform.position, Vector3.up);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77a9e5c97b39968429ddf7ef8a6d0687
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user