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(); woolCollider = GetComponent(); // Attempt to get the particle system component from the children woolParticle = GetComponentInChildren(); 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.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(); filter.mesh = mesh; var meshRenderer = woolObj.AddComponent(); 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; } } }