Project_WL/Assets/FarmingIsland/Scripts/Animals/Wool.cs

188 lines
7.1 KiB
C#

using System.Collections;
using System.Linq;
using UnityEngine;
namespace CryingSnow.FarmingIsland
{
[RequireComponent(typeof(SkinnedMeshRenderer))]
[RequireComponent(typeof(MeshCollider))]
public class Wool : MonoBehaviour
{
[SerializeField, Range(0.1f, 0.5f)]
[Tooltip("Radius around the shear point where vertices will be affected.")]
private float shearRadius = 0.1f;
[SerializeField, Range(0.1f, 1f)]
[Tooltip("Minimum percentage of wool that must be sheared before the process is complete.")]
private float minShearAmount = 0.9f;
[SerializeField]
[Tooltip("Sound clip played when the wool is being sheared.")]
private AudioClip razorSound;
private SkinnedMeshRenderer skinnedMeshRenderer;
private MeshCollider woolCollider;
private ParticleSystem woolParticle;
private Camera mainCamera;
private int woolLayer;
void Awake()
{
// Get references to required components
skinnedMeshRenderer = GetComponent<SkinnedMeshRenderer>();
woolCollider = GetComponent<MeshCollider>();
// Attempt to get the particle system component from the children
woolParticle = GetComponentInChildren<ParticleSystem>();
if (!woolParticle)
Debug.LogWarning("Wool particle not found!");
// Disable the collider initially
woolCollider.enabled = false;
}
void Start()
{
// Cache the main camera and set the layer for the wool
mainCamera = Camera.main;
gameObject.layer = LayerMask.NameToLayer("Wool");
woolLayer = 1 << gameObject.layer;
}
public IEnumerator Shear()
{
// Create a shearable version of the wool
GameObject shearableWool = CreateShearableWool(out Mesh woolMesh);
Vector3[] movedVertices = woolMesh.vertices;
// Set the blend shape weight to maximum for shearing effect
skinnedMeshRenderer.SetBlendShapeWeight(0, 100f);
// Prepare a mesh to capture the state of wool after shearing
Mesh sheared = new Mesh();
skinnedMeshRenderer.BakeMesh(sheared);
Vector3[] targetVertices = sheared.vertices;
bool[] vertexMoved = new bool[movedVertices.Length];
// Temporarily disable the skinned mesh renderer and enable the collider
skinnedMeshRenderer.enabled = false;
woolCollider.enabled = true;
// Create an audio source to play the shearing sound
var audioSourceObj = new GameObject("Razor Audio Source");
var audioSource = audioSourceObj.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
audioSource.clip = razorSound;
// Hide the HUD and show the progress bar
UIManager.Instance.ToggleHUD(false);
UIManager.Instance.ProgressBar.Toggle("Shear the wool!");
float shearProgress = 0f;
while (shearProgress < minShearAmount)
{
// Calculate the shear progress based on moved vertices
shearProgress = vertexMoved.Count(moved => moved) / (float)vertexMoved.Length;
// Get the mouse position and cast a ray to check for intersections with the wool
Vector3 mousePos = Input.mousePosition;
Ray ray = mainCamera.ScreenPointToRay(mousePos);
if (Input.GetMouseButton(0) && Physics.Raycast(ray, out RaycastHit hit, 100f, woolLayer))
{
Vector3 hitPoint = hit.point;
// Play and position the particle system
if (!woolParticle.isPlaying) woolParticle.Play();
woolParticle.transform.position = hitPoint;
woolParticle.transform.forward = hit.normal;
// Play the shearing sound
if (!audioSource.isPlaying)
{
audioSource.loop = true;
audioSource.Play();
}
// Define a bounding box for shearing
Bounds shearBounds = new Bounds(hitPoint, Vector3.one * shearRadius * 2);
for (int i = 0; i < movedVertices.Length; i++)
{
if (!vertexMoved[i])
{
Vector3 worldVertex = transform.TransformPoint(movedVertices[i]);
if (shearBounds.Contains(worldVertex))
{
movedVertices[i] = targetVertices[i];
vertexMoved[i] = true;
}
}
}
// Update the mesh and recalculate normals
woolMesh.vertices = movedVertices;
woolMesh.RecalculateNormals();
}
else
{
// Stop particle system and audio if not shearing
if (woolParticle.isPlaying) woolParticle.Stop();
audioSource.loop = false;
}
// Update progress bar
float progress = shearProgress;
if (progress > 0f) progress += 1 - minShearAmount;
UIManager.Instance.ProgressBar.UpdateDisplay(progress);
yield return null;
}
// Short delay after finishing the shearing (wait for Pose animation transition)
yield return new WaitForSeconds(0.3f);
// Restore HUD and clean up
UIManager.Instance.ProgressBar.Toggle("");
UIManager.Instance.ToggleHUD(true);
woolCollider.enabled = false;
audioSource.loop = false;
Destroy(audioSourceObj, 1f);
woolParticle.Stop();
Destroy(shearableWool);
}
private GameObject CreateShearableWool(out Mesh woolMesh)
{
// Create a new GameObject for the shearable wool
var woolObj = new GameObject("Shearable Wool");
woolObj.transform.SetParent(transform.parent);
woolObj.transform.localPosition = Vector3.zero;
woolObj.transform.localRotation = transform.localRotation;
// Create a mesh for the shearable wool and assign it to the new GameObject
Mesh mesh = new Mesh();
skinnedMeshRenderer.BakeMesh(mesh);
var filter = woolObj.AddComponent<MeshFilter>();
filter.mesh = mesh;
var meshRenderer = woolObj.AddComponent<MeshRenderer>();
meshRenderer.material = skinnedMeshRenderer.material;
woolMesh = mesh;
return woolObj;
}
public void GrowWool()
{
// Reset the blend shape weight and enable the skinned mesh renderer
skinnedMeshRenderer.SetBlendShapeWeight(0, 0f);
skinnedMeshRenderer.enabled = true;
}
}
}